diff options
author | Alexis Menard <alexis.menard@nokia.com> | 2009-05-29 08:08:04 (GMT) |
---|---|---|
committer | Alexis Menard <alexis.menard@nokia.com> | 2009-05-29 08:08:04 (GMT) |
commit | 23a92388505c54155855d2f49d3a9cf81de0e5ea (patch) | |
tree | e27be8f97b6781540579d5a507914cf03272ba3d /src | |
parent | 560ca373e4879f335a0ceeb3f8a769cc0e4297fe (diff) | |
parent | 8acc20e525d589e0c4450fbd60141e8b9c3f40e9 (diff) | |
download | Qt-23a92388505c54155855d2f49d3a9cf81de0e5ea.zip Qt-23a92388505c54155855d2f49d3a9cf81de0e5ea.tar.gz Qt-23a92388505c54155855d2f49d3a9cf81de0e5ea.tar.bz2 |
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt into qt-main/qgraphicssceneindex
Diffstat (limited to 'src')
652 files changed, 33641 insertions, 11009 deletions
diff --git a/src/3rdparty/README b/src/3rdparty/README index 2be1036..ef05674 100644 --- a/src/3rdparty/README +++ b/src/3rdparty/README @@ -20,3 +20,8 @@ have been removed: Some patches are applied from time to time. Recent patches can be found in the patches subdirectory. + + +The pvr2d.h & wsegl.h in the powervr directory are required for building +the PowerVR plugin on Qt for Embedded Linux. These headers are for SGX +based SoCs, but may also work on MBX SoCs. diff --git a/src/3rdparty/clucene/src/CLucene/store/FSDirectory.cpp b/src/3rdparty/clucene/src/CLucene/store/FSDirectory.cpp index 36c170a..e9659cf 100644 --- a/src/3rdparty/clucene/src/CLucene/store/FSDirectory.cpp +++ b/src/3rdparty/clucene/src/CLucene/store/FSDirectory.cpp @@ -624,7 +624,7 @@ LuceneLock* FSDirectory::makeLock(const QString& name) QString lockFile(getLockPrefix()); - lockFile.append(QLatin1String("-")).append(name); + lockFile.append(QLatin1Char('-')).append(name); return _CLNEW FSLock(lockDir, lockFile); } diff --git a/src/3rdparty/clucene/src/CLucene/util/Misc.cpp b/src/3rdparty/clucene/src/CLucene/util/Misc.cpp index 069b487..cb2efe2 100644 --- a/src/3rdparty/clucene/src/CLucene/util/Misc.cpp +++ b/src/3rdparty/clucene/src/CLucene/util/Misc.cpp @@ -181,12 +181,9 @@ void Misc::segmentname(QString& buffer, int32_t bufferLen, CND_PRECONDITION(!segment.isEmpty(), "segment is NULL"); CND_PRECONDITION(!ext.isEmpty(), "extention is NULL"); - buffer.clear(); - if (x == -1) { - buffer = QString(segment + ext); - } else { - buffer = QString(QLatin1String("%1%2%3")).arg(segment).arg(ext).arg(x); - } + buffer = segment + ext; + if (x != -1) + buffer += QString::number(x); } // #pragma mark -- TCHAR related utils diff --git a/src/3rdparty/easing/easing.cpp b/src/3rdparty/easing/easing.cpp new file mode 100644 index 0000000..81af40f --- /dev/null +++ b/src/3rdparty/easing/easing.cpp @@ -0,0 +1,670 @@ +/* +Disclaimer for Robert Penner's Easing Equations license: + +TERMS OF USE - EASING EQUATIONS + +Open source under the BSD License. + +Copyright © 2001 Robert Penner +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <QtCore/qmath.h> +#include <math.h> +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_PI_2 +#define M_PI_2 (M_PI / 2) +#endif + +QT_USE_NAMESPACE + +/** + * Easing equation function for a simple linear tweening, with no easing. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeNone(qreal progress) +{ + return progress; +} + +/** + * Easing equation function for a quadratic (t^2) easing in: accelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInQuad(qreal t) +{ + return t*t; +} + +/** +* Easing equation function for a quadratic (t^2) easing out: decelerating to zero velocity. +* +* @param t Current time (in frames or seconds). +* @return The correct value. +*/ +static qreal easeOutQuad(qreal t) +{ + return -t*(t-2); +} + +/** + * Easing equation function for a quadratic (t^2) easing in/out: acceleration until halfway, then deceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInOutQuad(qreal t) +{ + t*=2.0; + if (t < 1) { + return t*t/qreal(2); + } else { + --t; + return -0.5 * (t*(t-2) - 1); + } +} + +/** + * Easing equation function for a quadratic (t^2) easing out/in: deceleration until halfway, then acceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutInQuad(qreal t) +{ + if (t < 0.5) return easeOutQuad (t*2)/2; + return easeInQuad((2*t)-1)/2 + 0.5; +} + +/** + * Easing equation function for a cubic (t^3) easing in: accelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInCubic(qreal t) +{ + return t*t*t; +} + +/** + * Easing equation function for a cubic (t^3) easing out: decelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutCubic(qreal t) +{ + t-=1.0; + return t*t*t + 1; +} + +/** + * Easing equation function for a cubic (t^3) easing in/out: acceleration until halfway, then deceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInOutCubic(qreal t) +{ + t*=2.0; + if(t < 1) { + return 0.5*t*t*t; + } else { + t -= qreal(2.0); + return 0.5*(t*t*t + 2); + } +} + +/** + * Easing equation function for a cubic (t^3) easing out/in: deceleration until halfway, then acceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutInCubic(qreal t) +{ + if (t < 0.5) return easeOutCubic (2*t)/2; + return easeInCubic(2*t - 1)/2 + 0.5; +} + +/** + * Easing equation function for a quartic (t^4) easing in: accelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInQuart(qreal t) +{ + return t*t*t*t; +} + +/** + * Easing equation function for a quartic (t^4) easing out: decelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutQuart(qreal t) +{ + t-= qreal(1.0); + return - (t*t*t*t- 1); +} + +/** + * Easing equation function for a quartic (t^4) easing in/out: acceleration until halfway, then deceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInOutQuart(qreal t) +{ + t*=2; + if (t < 1) return 0.5*t*t*t*t; + else { + t -= 2.0f; + return -0.5 * (t*t*t*t- 2); + } +} + +/** + * Easing equation function for a quartic (t^4) easing out/in: deceleration until halfway, then acceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutInQuart(qreal t) +{ + if (t < 0.5) return easeOutQuart (2*t)/2; + return easeInQuart(2*t-1)/2 + 0.5; +} + +/** + * Easing equation function for a quintic (t^5) easing in: accelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInQuint(qreal t) +{ + return t*t*t*t*t; +} + +/** + * Easing equation function for a quintic (t^5) easing out: decelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutQuint(qreal t) +{ + t-=1.0; + return t*t*t*t*t + 1; +} + +/** + * Easing equation function for a quintic (t^5) easing in/out: acceleration until halfway, then deceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInOutQuint(qreal t) +{ + t*=2.0; + if (t < 1) return 0.5*t*t*t*t*t; + else { + t -= 2.0; + return 0.5*(t*t*t*t*t + 2); + } +} + +/** + * Easing equation function for a quintic (t^5) easing out/in: deceleration until halfway, then acceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutInQuint(qreal t) +{ + if (t < 0.5) return easeOutQuint (2*t)/2; + return easeInQuint(2*t - 1)/2 + 0.5; +} + +/** + * Easing equation function for a sinusoidal (sin(t)) easing in: accelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInSine(qreal t) +{ + return (t == 1.0) ? 1.0 : -::cos(t * M_PI_2) + 1.0; +} + +/** + * Easing equation function for a sinusoidal (sin(t)) easing out: decelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutSine(qreal t) +{ + return ::sin(t* M_PI_2); +} + +/** + * Easing equation function for a sinusoidal (sin(t)) easing in/out: acceleration until halfway, then deceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInOutSine(qreal t) +{ + return -0.5 * (::cos(M_PI*t) - 1); +} + +/** + * Easing equation function for a sinusoidal (sin(t)) easing out/in: deceleration until halfway, then acceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutInSine(qreal t) +{ + if (t < 0.5) return easeOutSine (2*t)/2; + return easeInSine(2*t - 1)/2 + 0.5; +} + +/** + * Easing equation function for an exponential (2^t) easing in: accelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInExpo(qreal t) +{ + return (t==0 || t == 1.0) ? t : ::qPow(2.0, 10 * (t - 1)) - qreal(0.001); +} + +/** + * Easing equation function for an exponential (2^t) easing out: decelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutExpo(qreal t) +{ + return (t==1.0) ? 1.0 : 1.001 * (-::qPow(2.0f, -10 * t) + 1); +} + +/** + * Easing equation function for an exponential (2^t) easing in/out: acceleration until halfway, then deceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInOutExpo(qreal t) +{ + if (t==0.0) return qreal(0.0); + if (t==1.0) return qreal(1.0); + t*=2.0; + if (t < 1) return 0.5 * ::qPow(qreal(2.0), 10 * (t - 1)) - 0.0005; + return 0.5 * 1.0005 * (-::qPow(qreal(2.0), -10 * (t - 1)) + 2); +} + +/** + * Easing equation function for an exponential (2^t) easing out/in: deceleration until halfway, then acceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutInExpo(qreal t) +{ + if (t < 0.5) return easeOutExpo (2*t)/2; + return easeInExpo(2*t - 1)/2 + 0.5; +} + +/** + * Easing equation function for a circular (sqrt(1-t^2)) easing in: accelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInCirc(qreal t) +{ + return -(::sqrt(1 - t*t) - 1); +} + +/** + * Easing equation function for a circular (sqrt(1-t^2)) easing out: decelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutCirc(qreal t) +{ + t-= qreal(1.0); + return ::sqrt(1 - t* t); +} + +/** + * Easing equation function for a circular (sqrt(1-t^2)) easing in/out: acceleration until halfway, then deceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeInOutCirc(qreal t) +{ + t*=qreal(2.0); + if (t < 1) { + return -0.5 * (::sqrt(1 - t*t) - 1); + } else { + t -= qreal(2.0); + return 0.5 * (::sqrt(1 - t*t) + 1); + } +} + +/** + * Easing equation function for a circular (sqrt(1-t^2)) easing out/in: deceleration until halfway, then acceleration. + * + * @param t Current time (in frames or seconds). + * @return The correct value. + */ +static qreal easeOutInCirc(qreal t) +{ + if (t < 0.5) return easeOutCirc (2*t)/2; + return easeInCirc(2*t - 1)/2 + 0.5; +} + +static qreal easeInElastic_helper(qreal t, qreal b, qreal c, qreal d, qreal a, qreal p) +{ + if (t==0) return b; + qreal t_adj = (qreal)t / (qreal)d; + if (t_adj==1) return b+c; + + qreal s; + if(a < ::fabs(c)) { + a = c; + s = p / 4.0f; + } else { + s = p / (2 * M_PI) * ::asin(c / a); + } + + t_adj -= 1.0f; + return -(a*::qPow(2.0f,10*t_adj) * ::sin( (t_adj*d-s)*(2*M_PI)/p )) + b; +} + +/** + * Easing equation function for an elastic (exponentially decaying sine wave) easing in: accelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @param a Amplitude. + * @param p Period. + * @return The correct value. + */ +static qreal easeInElastic(qreal t, qreal a, qreal p) +{ + return easeInElastic_helper(t, 0, 1, 1, a, p); +} + +static qreal easeOutElastic_helper(qreal t, qreal /*b*/, qreal c, qreal /*d*/, qreal a, qreal p) +{ + if (t==0) return 0; + if (t==1) return c; + + qreal s; + if(a < c) { + a = c; + s = p / 4.0f; + } else { + s = p / (2 * M_PI) * ::asin(c / a); + } + + return (a*::qPow(2.0f,-10*t) * ::sin( (t-s)*(2*M_PI)/p ) + c); +} + +/** + * Easing equation function for an elastic (exponentially decaying sine wave) easing out: decelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @param a Amplitude. + * @param p Period. + * @return The correct value. + */ +static qreal easeOutElastic(qreal t, qreal a, qreal p) +{ + return easeOutElastic_helper(t, 0, 1, 1, a, p); +} + +/** + * Easing equation function for an elastic (exponentially decaying sine wave) easing in/out: acceleration until halfway, then deceleration. + * + * @param t Current time (in frames or seconds). + * @param a Amplitude. + * @param p Period. + * @return The correct value. + */ +static qreal easeInOutElastic(qreal t, qreal a, qreal p) +{ + if (t==0) return 0.0; + t*=2.0; + if (t==2) return 1.0; + + qreal s; + if(a < 1.0) { + a = 1.0; + s = p / 4.0f; + } else { + s = p / (2 * M_PI) * ::asin(1.0 / a); + } + + if (t < 1) return -.5*(a*::qPow(2.0f,10*(t-1)) * ::sin( (t-1-s)*(2*M_PI)/p )); + return a*::qPow(2.0f,-10*(t-1)) * ::sin( (t-1-s)*(2*M_PI)/p )*.5 + 1.0; +} + +/** + * Easing equation function for an elastic (exponentially decaying sine wave) easing out/in: deceleration until halfway, then acceleration. + * + * @param t Current time (in frames or seconds). + * @param a Amplitude. + * @param p Period. + * @return The correct value. + */ +static qreal easeOutInElastic(qreal t, qreal a, qreal p) +{ + if (t < 0.5) return easeOutElastic_helper(t*2, 0, 0.5, 1.0, a, p); + return easeInElastic_helper(2*t - 1.0, 0.5, 0.5, 1.0, a, p); +} + +/** + * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in: accelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @param s Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent). + * @return The correct value. + */ +static qreal easeInBack(qreal t, qreal s) +{ + return t*t*((s+1)*t - s); +} + +/** + * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out: decelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @param s Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent). + * @return The correct value. + */ +static qreal easeOutBack(qreal t, qreal s) +{ + t-= qreal(1.0); + return t*t*((s+1)*t+ s) + 1; +} + +/** + * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in/out: acceleration until halfway, then deceleration. + * + * @param t Current time (in frames or seconds). + * @param s Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent). + * @return The correct value. + */ +static qreal easeInOutBack(qreal t, qreal s) +{ + t *= 2.0; + if (t < 1) { + s *= 1.525f; + return 0.5*(t*t*((s+1)*t - s)); + } else { + t -= 2; + s *= 1.525f; + return 0.5*(t*t*((s+1)*t+ s) + 2); + } +} + +/** + * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out/in: deceleration until halfway, then acceleration. + * + * @param t Current time (in frames or seconds). + * @param s Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent). + * @return The correct value. + */ +static qreal easeOutInBack(qreal t, qreal s) +{ + if (t < 0.5) return easeOutBack (2*t, s)/2; + return easeInBack(2*t - 1, s)/2 + 0.5; +} + +static qreal easeOutBounce_helper(qreal t, qreal c, qreal a) +{ + if (t == 1.0) return c; + if (t < (4/11.0)) { + return c*(7.5625*t*t); + } else if (t < (8/11.0)) { + t -= (6/11.0); + return -a * (1. - (7.5625*t*t + .75)) + c; + } else if (t < (10/11.0)) { + t -= (9/11.0); + return -a * (1. - (7.5625*t*t + .9375)) + c; + } else { + t -= (21/22.0); + return -a * (1. - (7.5625*t*t + .984375)) + c; + } +} + +/** + * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out: decelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @param a Amplitude. + * @return The correct value. + */ +static qreal easeOutBounce(qreal t, qreal a) +{ + return easeOutBounce_helper(t, 1, a); +} + +/** + * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in: accelerating from zero velocity. + * + * @param t Current time (in frames or seconds). + * @param a Amplitude. + * @return The correct value. + */ +static qreal easeInBounce(qreal t, qreal a) +{ + return 1.0 - easeOutBounce_helper(1.0-t, 1.0, a); +} + + +/** + * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in/out: acceleration until halfway, then deceleration. + * + * @param t Current time (in frames or seconds). + * @param a Amplitude. + * @return The correct value. + */ +static qreal easeInOutBounce(qreal t, qreal a) +{ + if (t < 0.5) return easeInBounce (2*t, a)/2; + else return (t == 1.0) ? 1.0 : easeOutBounce (2*t - 1, a)/2 + 0.5; +} + +/** + * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out/in: deceleration until halfway, then acceleration. + * + * @param t Current time (in frames or seconds). + * @param a Amplitude. + * @return The correct value. + */ +static qreal easeOutInBounce(qreal t, qreal a) +{ + if (t < 0.5) return easeOutBounce_helper(t*2, 0.5, a); + return 1.0 - easeOutBounce_helper (2.0-2*t, 0.5, a); +} + +static inline qreal qt_sinProgress(qreal value) +{ + return qSin((value * M_PI) - M_PI_2) / 2 + qreal(0.5); +} + +static inline qreal qt_smoothBeginEndMixFactor(qreal value) +{ + return qMin(qMax(1 - value * 2 + qreal(0.3), qreal(0.0)), qreal(1.0)); +} + +// SmoothBegin blends Smooth and Linear Interpolation. +// Progress 0 - 0.3 : Smooth only +// Progress 0.3 - ~ 0.5 : Mix of Smooth and Linear +// Progress ~ 0.5 - 1 : Linear only + +/** + * Easing function that starts growing slowly, then increases in speed. At the end of the curve the speed will be constant. + */ +static qreal easeInCurve(qreal t) +{ + const qreal sinProgress = qt_sinProgress(t); + const qreal mix = qt_smoothBeginEndMixFactor(t); + return sinProgress * mix + t * (1 - mix); +} + +/** + * Easing function that starts growing steadily, then ends slowly. The speed will be constant at the beginning of the curve. + */ +static qreal easeOutCurve(qreal t) +{ + const qreal sinProgress = qt_sinProgress(t); + const qreal mix = qt_smoothBeginEndMixFactor(1 - t); + return sinProgress * mix + t * (1 - mix); +} + +/** + * Easing function where the value grows sinusoidally. Note that the calculated end value will be 0 rather than 1. + */ +static qreal easeSineCurve(qreal t) +{ + return (qSin(((t * M_PI * 2)) - M_PI_2) + 1) / 2; +} + +/** + * Easing function where the value grows cosinusoidally. Note that the calculated start value will be 0.5 and the end value will be 0.5 + * contrary to the usual 0 to 1 easing curve. + */ +static qreal easeCosineCurve(qreal t) +{ + return (qCos(((t * M_PI * 2)) - M_PI_2) + 1) / 2; +} + diff --git a/src/3rdparty/easing/legal.qdoc b/src/3rdparty/easing/legal.qdoc new file mode 100644 index 0000000..25f67e1 --- /dev/null +++ b/src/3rdparty/easing/legal.qdoc @@ -0,0 +1,35 @@ +/*! +\page legal-easing.html +\title Easing Equations by Robert Penner +\ingroup animation + +\legalese +\code +Copyright (c) 2001 Robert Penner +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the author nor the names of contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\endcode +\endlegalese +*/ diff --git a/src/3rdparty/phonon/phonon/effectwidget.cpp b/src/3rdparty/phonon/phonon/effectwidget.cpp index da5a51a..d5c6c81 100644 --- a/src/3rdparty/phonon/phonon/effectwidget.cpp +++ b/src/3rdparty/phonon/phonon/effectwidget.cpp @@ -165,6 +165,7 @@ void EffectWidgetPrivate::autogenerateUi() if (minValue == -1. && maxValue == 1.) { //Special case values between -1 and 1.0 to use a slider for improved usability QSlider *slider = new QSlider(Qt::Horizontal, q); + control = slider; slider->setRange(-SLIDER_RANGE, +SLIDER_RANGE); slider->setValue(int(SLIDER_RANGE * value.toDouble())); slider->setTickPosition(QSlider::TicksBelow); @@ -188,10 +189,10 @@ void EffectWidgetPrivate::autogenerateUi() break; } + if (control) { #ifndef QT_NO_TOOLTIP control->setToolTip(para.description()); #endif - if (control) { #ifndef QT_NO_SHORTCUT label->setBuddy(control); #endif diff --git a/src/3rdparty/phonon/phonon/phonon_export.h b/src/3rdparty/phonon/phonon/phonon_export.h index e579f67..5f93ea0 100644 --- a/src/3rdparty/phonon/phonon/phonon_export.h +++ b/src/3rdparty/phonon/phonon/phonon_export.h @@ -32,7 +32,11 @@ # define PHONON_EXPORT Q_DECL_IMPORT # endif # else /* UNIX */ -# define PHONON_EXPORT Q_DECL_EXPORT +# ifdef MAKE_PHONON_LIB /* We are building this library */ +# define PHONON_EXPORT Q_DECL_EXPORT +# else /* We are using this library */ +# define PHONON_EXPORT Q_DECL_IMPORT +# endif # endif #endif diff --git a/src/3rdparty/phonon/phonon/phononnamespace.h b/src/3rdparty/phonon/phonon/phononnamespace.h index 0bbf4f4..2492ee6 100644 --- a/src/3rdparty/phonon/phonon/phononnamespace.h +++ b/src/3rdparty/phonon/phonon/phononnamespace.h @@ -25,6 +25,11 @@ #include "phonon_export.h" +#ifdef __QT_SYNCQT__ +// Tell syncqt to create a "Global" header here +#pragma qt_class(Phonon::Global) +#endif + /** * Helper macro that can be used like * \code diff --git a/src/3rdparty/powervr/pvr2d.h b/src/3rdparty/powervr/pvr2d.h new file mode 100644 index 0000000..07f28c7 --- /dev/null +++ b/src/3rdparty/powervr/pvr2d.h @@ -0,0 +1,502 @@ +/*!**************************************************************************** +@File pvr2d.h +@Title PVR2D external header file +@Author Imagination Technologies +@Copyright Copyright (c) by Imagination Technologies Limited. + This specification is protected by copyright laws and contains + material proprietary to Imagination Technologies Limited. + You may use and distribute this specification free of charge for implementing + the functionality therein, without altering or removing any trademark, copyright, + or other notice from the specification. +@Platform Generic +@Description PVR2D definitions for PVR2D clients +******************************************************************************/ + + +/****************************************************************************** +Modifications :- +$Log: pvr2d.h $ +******************************************************************************/ + +#ifndef _PVR2D_H_ +#define _PVR2D_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* PVR2D Platform-specific definitions */ +#define PVR2D_EXPORT +#define PVR2D_IMPORT + + +#define PVR2D_REV_MAJOR 2 +#define PVR2D_REV_MINOR 1 + +typedef enum +{ + PVR2D_FALSE = 0, + PVR2D_TRUE +} PVR2D_BOOL; + + +/* error codes */ +typedef enum +{ + PVR2D_OK = 0, + PVR2DERROR_INVALID_PARAMETER = -1, + PVR2DERROR_DEVICE_UNAVAILABLE = -2, + PVR2DERROR_INVALID_CONTEXT = -3, + PVR2DERROR_MEMORY_UNAVAILABLE = -4, + PVR2DERROR_DEVICE_NOT_PRESENT = -5, + PVR2DERROR_IOCTL_ERROR = -6, + PVR2DERROR_GENERIC_ERROR = -7, + PVR2DERROR_BLT_NOTCOMPLETE = -8, + PVR2DERROR_HW_FEATURE_NOT_SUPPORTED = -9, + PVR2DERROR_NOT_YET_IMPLEMENTED = -10, + PVR2DERROR_MAPPING_FAILED = -11 +}PVR2DERROR; + + +/* pixel formats */ +typedef enum +{ + PVR2D_1BPP = 0, + PVR2D_RGB565, + PVR2D_ARGB4444, + PVR2D_RGB888, + PVR2D_ARGB8888, + PVR2D_ARGB1555, + PVR2D_ALPHA8, + PVR2D_ALPHA4, + PVR2D_PAL2, + PVR2D_PAL4, + PVR2D_PAL8, + PVR2D_VGAEMU + +}PVR2DFORMAT; + + +/* wrap surface type */ +typedef enum +{ + PVR2D_WRAPFLAG_NONCONTIGUOUS = 0, + PVR2D_WRAPFLAG_CONTIGUOUS = 1, + +}PVR2DWRAPFLAGS; + +/* flags for control information of additional blits */ +typedef enum +{ + PVR2D_BLIT_DISABLE_ALL = 0x0000, /* disable all additional controls */ + PVR2D_BLIT_CK_ENABLE = 0x0001, /* enable colour key */ + PVR2D_BLIT_GLOBAL_ALPHA_ENABLE = 0x0002, /* enable standard global alpha */ + PVR2D_BLIT_PERPIXEL_ALPHABLEND_ENABLE = 0x0004, /* enable per-pixel alpha bleding */ + PVR2D_BLIT_PAT_SURFACE_ENABLE = 0x0008, /* enable pattern surf (disable fill) */ + PVR2D_BLIT_FULLY_SPECIFIED_ALPHA_ENABLE = 0x0010, /* enable fully specified alpha */ + PVR2D_BLIT_ROT_90 = 0x0020, /* apply 90 degree rotation to the blt */ + PVR2D_BLIT_ROT_180 = 0x0040, /* apply 180 degree rotation to the blt */ + PVR2D_BLIT_ROT_270 = 0x0080, /* apply 270 degree rotation to the blt */ + PVR2D_BLIT_COPYORDER_TL2BR = 0x0100, /* copy order overrides */ + PVR2D_BLIT_COPYORDER_BR2TL = 0x0200, + PVR2D_BLIT_COPYORDER_TR2BL = 0x0400, + PVR2D_BLIT_COPYORDER_BL2TR = 0x0800, + PVR2D_BLIT_COLKEY_SOURCE = 0x1000, /* Key colour is on the source surface */ + PVR2D_BLIT_COLKEY_DEST = 0x2000 /* Key colour is on the destination surface */ + +} PVR2DBLITFLAGS; + +/* standard alpha-blending functions, AlphaBlendingFunc field of PVR2DBLTINFO */ +typedef enum +{ + PVR2D_ALPHA_OP_SRC_DSTINV = 1, /* source alpha : Cdst = Csrc*Asrc + Cdst*(1-Asrc) */ + PVR2D_ALPHA_OP_SRCP_DSTINV = 2 /* premultiplied source alpha : Cdst = Csrc + Cdst*(1-Asrc) */ +} PVR2D_ALPHABLENDFUNC; + +/* blend ops for fully specified alpha */ +typedef enum +{ + PVR2D_BLEND_OP_ZERO = 0, + PVR2D_BLEND_OP_ONE = 1, + PVR2D_BLEND_OP_SRC = 2, + PVR2D_BLEND_OP_DST = 3, + PVR2D_BLEND_OP_GLOBAL = 4, + PVR2D_BLEND_OP_SRC_PLUS_GLOBAL = 5, + PVR2D_BLEND_OP_DST_PLUS_GLOBAL = 6 +}PVR2D_BLEND_OP; + + +typedef void* PVR2D_HANDLE; + + +/* Fully specified alpha blend : pAlpha field of PVR2DBLTINFO structure */ +/* a fully specified Alpha Blend operation is defined as */ +/* DST (ALPHA) = (ALPHA_1 * SRC (ALPHA)) + (ALPHA_3 * DST (ALPHA)) */ +/* DST (RGB) = (ALPHA_2 * SRC (RGB)) + (ALPHA_4 * DST (RGB)) */ +/* if the pre-multiplication stage is enabled then the equations become the following: */ +/* PRE_MUL = ((SRC(A)) * (Global Alpha Value)) */ +/* DST (ALPHA) = (ALPHA_1 * SRC (ALPHA)) + (PRE_MUL * DST (ALPHA)) */ +/* DST (RGB) = (ALPHA_2 * SRC (RGB)) + (PRE_MUL * DST (RGB)) */ +/* if the transparent source alpha stage is enabled then a source alpha of zero forces the */ +/* source to be transparent for that pixel regardless of the blend equation being used. */ +typedef struct _PVR2D_ALPHABLT +{ + PVR2D_BLEND_OP eAlpha1; + PVR2D_BOOL bAlpha1Invert; + PVR2D_BLEND_OP eAlpha2; + PVR2D_BOOL bAlpha2Invert; + PVR2D_BLEND_OP eAlpha3; + PVR2D_BOOL bAlpha3Invert; + PVR2D_BLEND_OP eAlpha4; + PVR2D_BOOL bAlpha4Invert; + PVR2D_BOOL bPremulAlpha; /* enable pre-multiplication stage */ + PVR2D_BOOL bTransAlpha; /* enable transparent source alpha stage */ + PVR2D_BOOL bUpdateAlphaLookup; /* enable and update the 1555-Lookup alpha table */ + unsigned char uAlphaLookup0; /* 8 bit alpha when A=0 in a 1555-Lookup surface */ + unsigned char uAlphaLookup1; /* 8 bit alpha when A=1 in a 1555-Lookup surface */ + unsigned char uGlobalRGB; /* Global Alpha Value for RGB, 0=transparent 255=opaque */ + unsigned char uGlobalA; /* Global Alpha Value for Alpha */ + +} PVR2D_ALPHABLT, *PPVR2D_ALPHABLT; + + +/* surface memory info structure */ +typedef struct _PVR2DMEMINFO +{ + void *pBase; + unsigned long ui32MemSize; + unsigned long ui32DevAddr; + unsigned long ulFlags; + void *hPrivateData; + void *hPrivateMapData; + +}PVR2DMEMINFO, *PPVR2DMEMINFO; + + +#define PVR2D_MAX_DEVICE_NAME 20 + +typedef struct _PVR2DDEVICEINFO +{ + unsigned long ulDevID; + char szDeviceName[PVR2D_MAX_DEVICE_NAME]; +}PVR2DDEVICEINFO; + + +typedef struct _PVR2DISPLAYINFO +{ + unsigned long ulMaxFlipChains; + unsigned long ulMaxBuffersInChain; + PVR2DFORMAT eFormat; + unsigned long ulWidth; + unsigned long ulHeight; + long lStride; + unsigned long ulMinFlipInterval; + unsigned long ulMaxFlipInterval; + +}PVR2DDISPLAYINFO; + + +typedef struct _PVR2DBLTINFO +{ + unsigned long CopyCode; /* rop code */ + unsigned long Colour; /* fill colour */ + unsigned long ColourKey; /* colour key */ + unsigned char GlobalAlphaValue; /* global alpha blending */ + unsigned char AlphaBlendingFunc; /* per-pixel alpha-blending function */ + + PVR2DBLITFLAGS BlitFlags; /* additional blit control information */ + + PVR2DMEMINFO *pDstMemInfo; /* destination memory */ + unsigned long DstOffset; /* byte offset from start of allocation to destination surface pixel 0,0 */ + long DstStride; /* signed stride, the number of bytes from pixel 0,0 to 0,1 */ + long DstX, DstY; /* pixel offset from start of dest surface to start of blt rectangle */ + long DSizeX,DSizeY; /* blt size */ + PVR2DFORMAT DstFormat; /* dest format */ + unsigned long DstSurfWidth; /* size of dest surface in pixels */ + unsigned long DstSurfHeight; /* size of dest surface in pixels */ + + PVR2DMEMINFO *pSrcMemInfo; /* source mem, (source fields are also used for patterns) */ + unsigned long SrcOffset; /* byte offset from start of allocation to src/pat surface pixel 0,0 */ + long SrcStride; /* signed stride, the number of bytes from pixel 0,0 to 0,1 */ + long SrcX, SrcY; /* pixel offset from start of surface to start of source rectangle */ + /* for patterns this is the start offset within the pattern */ + long SizeX,SizeY; /* source rectangle size or pattern size in pixels */ + PVR2DFORMAT SrcFormat; /* source/pattern format */ + PVR2DMEMINFO *pPalMemInfo; /* source/pattern palette memory containing argb8888 colour table */ + unsigned long PalOffset; /* byte offset from start of allocation to start of palette */ + unsigned long SrcSurfWidth; /* size of source surface in pixels */ + unsigned long SrcSurfHeight; /* size of source surface in pixels */ + + PVR2DMEMINFO *pMaskMemInfo; /* mask memory, 1bpp format implied */ + unsigned long MaskOffset; /* byte offset from start of allocation to mask surface pixel 0,0 */ + long MaskStride; /* signed stride, the number of bytes from pixel 0,0 to 0,1 */ + long MaskX, MaskY; /* mask rect top left (mask size = blt size) */ + unsigned long MaskSurfWidth; /* size of mask surface in pixels */ + unsigned long MaskSurfHeight; /* size of mask surface in pixels */ + + PPVR2D_ALPHABLT pAlpha; /* fully specified alpha blend */ + +}PVR2DBLTINFO, *PPVR2DBLTINFO; + +typedef struct _PVR2DRECT +{ + long left, top; + long right, bottom; +} PVR2DRECT; + +typedef struct +{ + PVR2DMEMINFO *pSurfMemInfo; /* surface memory */ + unsigned long SurfOffset; /* byte offset from start of allocation to destination surface pixel 0,0 */ + long Stride; /* signed stride */ + PVR2DFORMAT Format; + unsigned long SurfWidth; /* surface size in pixels */ + unsigned long SurfHeight; + +} PVR2D_SURFACE, *PPVR2D_SURFACE; + +typedef struct +{ + unsigned long *pUseCode; /* USSE code */ + unsigned long UseCodeSize; /* usse code size in bytes */ + +} PVR2D_USECODE, *PPVR2D_USECODE; + +typedef struct +{ + PVR2D_SURFACE sDst; /* destination surface */ + PVR2D_SURFACE sSrc; /* source surface */ + PVR2DRECT rcDest; /* destination rectangle */ + PVR2DRECT rcSource; /* source rectangle */ + PVR2D_HANDLE hUseCode; /* custom USE code (NULL implies source copy) */ + unsigned long UseParams[2]; /* per-blt params for use code */ + +} PVR2D_3DBLT, *PPVR2D_3DBLT; + + +#define MAKE_COPY_BLIT(src,soff,dest,doff,sx,sy,dx,dy,sz) + +typedef void* PVR2DCONTEXTHANDLE; +typedef void* PVR2DFLIPCHAINHANDLE; + + +// CopyCode field of PVR2DBLTINFO structure: +// the CopyCode field of the PVR2DBLTINFO structure should contain a rop3 or rop4 code. +// a rop3 is an 8 bit code that describes a blt with three inputs : source dest and pattern +// rop4 is a 16 bit code that describes a blt with four inputs : source dest pattern and mask +// common rop3 codes are defined below +// a colour fill blt is processed in the pattern channel as a constant colour with a rop code of 0xF0 +// PVR2D_BLIT_PAT_SURFACE_ENABLE defines whether the pattern channel is a surface or a fill colour. +// a rop4 is defined by two rop3 codes, and the 1 bit-per-pixel mask surface defines which is used. +// a common rop4 is 0xAAF0 which is the mask copy blt used for text glyphs. +// CopyCode is taken to be a rop4 when pMaskMemInfo is non zero, otherwise it is assumed to be a rop3 +// use the PVR2DMASKROP4 macro below to construct a rop4 from two rop3's +// rop3a is the rop used when mask pixel = 1, and rop3b when mask = 0 +#define PVR2DROP4(rop3b, rop3a) ((rop3b<<8)|rop3a) + +/* common rop codes */ +#define PVR2DROPclear 0x00 /* 0 (whiteness) */ +#define PVR2DROPset 0xFF /* 1 (blackness) */ +#define PVR2DROPnoop 0xAA /* dst (used for masked blts) */ + +/* source and dest rop codes */ +#define PVR2DROPand 0x88 /* src AND dst */ +#define PVR2DROPandReverse 0x44 /* src AND NOT dst */ +#define PVR2DROPcopy 0xCC /* src (used for source copy and alpha blts) */ +#define PVR2DROPandInverted 0x22 /* NOT src AND dst */ +#define PVR2DROPxor 0x66 /* src XOR dst */ +#define PVR2DROPor 0xEE /* src OR dst */ +#define PVR2DROPnor 0x11 /* NOT src AND NOT dst */ +#define PVR2DROPequiv 0x99 /* NOT src XOR dst */ +#define PVR2DROPinvert 0x55 /* NOT dst */ +#define PVR2DROPorReverse 0xDD /* src OR NOT dst */ +#define PVR2DROPcopyInverted 0x33 /* NOT src */ +#define PVR2DROPorInverted 0xBB /* NOT src OR dst */ +#define PVR2DROPnand 0x77 /* NOT src OR NOT dst */ + +/* pattern rop codes */ +#define PVR2DPATROPand 0xA0 /* pat AND dst */ +#define PVR2DPATROPandReverse 0x50 /* pat AND NOT dst */ +#define PVR2DPATROPcopy 0xF0 /* pat (used for solid color fills and pattern blts) */ +#define PVR2DPATROPandInverted 0x0A /* NOT pat AND dst */ +#define PVR2DPATROPxor 0x5A /* pat XOR dst */ +#define PVR2DPATROPor 0xFA /* pat OR dst */ +#define PVR2DPATROPnor 0x05 /* NOT pat AND NOT dst */ +#define PVR2DPATROPequiv 0xA5 /* NOT pat XOR dst */ +#define PVR2DPATROPinvert 0x55 /* NOT dst */ +#define PVR2DPATROPorReverse 0xF5 /* pat OR NOT dst */ +#define PVR2DPATROPcopyInverted 0x0F /* NOT pat */ +#define PVR2DPATROPorInverted 0xAF /* NOT pat OR dst */ +#define PVR2DPATROPnand 0x5F /* NOT pat OR NOT dst */ + +/* common rop4 codes */ +#define PVR2DROP4MaskedCopy PVR2DROP4(PVR2DROPnoop,PVR2DROPcopy) /* masked source copy blt (used for rounded window corners etc) */ +#define PVR2DROP4MaskedFill PVR2DROP4(PVR2DROPnoop,PVR2DPATROPcopy) /* masked colour fill blt (used for text) */ + +/* Legacy support */ +#define PVR2DROP3_PATMASK PVR2DPATROPcopy +#define PVR2DROP3_SRCMASK PVR2DROPcopy + +/* pixmap memory alignment */ +#define PVR2D_ALIGNMENT_4 4 /* DWORD alignment */ +#define PVR2D_ALIGNMENT_ANY 0 /* no alignment */ +#define PVR2D_ALIGNMENT_PALETTE 16 /* 16 byte alignment is required for palettes */ + +/* Heap number for PVR2DGetFrameBuffer */ +#define PVR2D_FB_PRIMARY_SURFACE 0 + +#define PVR2D_PRESENT_PROPERTY_SRCSTRIDE (1 << 0) +#define PVR2D_PRESENT_PROPERTY_DSTSIZE (1 << 1) +#define PVR2D_PRESENT_PROPERTY_DSTPOS (1 << 2) +#define PVR2D_PRESENT_PROPERTY_CLIPRECTS (1 << 3) +#define PVR2D_PRESENT_PROPERTY_INTERVAL (1 << 4) + + +#define PVR2D_CREATE_FLIPCHAIN_SHARED (1 << 0) +#define PVR2D_CREATE_FLIPCHAIN_QUERY (1 << 1) + +/* Functions that the library exports */ + +PVR2D_IMPORT +int PVR2DEnumerateDevices(PVR2DDEVICEINFO *pDevInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DCreateDeviceContext(unsigned long ulDevID, + PVR2DCONTEXTHANDLE* phContext, + unsigned long ulFlags); + +PVR2D_IMPORT +PVR2DERROR PVR2DDestroyDeviceContext(PVR2DCONTEXTHANDLE hContext); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetDeviceInfo(PVR2DCONTEXTHANDLE hContext, + PVR2DDISPLAYINFO *pDisplayInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetScreenMode(PVR2DCONTEXTHANDLE hContext, + PVR2DFORMAT *pFormat, + long *plWidth, + long *plHeight, + long *plStride, + int *piRefreshRate); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetFrameBuffer(PVR2DCONTEXTHANDLE hContext, + int nHeap, + PVR2DMEMINFO **ppsMemInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DMemAlloc(PVR2DCONTEXTHANDLE hContext, + unsigned long ulBytes, + unsigned long ulAlign, + unsigned long ulFlags, + PVR2DMEMINFO **ppsMemInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DMemWrap(PVR2DCONTEXTHANDLE hContext, + void *pMem, + unsigned long ulFlags, + unsigned long ulBytes, + unsigned long alPageAddress[], + PVR2DMEMINFO **ppsMemInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DMemMap(PVR2DCONTEXTHANDLE hContext, + unsigned long ulFlags, + void *hPrivateMapData, + PVR2DMEMINFO **ppsDstMem); + +PVR2D_IMPORT +PVR2DERROR PVR2DMemFree(PVR2DCONTEXTHANDLE hContext, + PVR2DMEMINFO *psMemInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DBlt(PVR2DCONTEXTHANDLE hContext, + PVR2DBLTINFO *pBltInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DBltClipped(PVR2DCONTEXTHANDLE hContext, + PVR2DBLTINFO *pBltInfo, + unsigned long ulNumClipRects, + PVR2DRECT *pClipRects); + +PVR2D_IMPORT +PVR2DERROR PVR2DQueryBlitsComplete(PVR2DCONTEXTHANDLE hContext, + PVR2DMEMINFO *pMemInfo, + unsigned int uiWaitForComplete); + +PVR2D_IMPORT +PVR2DERROR PVR2DSetPresentBltProperties(PVR2DCONTEXTHANDLE hContext, + unsigned long ulPropertyMask, + long lSrcStride, + unsigned long ulDstWidth, + unsigned long ulDstHeight, + long lDstXPos, + long lDstYPos, + unsigned long ulNumClipRects, + PVR2DRECT *pClipRects, + unsigned long ulSwapInterval); + +PVR2D_IMPORT +PVR2DERROR PVR2DPresentBlt(PVR2DCONTEXTHANDLE hContext, + PVR2DMEMINFO *pMemInfo, + long lRenderID); + +PVR2D_IMPORT +PVR2DERROR PVR2DCreateFlipChain(PVR2DCONTEXTHANDLE hContext, + unsigned long ulFlags, + unsigned long ulNumBuffers, + unsigned long ulWidth, + unsigned long ulHeight, + PVR2DFORMAT eFormat, + long *plStride, + unsigned long *pulFlipChainID, + PVR2DFLIPCHAINHANDLE *phFlipChain); + +PVR2D_IMPORT +PVR2DERROR PVR2DDestroyFlipChain(PVR2DCONTEXTHANDLE hContext, + PVR2DFLIPCHAINHANDLE hFlipChain); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetFlipChainBuffers(PVR2DCONTEXTHANDLE hContext, + PVR2DFLIPCHAINHANDLE hFlipChain, + unsigned long *pulNumBuffers, + PVR2DMEMINFO *psMemInfo[]); + +PVR2D_IMPORT +PVR2DERROR PVR2DSetPresentFlipProperties(PVR2DCONTEXTHANDLE hContext, + PVR2DFLIPCHAINHANDLE hFlipChain, + unsigned long ulPropertyMask, + long lDstXPos, + long lDstYPos, + unsigned long ulNumClipRects, + PVR2DRECT *pClipRects, + unsigned long ulSwapInterval); + +PVR2D_IMPORT +PVR2DERROR PVR2DPresentFlip(PVR2DCONTEXTHANDLE hContext, + PVR2DFLIPCHAINHANDLE hFlipChain, + PVR2DMEMINFO *psMemInfo, + long lRenderID); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetAPIRev(long *lRevMajor, long *lRevMinor); + +PVR2D_IMPORT +PVR2DERROR PVR2DLoadUseCode (const PVR2DCONTEXTHANDLE hContext, const unsigned char *pUseCode, + const unsigned long UseCodeSize, PVR2D_HANDLE *pUseCodeHandle); +PVR2D_IMPORT +PVR2DERROR PVR2DFreeUseCode (const PVR2DCONTEXTHANDLE hContext, const PVR2D_HANDLE hUseCodeHandle); + +PVR2D_IMPORT +PVR2DERROR PVR2DBlt3D (const PVR2DCONTEXTHANDLE hContext, const PPVR2D_3DBLT pBlt3D); + +#ifdef __cplusplus +} +#endif + +#endif /* _PVR2D_H_ */ + +/****************************************************************************** + End of file (pvr2d.h) +******************************************************************************/ diff --git a/src/3rdparty/powervr/wsegl.h b/src/3rdparty/powervr/wsegl.h new file mode 100644 index 0000000..0490607 --- /dev/null +++ b/src/3rdparty/powervr/wsegl.h @@ -0,0 +1,240 @@ +/****************************************************************************** + Name : wsegl.h + Copyright : Copyright (c) Imagination Technologies Limited. + This specification is protected by copyright laws and contains + material proprietary to Imagination Technologies Limited. + You may use and distribute this specification free of charge for implementing + the functionality therein, without altering or removing any trademark, copyright, + or other notice from the specification. + Platform : ANSI +*****************************************************************************/ + + +#if !defined(__WSEGL_H__) +#define __WSEGL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +// WSEGL Platform-specific definitions +*/ +#define WSEGL_EXPORT +#define WSEGL_IMPORT + +/* +// WSEGL API Version Number +*/ + +#define WSEGL_VERSION 1 +#define WSEGL_DEFAULT_DISPLAY 0 +#define WSEGL_DEFAULT_NATIVE_ENGINE 0 + +#define WSEGL_FALSE 0 +#define WSEGL_TRUE 1 +#define WSEGL_NULL 0 + +#define WSEGL_UNREFERENCED_PARAMETER(param) (param) = (param) + +/* +// WSEGL handles +*/ +typedef void *WSEGLDisplayHandle; +typedef void *WSEGLDrawableHandle; + +/* +// Display capability type +*/ +typedef enum WSEGLCapsType_TAG +{ + WSEGL_NO_CAPS = 0, + WSEGL_CAP_MIN_SWAP_INTERVAL = 1, /* System default value = 1 */ + WSEGL_CAP_MAX_SWAP_INTERVAL = 2, /* System default value = 1 */ + WSEGL_CAP_WINDOWS_USE_HW_SYNC = 3, /* System default value = 0 (FALSE) */ + WSEGL_CAP_PIXMAPS_USE_HW_SYNC = 4, /* System default value = 0 (FALSE) */ + +} WSEGLCapsType; + +/* +// Display capability +*/ +typedef struct WSEGLCaps_TAG +{ + WSEGLCapsType eCapsType; + unsigned long ui32CapsValue; + +} WSEGLCaps; + +/* +// Drawable type +*/ +#define WSEGL_NO_DRAWABLE 0x0 +#define WSEGL_DRAWABLE_WINDOW 0x1 +#define WSEGL_DRAWABLE_PIXMAP 0x2 + + +/* +// Pixel format of display/drawable +*/ +typedef enum WSEGLPixelFormat_TAG +{ + WSEGL_PIXELFORMAT_565 = 0, + WSEGL_PIXELFORMAT_4444 = 1, + WSEGL_PIXELFORMAT_8888 = 2, + WSEGL_PIXELFORMAT_1555 = 3 + +} WSEGLPixelFormat; + +/* +// Transparent of display/drawable +*/ +typedef enum WSEGLTransparentType_TAG +{ + WSEGL_OPAQUE = 0, + WSEGL_COLOR_KEY = 1, + +} WSEGLTransparentType; + +/* +// Display/drawable configuration +*/ +typedef struct WSEGLConfig_TAG +{ + /* + // Type of drawables this configuration applies to - + // OR'd values of drawable types. + */ + unsigned long ui32DrawableType; + + /* Pixel format */ + WSEGLPixelFormat ePixelFormat; + + /* Native Renderable - set to WSEGL_TRUE if native renderable */ + unsigned long ulNativeRenderable; + + /* FrameBuffer Level Parameter */ + unsigned long ulFrameBufferLevel; + + /* Native Visual ID */ + unsigned long ulNativeVisualID; + + /* Native Visual */ + void *hNativeVisual; + + /* Transparent Type */ + WSEGLTransparentType eTransparentType; + + /* Transparent Color - only used if transparent type is COLOR_KEY */ + unsigned long ulTransparentColor; /* packed as 0x00RRGGBB */ + + +} WSEGLConfig; + +/* +// WSEGL errors +*/ +typedef enum WSEGLError_TAG +{ + WSEGL_SUCCESS = 0, + WSEGL_CANNOT_INITIALISE = 1, + WSEGL_BAD_NATIVE_DISPLAY = 2, + WSEGL_BAD_NATIVE_WINDOW = 3, + WSEGL_BAD_NATIVE_PIXMAP = 4, + WSEGL_BAD_NATIVE_ENGINE = 5, + WSEGL_BAD_DRAWABLE = 6, + WSEGL_BAD_CONFIG = 7, + WSEGL_OUT_OF_MEMORY = 8 + +} WSEGLError; + +/* +// Drawable orientation (in degrees anti-clockwise) +*/ +typedef enum WSEGLRotationAngle_TAG +{ + WSEGL_ROTATE_0 = 0, + WSEGL_ROTATE_90 = 1, + WSEGL_ROTATE_180 = 2, + WSEGL_ROTATE_270 = 3 + +} WSEGLRotationAngle; + +/* +// Drawable information required by OpenGL-ES driver +*/ +typedef struct WSEGLDrawableParams_TAG +{ + /* Width in pixels of the drawable */ + unsigned long ui32Width; + + /* Height in pixels of the drawable */ + unsigned long ui32Height; + + /* Stride in pixels of the drawable */ + unsigned long ui32Stride; + + /* Pixel format of the drawable */ + WSEGLPixelFormat ePixelFormat; + + /* User space cpu virtual address of the drawable */ + void *pvLinearAddress; + + /* HW address of the drawable */ + unsigned long ui32HWAddress; + + /* Private data for the drawable */ + void *hPrivateData; + +} WSEGLDrawableParams; + + +/* +// Table of function pointers that is returned by WSEGL_GetFunctionTablePointer() +// +// The first entry in the table is the version number of the wsegl.h header file that +// the module has been written against, and should therefore be set to WSEGL_VERSION +*/ +typedef struct WSEGL_FunctionTable_TAG +{ + unsigned long ui32WSEGLVersion; + + WSEGLError (*pfnWSEGL_IsDisplayValid)(NativeDisplayType); + + WSEGLError (*pfnWSEGL_InitialiseDisplay)(NativeDisplayType, WSEGLDisplayHandle *, const WSEGLCaps **, WSEGLConfig **); + + WSEGLError (*pfnWSEGL_CloseDisplay)(WSEGLDisplayHandle); + + WSEGLError (*pfnWSEGL_CreateWindowDrawable)(WSEGLDisplayHandle, WSEGLConfig *, WSEGLDrawableHandle *, NativeWindowType, WSEGLRotationAngle *); + + WSEGLError (*pfnWSEGL_CreatePixmapDrawable)(WSEGLDisplayHandle, WSEGLConfig *, WSEGLDrawableHandle *, NativePixmapType, WSEGLRotationAngle *); + + WSEGLError (*pfnWSEGL_DeleteDrawable)(WSEGLDrawableHandle); + + WSEGLError (*pfnWSEGL_SwapDrawable)(WSEGLDrawableHandle, unsigned long); + + WSEGLError (*pfnWSEGL_SwapControlInterval)(WSEGLDrawableHandle, unsigned long); + + WSEGLError (*pfnWSEGL_WaitNative)(WSEGLDrawableHandle, unsigned long); + + WSEGLError (*pfnWSEGL_CopyFromDrawable)(WSEGLDrawableHandle, NativePixmapType); + + WSEGLError (*pfnWSEGL_CopyFromPBuffer)(void *, unsigned long, unsigned long, unsigned long, WSEGLPixelFormat, NativePixmapType); + + WSEGLError (*pfnWSEGL_GetDrawableParameters)(WSEGLDrawableHandle, WSEGLDrawableParams *, WSEGLDrawableParams *); + + +} WSEGL_FunctionTable; + + +WSEGL_IMPORT const WSEGL_FunctionTable *WSEGL_GetFunctionTablePointer(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __WSEGL_H__ */ + +/****************************************************************************** + End of file (wsegl.h) +******************************************************************************/ diff --git a/src/3rdparty/webkit/VERSION b/src/3rdparty/webkit/VERSION index 26ce489..7d5d1c5 100644 --- a/src/3rdparty/webkit/VERSION +++ b/src/3rdparty/webkit/VERSION @@ -8,4 +8,4 @@ The commit imported was from the and has the sha1 checksum - a6ebe3865025e2bb4d767a79435af4daf5a9b4db + 4ee8af9348b3f57d3c0f3575ae0a58336cf07a92 diff --git a/src/3rdparty/webkit/WebCore/ChangeLog b/src/3rdparty/webkit/WebCore/ChangeLog index 00bd427..072beee 100644 --- a/src/3rdparty/webkit/WebCore/ChangeLog +++ b/src/3rdparty/webkit/WebCore/ChangeLog @@ -1,3 +1,143 @@ +2009-05-19 Kenneth Rohde Christiansen <kenneth.christiansen@openbossa.org> + + Reviewed by Simon Hausmann. + + Do not call the parent implementation (Widget::) in show() and hide() + of the PluginViewQt, as it always changes the visible state of the + platformWidget (equal to the platformPluginWidget in the Qt port), + thus ignoring the isParentVisible() test. + + * plugins/qt/PluginViewQt.cpp: + (WebCore::PluginView::show): + (WebCore::PluginView::hide): + +2009-04-22 Tamas Szirbucz <szirbucz.tamas@stud.u-szeged.hu> + + Reviewed by Ariya Hidayat. + + https://bugs.webkit.org/show_bug.cgi?id=25023 + Delete reply in QNetworkReplyHandler::abort() to avoid leak. + + * platform/network/qt/QNetworkReplyHandler.cpp: + (WebCore::QNetworkReplyHandler::abort): + +2009-05-20 Holger Hans Peter Freyther <zecke@selfish.org> + + Reviewed by Anders Carlsson. + + https://bugs.webkit.org/show_bug.cgi?id=24510 + + Fix a bug where the browserfuncs were not properly assigned, + make hasproperty use _NP_HasProperty and hasmethod _NP_HasMethod. + + Test: plugins/netscape-invoke-browserfuncs.html + + * plugins/gtk/PluginPackageGtk.cpp: + (WebCore::PluginPackage::load): Fix assignment + * plugins/qt/PluginPackageQt.cpp: + (WebCore::PluginPackage::load): Fix assignment + +2009-05-11 Yael Aharon <yael.aharon@nokia.com> + + Reviewed by Holger Freyther. + + Change Qt port to match the mac and windows ports, and unregister plugins when plugins are stopped. + Not doing that can cause assersion failure. + https://bugs.webkit.org/show_bug.cgi?id=25702 + + * plugins/qt/PluginViewQt.cpp: + (WebCore::PluginView::stop): + +2009-05-18 Ariya Hidayat <ariya.hidayat@nokia.com> + + Reviewed by Simon Hausmann. + + Done together with Balazs Kelemen <kelemen.balazs@stud.u-szeged.hu>. + + https://bugs.webkit.org/show_bug.cgi?id=24551 + + [Qt] Reuse FontPlatformData for the same FontDescription. + This effectively prevents growing heap usage for loading every web page. + + * platform/graphics/qt/FontCacheQt.cpp: + (WebCore::qHash): Necessary for FontPlatformDataCache. + (WebCore::FontCache::getCachedFontPlatformData): Reuse the instance if + it exists, otherwise create a new one and insert it in the cache. + +2009-05-18 Balazs Kelemen <kelemen.balazs@stud.u-szeged.hu> + + Reviewed by Ariya Hidayat. + + https://bugs.webkit.org/show_bug.cgi?id=24551 + + [Qt] Fix the leak in FontFallbackList::fontDataAt() function. + When creating a new instance of SimpleFontData, put it in the font list + so that it can deleted later on. + + * platform/graphics/qt/FontFallbackListQt.cpp: + (WebCore::FontFallbackList::invalidate): + (WebCore::FontFallbackList::releaseFontData): + (WebCore::FontFallbackList::fontDataAt): + +2009-05-15 Ariya Hidayat <ariya.hidayat@nokia.com> + + Reviewed by Holger Freyther. + + [Qt] In the image decoder, remove the raw image data represented as QImage + once the image is converted to QPixmap and inserted in the pixmap cache. + This effectively reduces the heap usage when running on graphics system + other than raster (i.e the case where QImage != QPixmap). + + * platform/graphics/qt/ImageDecoderQt.cpp: + (WebCore::ImageDecoderQt::imageAtIndex): Nullified the image on purpose. + * platform/graphics/qt/ImageDecoderQt.h: Made m_imageList mutable. + +2009-05-15 Ariya Hidayat <ariya.hidayat@nokia.com> + + Reviewed by Holger Freyther. + + [Qt] Refactor alpha channel detection the image decoder. + Sets the boolean flag as soon as the image is being read. + + * platform/graphics/qt/ImageDecoderQt.cpp: + (WebCore::ImageDecoderQt::ImageDecoderQt): Initialized m_hasAlphaChannel. + (WebCore::ImageDecoderQt::setData): Set the flag when appropriate. + (WebCore::ImageDecoderQt::supportsAlpha): Simplified. + (WebCore::ImageDecoderQt::reset): Resetted the flag. + * platform/graphics/qt/ImageDecoderQt.h: Added m_hasAlphaChannel. + +2009-05-13 Ariya Hidayat <ariya.hidayat@nokia.com> + + Reviewed by Sam Weinig. + + [Qt] Fix "lighther" composition mode. + QPainter::CompositionMode_Plus is the right match. + + * platform/graphics/qt/GraphicsContextQt.cpp: + (WebCore::toQtCompositionMode): + +2009-04-29 Ariya Hidayat <ariya.hidayat@nokia.com> + + Reviewed by Simon Fraser. + + [Qt] Initialize GraphicsContext's and ImageBuffer's QPainter to match + the default values of canvas attributes. + + * platform/graphics/qt/ImageBufferQt.cpp: + (WebCore::ImageBufferData::ImageBufferData): + +2009-04-27 Ariya Hidayat <ariya.hidayat@nokia.com> + + Reviewed by Tor Arne Vestbø. + + https://bugs.webkit.org/show_bug.cgi?id=18475 + + [Qt] Widget painting should follow the layout direction (LTR, RTL) + of the element style, not the application layout direction. + + * platform/qt/RenderThemeQt.cpp: + (WebCore::RenderThemeQt::applyTheme): + 2009-03-13 Adam Bergkvist <adam.bergkvist@ericsson.com> Reviewed by Alexey Proskuryakov. diff --git a/src/3rdparty/webkit/WebCore/bridge/qt/qt_instance.cpp b/src/3rdparty/webkit/WebCore/bridge/qt/qt_instance.cpp index 4b94a94..26323e8 100644 --- a/src/3rdparty/webkit/WebCore/bridge/qt/qt_instance.cpp +++ b/src/3rdparty/webkit/WebCore/bridge/qt/qt_instance.cpp @@ -337,7 +337,7 @@ JSValuePtr QtField::valueFromInstance(ExecState* exec, const Instance* inst) con return ret; } else { - QString msg = QString(QLatin1String("cannot access member `%1' of deleted QObject")).arg(QLatin1String(name())); + QString msg = QString::fromLatin1("cannot access member `%1' of deleted QObject").arg(QLatin1String(name())); return throwError(exec, GeneralError, msg.toLatin1().constData()); } } @@ -362,7 +362,7 @@ void QtField::setValueToInstance(ExecState* exec, const Instance* inst, JSValueP } else if (m_type == DynamicProperty) obj->setProperty(m_dynamicProperty.constData(), val); } else { - QString msg = QString(QLatin1String("cannot access member `%1' of deleted QObject")).arg(QLatin1String(name())); + QString msg = QString::fromLatin1("cannot access member `%1' of deleted QObject").arg(QLatin1String(name())); throwError(exec, GeneralError, msg.toLatin1().constData()); } } diff --git a/src/3rdparty/webkit/WebCore/bridge/qt/qt_runtime.cpp b/src/3rdparty/webkit/WebCore/bridge/qt/qt_runtime.cpp index c7ba6c2..5a73dc7 100644 --- a/src/3rdparty/webkit/WebCore/bridge/qt/qt_runtime.cpp +++ b/src/3rdparty/webkit/WebCore/bridge/qt/qt_runtime.cpp @@ -1515,7 +1515,7 @@ JSValuePtr QtRuntimeConnectionMethod::call(ExecState* exec, JSObject* functionOb bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset()); if (!ok) { delete conn; - QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()")) + QString msg = QString::fromLatin1("QtMetaMethod.connect: failed to connect to %1::%2()") .arg(QLatin1String(sender->metaObject()->className())) .arg(QLatin1String(d->m_signature)); return throwError(exec, GeneralError, msg.toLatin1().constData()); @@ -1541,14 +1541,14 @@ JSValuePtr QtRuntimeConnectionMethod::call(ExecState* exec, JSObject* functionOb } if (!ret) { - QString msg = QString(QLatin1String("QtMetaMethod.disconnect: failed to disconnect from %1::%2()")) + QString msg = QString::fromLatin1("QtMetaMethod.disconnect: failed to disconnect from %1::%2()") .arg(QLatin1String(sender->metaObject()->className())) .arg(QLatin1String(d->m_signature)); return throwError(exec, GeneralError, msg.toLatin1().constData()); } } } else { - QString msg = QString(QLatin1String("QtMetaMethod.%1: %2::%3() is not a signal")) + QString msg = QString::fromLatin1("QtMetaMethod.%1: %2::%3() is not a signal") .arg(QLatin1String(d->m_isConnect ? "connect": "disconnect")) .arg(QLatin1String(sender->metaObject()->className())) .arg(QLatin1String(d->m_signature)); diff --git a/src/3rdparty/webkit/WebCore/dom/XMLTokenizerQt.cpp b/src/3rdparty/webkit/WebCore/dom/XMLTokenizerQt.cpp index 2050a70..39ccefe 100644 --- a/src/3rdparty/webkit/WebCore/dom/XMLTokenizerQt.cpp +++ b/src/3rdparty/webkit/WebCore/dom/XMLTokenizerQt.cpp @@ -357,7 +357,7 @@ HashMap<String, String> parseAttributes(const String& string, bool& attrsOK) state.gotAttributes = false; QXmlStreamReader stream; - QString dummy = QString(QLatin1String("<?xml version=\"1.0\"?><attrs %1 />")).arg(string); + QString dummy = QString::fromLatin1("<?xml version=\"1.0\"?><attrs %1 />").arg(string); stream.addData(dummy); while (!stream.atEnd()) { stream.readNext(); diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp index 8a31861..5d1f147 100644 --- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -26,6 +26,9 @@ #include "FontDescription.h" #include "FontPlatformData.h" #include "Font.h" +#include "StringHash.h" + +#include <QHash> namespace WebCore { @@ -33,9 +36,31 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne { } +typedef QHash<FontDescription, FontPlatformData*> FontPlatformDataCache; + +// using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this. +static FontPlatformDataCache* gFontPlatformDataCache; + +uint qHash(const FontDescription& key) +{ + uint value = CaseFoldingHash::hash(key.family().family()); + value ^= key.computedPixelSize(); + value ^= static_cast<int>(key.weight()); + return value; +} + FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString& family, bool checkingAlternateName) { - return new FontPlatformData(description); + if (!gFontPlatformDataCache) + gFontPlatformDataCache = new FontPlatformDataCache; + + FontPlatformData* fontData = gFontPlatformDataCache->value(description, 0); + if (!fontData) { + fontData = new FontPlatformData(description); + gFontPlatformDataCache->insert(description, fontData); + } + + return fontData; } SimpleFontData* FontCache::getCachedFontData(const FontPlatformData*) diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontFallbackListQt.cpp index 22ae205..50627b7 100644 --- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontFallbackListQt.cpp +++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontFallbackListQt.cpp @@ -42,8 +42,6 @@ FontFallbackList::FontFallbackList() void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSelector) { - releaseFontData(); - m_fontList.clear(); m_familyIndex = 0; m_pitch = UnknownPitch; m_loadingCustomFonts = false; @@ -53,6 +51,9 @@ void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSel void FontFallbackList::releaseFontData() { + if (m_fontList.size()) + delete m_fontList[0].first; + m_fontList.clear(); } void FontFallbackList::determinePitch(const WebCore::Font* font) const @@ -90,7 +91,12 @@ const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigne family = family->next(); } - return new SimpleFontData(FontPlatformData(description), _font->wordSpacing(), _font->letterSpacing()); + if (m_fontList.size()) + return m_fontList[0].first; + + const FontData* result = new SimpleFontData(FontPlatformData(description), _font->wordSpacing(), _font->letterSpacing()); + m_fontList.append(pair<const FontData*, bool>(result, result->isCustomFont())); + return result; } const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* font, const UChar*, int) const diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 6c90ea3..490b54b 100644 --- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -98,7 +98,7 @@ static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op case CompositeHighlight: return QPainter::CompositionMode_SourceOver; case CompositePlusLighter: - return QPainter::CompositionMode_SourceOver; + return QPainter::CompositionMode_Plus; } return QPainter::CompositionMode_SourceOver; diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageBufferQt.cpp index 29a02d4..333269e 100644 --- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -47,7 +47,24 @@ ImageBufferData::ImageBufferData(const IntSize& size) : m_pixmap(size) { m_pixmap.fill(QColor(Qt::transparent)); - m_painter.set(new QPainter(&m_pixmap)); + + QPainter* painter = new QPainter(&m_pixmap); + m_painter.set(painter); + + // Since ImageBuffer is used mainly for Canvas, explicitly initialize + // its painter's pen and brush with the corresponding canvas defaults + // NOTE: keep in sync with CanvasRenderingContext2D::State + QPen pen = painter->pen(); + pen.setColor(Qt::black); + pen.setWidth(1); + pen.setCapStyle(Qt::FlatCap); + pen.setJoinStyle(Qt::MiterJoin); + pen.setMiterLimit(10); + painter->setPen(pen); + QBrush brush = painter->brush(); + brush.setColor(Qt::black); + painter->setBrush(brush); + painter->setCompositionMode(QPainter::CompositionMode_SourceOver); } ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success) diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 394c7a7..cd32428 100644 --- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -197,7 +197,8 @@ ImageDecoderQt* ImageDecoderQt::create(const SharedBuffer& data) } ImageDecoderQt::ImageDecoderQt(const QString &imageFormat) - : m_imageFormat(imageFormat) + : m_hasAlphaChannel(false) + , m_imageFormat(imageFormat) { } @@ -212,6 +213,7 @@ bool ImageDecoderQt::hasFirstImageHeader() const void ImageDecoderQt::reset() { + m_hasAlphaChannel = false; m_failed = false; m_imageList.clear(); m_pixmapCache.clear(); @@ -230,6 +232,9 @@ void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived) const ReadContext::ReadResult readResult = readContext.read(allDataReceived); + if (hasFirstImageHeader()) + m_hasAlphaChannel = m_imageList[0].m_image.hasAlphaChannel(); + if (debugImageDecoderQt) qDebug() << " read returns " << readResult; @@ -280,7 +285,7 @@ int ImageDecoderQt::repetitionCount() const bool ImageDecoderQt::supportsAlpha() const { - return hasFirstImageHeader() && m_imageList[0].m_image.hasAlphaChannel(); + return m_hasAlphaChannel; } int ImageDecoderQt::duration(size_t index) const @@ -314,6 +319,10 @@ QPixmap* ImageDecoderQt::imageAtIndex(size_t index) const if (!m_pixmapCache.contains(index)) { m_pixmapCache.insert(index, QPixmap::fromImage(m_imageList[index].m_image)); + + // store null image since the converted pixmap is already in pixmap cache + Q_ASSERT(m_imageList[index].m_imageState == ImageComplete); + m_imageList[index].m_image = QImage(); } return &m_pixmapCache[index]; } diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageDecoderQt.h b/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageDecoderQt.h index a2eb6aa..b8c3edd 100644 --- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageDecoderQt.h +++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -81,8 +81,9 @@ private: int m_duration; }; + bool m_hasAlphaChannel; typedef QList<ImageData> ImageList; - ImageList m_imageList; + mutable ImageList m_imageList; mutable QHash<int, QPixmap> m_pixmapCache; int m_loopCount; QString m_imageFormat; diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/PathQt.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/qt/PathQt.cpp index e68be2b..bff9edb 100644 --- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/PathQt.cpp +++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/PathQt.cpp @@ -286,10 +286,10 @@ String Path::debugString() const switch (cur.type) { case QPainterPath::MoveToElement: - ret += QString(QLatin1String("M %1 %2")).arg(cur.x).arg(cur.y); + ret += QString::fromLatin1("M %1 %2").arg(cur.x).arg(cur.y); break; case QPainterPath::LineToElement: - ret += QString(QLatin1String("L %1 %2")).arg(cur.x).arg(cur.y); + ret += QString::fromLatin1("L %1 %2").arg(cur.x).arg(cur.y); break; case QPainterPath::CurveToElement: { @@ -299,7 +299,7 @@ String Path::debugString() const Q_ASSERT(c1.type == QPainterPath::CurveToDataElement); Q_ASSERT(c2.type == QPainterPath::CurveToDataElement); - ret += QString(QLatin1String("C %1 %2 %3 %4 %5 %6")).arg(cur.x).arg(cur.y).arg(c1.x).arg(c1.y).arg(c2.x).arg(c2.y); + ret += QString::fromLatin1("C %1 %2 %3 %4 %5 %6").arg(cur.x).arg(cur.y).arg(c1.x).arg(c1.y).arg(c2.x).arg(c2.y); i += 2; break; diff --git a/src/3rdparty/webkit/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/src/3rdparty/webkit/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 2c730a6..3e9b239 100644 --- a/src/3rdparty/webkit/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/src/3rdparty/webkit/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -174,6 +174,7 @@ void QNetworkReplyHandler::abort() if (m_reply) { QNetworkReply* reply = release(); reply->abort(); + reply->deleteLater(); deleteLater(); } } diff --git a/src/3rdparty/webkit/WebCore/platform/qt/RenderThemeQt.cpp b/src/3rdparty/webkit/WebCore/platform/qt/RenderThemeQt.cpp index a9da76b..02d17ed 100644 --- a/src/3rdparty/webkit/WebCore/platform/qt/RenderThemeQt.cpp +++ b/src/3rdparty/webkit/WebCore/platform/qt/RenderThemeQt.cpp @@ -737,6 +737,10 @@ ControlPart RenderThemeQt::applyTheme(QStyleOption& option, RenderObject* o) con if (isHovered(o)) option.state |= QStyle::State_MouseOver; + option.direction = Qt::LeftToRight; + if (o->style() && o->style()->direction() == WebCore::RTL) + option.direction = Qt::RightToLeft; + ControlPart result = o->style()->appearance(); switch (result) { diff --git a/src/3rdparty/webkit/WebCore/plugins/qt/PluginPackageQt.cpp b/src/3rdparty/webkit/WebCore/plugins/qt/PluginPackageQt.cpp index 4387813..13f5394 100644 --- a/src/3rdparty/webkit/WebCore/plugins/qt/PluginPackageQt.cpp +++ b/src/3rdparty/webkit/WebCore/plugins/qt/PluginPackageQt.cpp @@ -151,8 +151,8 @@ bool PluginPackage::load() m_browserFuncs.getproperty = _NPN_GetProperty; m_browserFuncs.setproperty = _NPN_SetProperty; m_browserFuncs.removeproperty = _NPN_RemoveProperty; - m_browserFuncs.hasproperty = _NPN_HasMethod; - m_browserFuncs.hasmethod = _NPN_HasProperty; + m_browserFuncs.hasproperty = _NPN_HasProperty; + m_browserFuncs.hasmethod = _NPN_HasMethod; m_browserFuncs.setexception = _NPN_SetException; m_browserFuncs.enumerate = _NPN_Enumerate; m_browserFuncs.construct = _NPN_Construct; diff --git a/src/3rdparty/webkit/WebCore/plugins/qt/PluginViewQt.cpp b/src/3rdparty/webkit/WebCore/plugins/qt/PluginViewQt.cpp index c8dd0e5..e856f92 100644 --- a/src/3rdparty/webkit/WebCore/plugins/qt/PluginViewQt.cpp +++ b/src/3rdparty/webkit/WebCore/plugins/qt/PluginViewQt.cpp @@ -58,6 +58,7 @@ #include "MouseEvent.h" #include "Page.h" #include "PlatformMouseEvent.h" +#include "PluginMainThreadScheduler.h" #include "RenderLayer.h" #include "Settings.h" @@ -112,7 +113,9 @@ void PluginView::show() if (isParentVisible() && platformPluginWidget()) platformPluginWidget()->setVisible(true); - Widget::show(); + // do not call parent impl. here as it will set the platformWidget + // (same as platformPluginWidget in the Qt port) to visible, even + // when parent isn't visible. } void PluginView::hide() @@ -122,7 +125,9 @@ void PluginView::hide() if (isParentVisible() && platformPluginWidget()) platformPluginWidget()->setVisible(false); - Widget::hide(); + // do not call parent impl. here as it will set the platformWidget + // (same as platformPluginWidget in the Qt port) to invisible, even + // when parent isn't visible. } void PluginView::paint(GraphicsContext* context, const IntRect& rect) @@ -225,6 +230,8 @@ void PluginView::stop() JSC::JSLock::DropAllLocks dropAllLocks(false); + PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance); + // Clear the window m_npWindow.window = 0; if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) { diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebframe.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebframe.cpp index 5dc6363..e565476 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebframe.cpp +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebframe.cpp @@ -268,7 +268,7 @@ void QWebFrame::addToJavaScriptWindowObject(const QString &name, QObject *object } /*! - Returns the frame's content, converted to HTML. + Returns the frame's content as HTML, enclosed in HTML and BODY tags. \sa setHtml(), toPlainText() */ @@ -280,7 +280,8 @@ QString QWebFrame::toHtml() const } /*! - Returns the content of this frame converted to plain text. + Returns the content of this frame converted to plain text, completely + stripped of all HTML formatting. \sa toHtml() */ diff --git a/src/3rdparty/webkit/WebKit/qt/ChangeLog b/src/3rdparty/webkit/WebKit/qt/ChangeLog index c3bd633..d9f925a 100644 --- a/src/3rdparty/webkit/WebKit/qt/ChangeLog +++ b/src/3rdparty/webkit/WebKit/qt/ChangeLog @@ -1,3 +1,28 @@ +2009-05-19 Kenneth Rohde Christiansen <kenneth.christiansen@openbossa.org> + + Reviewed by Simon Hausmann. + + Fix a plugin bug in the WebKit code, similar to the one in WebCore. + + The problem is when a non visible QtPluginWidget would show it self + in a sibling frame. The problem was due to our clipping. In Qt, + if setMask is set with an empty QRegion, no clipping will + be performed, so in that case we hide the PluginContainer + + * WebCoreSupport/FrameLoaderClientQt.cpp: + (WebCore::): + +2009-03-27 Erik L. Bunce <elbunce@xendom.com> + + Reviewed by Simon Hausmann. + + https://bugs.webkit.org/show_bug.cgi?id=24746 + + Improved selection tests. + + * tests/qwebpage/tst_qwebpage.cpp: + (tst_QWebPage::textSelection): + 2009-04-24 Simon Hausmann <simon.hausmann@nokia.com> Rubber-stamped by Ariya Hidayat. diff --git a/src/3rdparty/webkit/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp b/src/3rdparty/webkit/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp index c421d42..a2b33c0 100644 --- a/src/3rdparty/webkit/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp +++ b/src/3rdparty/webkit/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp @@ -1058,7 +1058,13 @@ public: IntRect clipRect(static_cast<FrameView*>(parentScrollView)->windowClipRect()); clipRect.move(-windowRect.x(), -windowRect.y()); clipRect.intersect(platformWidget()->rect()); - platformWidget()->setMask(QRegion(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height())); + + QRegion clipRegion = QRegion(clipRect); + platformWidget()->setMask(clipRegion); + + // if setMask is set with an empty QRegion, no clipping will + // be performed, so in that case we hide the platformWidget + platformWidget()->setVisible(!clipRegion.isEmpty()); } }; diff --git a/src/3rdparty/webkit/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp b/src/3rdparty/webkit/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp index fe74fac..620aa31 100644 --- a/src/3rdparty/webkit/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp +++ b/src/3rdparty/webkit/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp @@ -872,14 +872,6 @@ void tst_QWebPage::textSelection() "<p>May the source<br/>be with you!</p></body></html>"); page->mainFrame()->setHtml(content); - // this will select the first paragraph - QString script = "var range = document.createRange(); " \ - "var node = document.getElementById(\"one\"); " \ - "range.selectNode(node); " \ - "getSelection().addRange(range);"; - page->mainFrame()->evaluateJavaScript(script); - QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); - // these actions must exist QVERIFY(page->action(QWebPage::SelectAll) != 0); QVERIFY(page->action(QWebPage::SelectNextChar) != 0); @@ -895,7 +887,8 @@ void tst_QWebPage::textSelection() QVERIFY(page->action(QWebPage::SelectStartOfDocument) != 0); QVERIFY(page->action(QWebPage::SelectEndOfDocument) != 0); - // right now they are disabled because contentEditable is false + // right now they are disabled because contentEditable is false and + // there isn't an existing selection to modify QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), false); QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), false); QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), false); @@ -912,11 +905,37 @@ void tst_QWebPage::textSelection() // ..but SelectAll is awalys enabled QCOMPARE(page->action(QWebPage::SelectAll)->isEnabled(), true); + // this will select the first paragraph + QString selectScript = "var range = document.createRange(); " \ + "var node = document.getElementById(\"one\"); " \ + "range.selectNode(node); " \ + "getSelection().addRange(range);"; + page->mainFrame()->evaluateJavaScript(selectScript); + QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); + + // here the actions are enabled after a selection has been created + QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), true); + QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), true); + // make it editable before navigating the cursor page->setContentEditable(true); + // cursor will be before the word "The", this makes sure there is a charet + page->triggerAction(QWebPage::MoveToStartOfDocument); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 0); + // here the actions are enabled after contentEditable is true - QCOMPARE(page->action(QWebPage::SelectAll)->isEnabled(), true); QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), true); QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), true); QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), true); diff --git a/src/activeqt/container/qaxbase.cpp b/src/activeqt/container/qaxbase.cpp index 44c3e9e..e1ffb81 100644 --- a/src/activeqt/container/qaxbase.cpp +++ b/src/activeqt/container/qaxbase.cpp @@ -421,7 +421,7 @@ public: argv[p + 1] = varp + p + 1; } else { argv[p + 1] = const_cast<void*>(varp[p + 1].constData()); - if (ptype.endsWith("*")) { + if (ptype.endsWith('*')) { argv_pointer[p + 1] = argv[p + 1]; argv[p + 1] = argv_pointer + p + 1; } @@ -648,7 +648,7 @@ QByteArray QAxEventSink::findProperty(DISPID dispID) int index = mo->indexOfProperty(propname); const QMetaProperty prop = mo->property(index); propsignal += prop.typeName(); - propsignal += ")"; + propsignal += ')'; addProperty(dispID, propname, propsignal); return propname; @@ -1661,7 +1661,7 @@ private: void addProperty(const QByteArray &type, const QByteArray &name, uint flags) { QByteArray propertyType(type); - if (propertyType.endsWith("&")) + if (propertyType.endsWith('&')) propertyType.chop(1); Property &prop = property_list[name]; @@ -2046,11 +2046,11 @@ QByteArray MetaObjectGenerator::guessTypes(const TYPEDESC &tdesc, ITypeInfo *inf case VT_INT: case VT_UINT: case VT_CY: - str += "&"; + str += '&'; break; case VT_PTR: if (str == "QFont" || str == "QPixmap") { - str += "&"; + str += '&'; break; } else if (str == "void*") { str = "void **"; @@ -2059,19 +2059,19 @@ QByteArray MetaObjectGenerator::guessTypes(const TYPEDESC &tdesc, ITypeInfo *inf // FALLTHROUGH default: if (str == "QColor") - str += "&"; + str += '&'; else if (str == "QDateTime") - str += "&"; + str += '&'; else if (str == "QVariantList") - str += "&"; + str += '&'; else if (str == "QByteArray") - str += "&"; + str += '&'; else if (str == "QStringList") - str += "&"; + str += '&'; else if (!str.isEmpty() && hasEnum(str)) - str += "&"; + str += '&'; else if (!str.isEmpty() && str != "QFont" && str != "QPixmap" && str != "QVariant") - str += "*"; + str += '*'; } break; case VT_SAFEARRAY: @@ -2089,7 +2089,7 @@ QByteArray MetaObjectGenerator::guessTypes(const TYPEDESC &tdesc, ITypeInfo *inf default: str = guessTypes(tdesc.lpadesc->tdescElem, info, function); if (!str.isEmpty()) - str = "QList<" + str + ">"; + str = "QList<" + str + '>'; break; } break; @@ -2097,7 +2097,7 @@ QByteArray MetaObjectGenerator::guessTypes(const TYPEDESC &tdesc, ITypeInfo *inf str = guessTypes(tdesc.lpadesc->tdescElem, info, function); if (!str.isEmpty()) { for (int index = 0; index < tdesc.lpadesc->cDims; ++index) - str += "[" + QByteArray::number((int)tdesc.lpadesc->rgbounds[index].cElements) + "]"; + str += '[' + QByteArray::number((int)tdesc.lpadesc->rgbounds[index].cElements) + ']'; } break; case VT_USERDEFINED: @@ -2114,7 +2114,7 @@ QByteArray MetaObjectGenerator::guessTypes(const TYPEDESC &tdesc, ITypeInfo *inf } if (tdesc.vt & VT_BYREF) - str += "&"; + str += '&'; str.replace("&*", "**"); return str; @@ -2141,7 +2141,7 @@ void MetaObjectGenerator::readClassInfo() if (d->useClassInfo && !hasClassInfo("CoClass")) { QString coClassIDstr = iidnames.value(QLatin1String("/CLSID/") + coClassID + QLatin1String("/Default"), coClassID).toString(); addClassInfo("CoClass", coClassIDstr.isEmpty() ? coClassID.toLatin1() : coClassIDstr.toLatin1()); - QByteArray version = QByteArray::number(typeattr->wMajorVerNum) + "." + QByteArray::number(typeattr->wMinorVerNum); + QByteArray version = QByteArray::number(typeattr->wMajorVerNum) + '.' + QByteArray::number(typeattr->wMinorVerNum); if (version != "0.0") addClassInfo("Version", version); } @@ -2174,7 +2174,7 @@ void MetaObjectGenerator::readClassInfo() while (tlfile.isEmpty() && vit != versions.end()) { QString version = *vit; ++vit; - tlfile = controls.value(QLatin1String("/") + version + QLatin1String("/0/win32/.")).toString(); + tlfile = controls.value(QLatin1Char('/') + version + QLatin1String("/0/win32/.")).toString(); } controls.endGroup(); } else { @@ -2347,7 +2347,7 @@ void MetaObjectGenerator::addChangedSignal(const QByteArray &function, const QBy // generate changed signal QByteArray signalName(function); signalName += "Changed"; - QByteArray signalProto = signalName + "(" + replaceType(type) + ")"; + QByteArray signalProto = signalName + '(' + replaceType(type) + ')'; if (!hasSignal(signalProto)) addSignal(signalProto, function); if (eventSink) @@ -2364,7 +2364,7 @@ void MetaObjectGenerator::addSetterSlot(const QByteArray &property) set = "set"; prototype[0] = toupper(prototype[0]); } - prototype = set + prototype + "(" + propertyType(property) + ")"; + prototype = set + prototype + '(' + propertyType(property) + ')'; if (!hasSlot(prototype)) addSlot(0, prototype, property); } @@ -2381,7 +2381,7 @@ QByteArray MetaObjectGenerator::createPrototype(FUNCDESC *funcdesc, ITypeInfo *t type = guessTypes(funcdesc->lprgelemdescParam->tdesc, typeinfo, function); } - prototype = function + "("; + prototype = function + '('; if (funcdesc->invkind == INVOKE_FUNC && type == hresult) type = 0; @@ -2395,7 +2395,7 @@ QByteArray MetaObjectGenerator::createPrototype(FUNCDESC *funcdesc, ITypeInfo *t QByteArray ptype = guessTypes(tdesc, typeinfo, function); if (pdesc.wParamFlags & PARAMFLAG_FRETVAL) { - if (ptype.endsWith("&")) { + if (ptype.endsWith('&')) { ptype.truncate(ptype.length() - 1); } else if (ptype.endsWith("**")) { ptype.truncate(ptype.length() - 1); @@ -2403,8 +2403,8 @@ QByteArray MetaObjectGenerator::createPrototype(FUNCDESC *funcdesc, ITypeInfo *t type = ptype; } else { prototype += ptype; - if (pdesc.wParamFlags & PARAMFLAG_FOUT && !ptype.endsWith("&") && !ptype.endsWith("**")) - prototype += "&"; + if (pdesc.wParamFlags & PARAMFLAG_FOUT && !ptype.endsWith('&') && !ptype.endsWith("**")) + prototype += '&'; if (optional || pdesc.wParamFlags & PARAMFLAG_FOPT) paramName += "=0"; else if (pdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) { @@ -2414,22 +2414,22 @@ QByteArray MetaObjectGenerator::createPrototype(FUNCDESC *funcdesc, ITypeInfo *t parameters << paramName; } if (p < funcdesc->cParams && !(pdesc.wParamFlags & PARAMFLAG_FRETVAL)) - prototype += ","; + prototype += ','; } if (!prototype.isEmpty()) { - if (prototype.right(1) == ",") { + if (prototype.endsWith(',')) { if (funcdesc->invkind == INVOKE_PROPERTYPUT && p == funcdesc->cParams) { TYPEDESC tdesc = funcdesc->lprgelemdescParam[p-1].tdesc; QByteArray ptype = guessTypes(tdesc, typeinfo, function); prototype += ptype; - prototype += ")"; + prototype += ')'; parameters << "rhs"; } else { prototype[prototype.length()-1] = ')'; } } else { - prototype += ")"; + prototype += ')'; } } @@ -2577,11 +2577,11 @@ void MetaObjectGenerator::readFuncsInfo(ITypeInfo *typeinfo, ushort nFuncs) if (defargs) { parameters.takeLast(); - int lastParam = prototype.lastIndexOf(","); + int lastParam = prototype.lastIndexOf(','); if (lastParam == -1) - lastParam = prototype.indexOf("(") + 1; + lastParam = prototype.indexOf('(') + 1; prototype.truncate(lastParam); - prototype += ")"; + prototype += ')'; } } while (defargs); } @@ -2597,8 +2597,8 @@ void MetaObjectGenerator::readFuncsInfo(ITypeInfo *typeinfo, ushort nFuncs) QString strDocu = QString::fromUtf16((const ushort*)bstrDocu); SysFreeString(bstrDocu); if (!!strDocu) - desc += "[" + strDocu + "]"; - desc += "\n"; + desc += '[' + strDocu + ']'; + desc += '\n'; #endif typeinfo->ReleaseFuncDesc(funcdesc); } @@ -2680,8 +2680,8 @@ void MetaObjectGenerator::readVarsInfo(ITypeInfo *typeinfo, ushort nVars) QString strDocu = QString::fromUtf16((const ushort*)bstrDocu); SysFreeString(bstrDocu); if (!!strDocu) - desc += "[" + strDocu + "]"; - desc += "\n"; + desc += '[' + strDocu + ']'; + desc += '\n'; #endif typeinfo->ReleaseVarDesc(vardesc); } @@ -2827,8 +2827,8 @@ void MetaObjectGenerator::readEventInterface(ITypeInfo *eventinfo, IConnectionPo QString strDocu = QString::fromUtf16((const ushort*)bstrDocu); SysFreeString(bstrDocu); if (!!strDocu) - desc += "[" + strDocu + "]"; - desc += "\n"; + desc += '[' + strDocu + ']'; + desc += '\n'; #endif eventinfo->ReleaseFuncDesc(funcdesc); } @@ -4398,8 +4398,8 @@ QVariant QAxBase::asVariant() const cn = cn.mid(cn.lastIndexOf(':') + 1); QObject *object = qObject(); if (QMetaType::type(cn)) - qvar = QVariant(qRegisterMetaType<QObject*>(cn + "*"), &object); -// qVariantSetValue(qvar, qObject(), cn + "*"); + qvar = QVariant(qRegisterMetaType<QObject*>(cn + '*'), &object); +// qVariantSetValue(qvar, qObject(), cn + '*'); } return qvar; diff --git a/src/activeqt/container/qaxdump.cpp b/src/activeqt/container/qaxdump.cpp index 62ef0a4..c3218a9 100644 --- a/src/activeqt/container/qaxdump.cpp +++ b/src/activeqt/container/qaxdump.cpp @@ -94,14 +94,14 @@ static QByteArray namedPrototype(const QList<QByteArray> ¶meterTypes, const prototype += type; if (p < parameterNames.count()) - prototype += " " + parameterNames.at(p); + prototype += ' ' + parameterNames.at(p); if (numDefArgs >= parameterTypes.count() - p) prototype += " = 0"; if (p < parameterTypes.count() - 1) prototype += ", "; } - prototype += ")"; + prototype += ')'; return prototype; } @@ -196,8 +196,8 @@ QString qax_generateDocumentation(QAxBase *that) prototype = namedPrototype(slot.parameterTypes(), slot.parameterNames()); QString detail = QString::fromLatin1("<h3><a name=") + QString::fromLatin1(name.constData()) + QLatin1String("></a>") + - QString::fromLatin1(returntype.constData()) + QLatin1String(" ") + - QString::fromLatin1(name.constData()) + QLatin1String(" ") + + QLatin1String(returntype.constData()) + QLatin1Char(' ') + + QLatin1String(name.constData()) + QLatin1Char(' ') + QString::fromLatin1(prototype.constData()) + QLatin1String("<tt> [slot]</tt></h3>\n"); prototype = namedPrototype(slot.parameterTypes(), QList<QByteArray>()); detail += docuFromName(typeInfo, QString::fromLatin1(name.constData())); @@ -220,14 +220,14 @@ QString qax_generateDocumentation(QAxBase *that) returntype = "QAxObject *"; } if (returntype != "void") - detail += QString::fromLatin1(returntype.constData()) + QLatin1String(" result = "); - detail += QLatin1String("object->") + QString::fromLatin1(functionToCall.constData()) + - QLatin1String("(\"" + name + prototype + "\""); + detail += QLatin1String(returntype.constData()) + QLatin1String(" result = "); + detail += QLatin1String("object->") + QLatin1String(functionToCall.constData()) + + QLatin1String("(\"" + name + prototype + '\"'); if (hasParams) detail += QLatin1String(", params"); - detail += QLatin1String(")"); + detail += QLatin1Char(')'); if (returntype != "void" && returntype != "QAxObject *" && returntype != "QVariant") - detail += QLatin1String(".") + QString::fromLatin1(toType(returntype)); + detail += QLatin1Char('.') + QLatin1String(toType(returntype)); detail += QLatin1String(";</pre>\n"); } else { detail += QLatin1String("<p>This function has parameters of unsupported types and cannot be called directly."); @@ -262,9 +262,9 @@ QString qax_generateDocumentation(QAxBase *that) QByteArray name = signature.left(signature.indexOf('(')); stream << "<li>void <a href=\"#" << name << "\"><b>" << name << "</b></a>" << prototype << ";</li>" << endl; - QString detail = QLatin1String("<h3><a name=") + QString::fromLatin1(name.constData()) + QLatin1String("></a>void ") + - QString::fromLatin1(name.constData()) + QLatin1String(" ") + - QString::fromLatin1(prototype.constData()) + QLatin1String("<tt> [signal]</tt></h3>\n"); + QString detail = QLatin1String("<h3><a name=") + QLatin1String(name.constData()) + QLatin1String("></a>void ") + + QLatin1String(name.constData()) + QLatin1Char(' ') + + QLatin1String(prototype.constData()) + QLatin1String("<tt> [signal]</tt></h3>\n"); if (typeLib) { interCount = 0; do { @@ -311,8 +311,8 @@ QString qax_generateDocumentation(QAxBase *that) stream << "<li>" << type << " <a href=\"#" << name << "\"><b>" << name << "</b></a>;</li>" << endl; QString detail = QLatin1String("<h3><a name=") + QString::fromLatin1(name.constData()) + QLatin1String("></a>") + - QString::fromLatin1(type.constData()) + - QLatin1String(" ") + QString::fromLatin1(name.constData()) + QLatin1String("</h3>\n"); + QLatin1String(type.constData()) + + QLatin1Char(' ') + QLatin1String(name.constData()) + QLatin1String("</h3>\n"); detail += docuFromName(typeInfo, QString::fromLatin1(name)); QVariant::Type vartype = QVariant::nameToType(type); if (!prop.isReadable()) @@ -326,14 +326,14 @@ QString qax_generateDocumentation(QAxBase *that) if (prop.isEnumType()) detail += QLatin1String("\tint val = "); else - detail += QLatin1String("\t") + QString::fromLatin1(type.constData()) + QLatin1String(" val = "); - detail += QLatin1String("object->property(\"") + QString::fromLatin1(name.constData()) + - QLatin1String("\").") + QString::fromLatin1(toType(type).constData()) + QLatin1String(";\n"); + detail += QLatin1Char('\t') + QLatin1String(type.constData()) + QLatin1String(" val = "); + detail += QLatin1String("object->property(\"") + QLatin1String(name.constData()) + + QLatin1String("\").") + QLatin1String(toType(type).constData()) + QLatin1String(";\n"); detail += QLatin1String("</pre>\n"); } else if (type == "IDispatch*" || type == "IUnknown*") { detail += QLatin1String("<p>Get the subobject using querySubObject:<pre>\n"); - detail += QLatin1String("\tQAxObject *") + QString::fromLatin1(name.constData()) + - QLatin1String(" = object->querySubObject(\"") + QString::fromLatin1(name.constData()) + QLatin1String("\");\n"); + detail += QLatin1String("\tQAxObject *") + QLatin1String(name.constData()) + + QLatin1String(" = object->querySubObject(\"") + QLatin1String(name.constData()) + QLatin1String("\");\n"); detail += QLatin1String("</pre>\n"); } else { detail += QLatin1String("<p>This property is of an unsupported type.\n"); diff --git a/src/activeqt/container/qaxscript.cpp b/src/activeqt/container/qaxscript.cpp index c69fea0..8f8186a 100644 --- a/src/activeqt/container/qaxscript.cpp +++ b/src/activeqt/container/qaxscript.cpp @@ -1203,9 +1203,9 @@ QString QAxScriptManager::scriptFileFilter() continue; allFiles += QLatin1String(" *") + engine.extension; - specialFiles += QLatin1String(";;") + engine.name + QLatin1String(" Files (*") + engine.extension + QLatin1String(")"); + specialFiles += QLatin1String(";;") + engine.name + QLatin1String(" Files (*") + engine.extension + QLatin1Char(')'); } - allFiles += QLatin1String(")"); + allFiles += QLatin1Char(')'); return allFiles + specialFiles + QLatin1String(";;All Files (*.*)"); } diff --git a/src/activeqt/control/qaxserver.cpp b/src/activeqt/control/qaxserver.cpp index d919382..1771293 100644 --- a/src/activeqt/control/qaxserver.cpp +++ b/src/activeqt/control/qaxserver.cpp @@ -90,7 +90,7 @@ QAxFactory *qAxFactory() QStringList keys(qax_factory->featureList()); for (int i = 0; i < keys.count(); ++i) { QString key(keys.at(i)); - qRegisterMetaType((key + QLatin1String("*")).toLatin1(), (void**)0); + qRegisterMetaType((key + QLatin1Char('*')).toLatin1(), (void**)0); } } return qax_factory; @@ -208,9 +208,9 @@ HRESULT UpdateRegistry(BOOL bRegister) { qAxIsServer = false; QString file = QString::fromLocal8Bit(qAxModuleFilename); - QString path = file.left(file.lastIndexOf(QLatin1String("\\"))+1); + QString path = file.left(file.lastIndexOf(QLatin1Char('\\'))+1); QString module = file.right(file.length() - path.length()); - module = module.left(module.lastIndexOf(QLatin1String("."))); + module = module.left(module.lastIndexOf(QLatin1Char('.'))); const QString appId = qAxFactory()->appID().toString().toUpper(); const QString libId = qAxFactory()->typeLibID().toString().toUpper(); @@ -226,7 +226,7 @@ HRESULT UpdateRegistry(BOOL bRegister) DWORD major = libAttr->wMajorVerNum; DWORD minor = libAttr->wMinorVerNum; - typeLibVersion = QString::number((uint)major) + QLatin1String(".") + QString::number((uint)minor); + typeLibVersion = QString::number((uint)major) + QLatin1Char('.') + QString::number((uint)minor); if (bRegister) RegisterTypeLib(qAxTypeLibrary, (TCHAR*)libFile.utf16(), 0); @@ -271,12 +271,12 @@ HRESULT UpdateRegistry(BOOL bRegister) className = qax_clean_type(className, mo); if (object) { // don't register subobject classes - QString classVersion = mo ? QString(QLatin1String(mo->classInfo(mo->indexOfClassInfo("Version")).value())) : QString(); + QString classVersion = mo ? QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("Version")).value()) : QString(); if (classVersion.isNull()) classVersion = QLatin1String("1.0"); bool insertable = mo && !qstricmp(mo->classInfo(mo->indexOfClassInfo("Insertable")).value(), "yes"); bool control = object->isWidgetType(); - const QString classMajorVersion = classVersion.left(classVersion.indexOf(QLatin1String("."))); + const QString classMajorVersion = classVersion.left(classVersion.indexOf(QLatin1Char('.'))); uint olemisc = OLEMISC_SETCLIENTSITEFIRST |OLEMISC_ACTIVATEWHENVISIBLE |OLEMISC_INSIDEOUT @@ -287,17 +287,17 @@ HRESULT UpdateRegistry(BOOL bRegister) else if (qFindChild<QMenuBar*>(object) && !qax_disable_inplaceframe) olemisc |= OLEMISC_WANTSTOMENUMERGE; - settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/."), className + QLatin1String(" Class")); - settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/CLSID/."), classId); + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/."), className + QLatin1String(" Class")); + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/CLSID/."), classId); if (insertable) - settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/Insertable/."), QVariant(QLatin1String(""))); + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/Insertable/."), QVariant(QLatin1String(""))); - settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/."), className + QLatin1String(" Class")); - settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/CLSID/."), classId); - settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/CurVer/."), module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion); + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/."), className + QLatin1String(" Class")); + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/CLSID/."), classId); + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/CurVer/."), module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion); settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/."), className + QLatin1String(" Class")); - if (file.right(3).toLower() == QLatin1String("exe")) + if (file.endsWith(QLatin1String("exe"), Qt::CaseInsensitive)) settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/AppID"), appId); if (control) settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Control/."), QVariant(QLatin1String(""))); @@ -307,15 +307,15 @@ HRESULT UpdateRegistry(BOOL bRegister) settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/InProcServer32/."), file); else settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/LocalServer32/."), - QLatin1String("\"") + file + QLatin1String("\" -activex")); + QLatin1Char('\"') + file + QLatin1String("\" -activex")); settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/MiscStatus/."), control ? QLatin1String("1") : QLatin1String("0")); settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/MiscStatus/1/."), QString::number(olemisc)); settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Programmable/."), QVariant(QLatin1String(""))); - settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/ToolboxBitmap32/."), QLatin1String("\"") + + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/ToolboxBitmap32/."), QLatin1Char('\"') + file + QLatin1String("\", 101")); settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/TypeLib/."), libId); settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Version/."), classVersion); - settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/VersionIndependentProgID/."), module + QLatin1String(".") + className); - settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/ProgID/."), module + QLatin1String(".") + className + QLatin1String(".") + classVersion.left(classVersion.indexOf(QLatin1Char('.')))); + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/VersionIndependentProgID/."), module + QLatin1Char('.') + className); + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/ProgID/."), module + QLatin1Char('.') + className + QLatin1Char('.') + classVersion.left(classVersion.indexOf(QLatin1Char('.')))); QString mime = QLatin1String(mo->classInfo(mo->indexOfClassInfo("MIME")).value()); if (!mime.isEmpty()) { @@ -330,15 +330,15 @@ HRESULT UpdateRegistry(BOOL bRegister) mime = mime.left(mime.length() - extension.length() - 1); // Prepend '.' before extension, if required. extension = extension.trimmed(); - if (extension[0] != QChar(QLatin1Char('.'))) - extension = QLatin1String(".") + extension; + if (extension[0] != QLatin1Char('.')) + extension = QLatin1Char('.') + extension; } if (!extension.isEmpty()) { - settings.setValue(QLatin1String("/") + extension + QLatin1String("/."), module + QLatin1String(".") + className); - settings.setValue(QLatin1String("/") + extension + QLatin1String("/Content Type"), mime); + settings.setValue(QLatin1Char('/') + extension + QLatin1String("/."), module + QLatin1Char('.') + className); + settings.setValue(QLatin1Char('/') + extension + QLatin1String("/Content Type"), mime); - mime = mime.replace(QLatin1String("/"), QLatin1String("\\")); + mime = mime.replace(QLatin1Char('/'), QLatin1Char('\\')); settings.setValue(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/CLSID"), classId); settings.setValue(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/Extension"), extension); } @@ -358,22 +358,22 @@ HRESULT UpdateRegistry(BOOL bRegister) const QString classId = qAxFactory()->classID(className).toString().toUpper(); className = qax_clean_type(className, mo); - QString classVersion = mo ? QString(QLatin1String(mo->classInfo(mo->indexOfClassInfo("Version")).value())) : QString(); + QString classVersion = mo ? QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("Version")).value()) : QString(); if (classVersion.isNull()) classVersion = QLatin1String("1.0"); - const QString classMajorVersion = classVersion.left(classVersion.indexOf(QLatin1String("."))); + const QString classMajorVersion = classVersion.left(classVersion.indexOf(QLatin1Char('.'))); qAxFactory()->unregisterClass(*key, &settings); - settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/CLSID/.")); - settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/Insertable/.")); - settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/.")); - settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/CLSID/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/Insertable/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion); - settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/CLSID/.")); - settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/CurVer/.")); - settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/.")); - settings.remove(QLatin1String("/") + module + QLatin1String(".") + className); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/CLSID/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/CurVer/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className); settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/AppID")); settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/Control/.")); @@ -404,14 +404,14 @@ HRESULT UpdateRegistry(BOOL bRegister) mime = mime.left(mime.length() - extension.length() - 1); // Prepend '.' before extension, if required. extension = extension.trimmed(); - if (extension[0] != QChar(QLatin1Char('.'))) - extension = QLatin1String(".") + extension; + if (extension[0] != QLatin1Char('.')) + extension.prepend(QLatin1Char('.')); } if (!extension.isEmpty()) { - settings.remove(QLatin1String("/") + extension + QLatin1String("/Content Type")); - settings.remove(QLatin1String("/") + extension + QLatin1String("/.")); - settings.remove(QLatin1String("/") + extension); - mime = mime.replace(QLatin1String("/"), QLatin1String("\\")); + settings.remove(QLatin1Char('/') + extension + QLatin1String("/Content Type")); + settings.remove(QLatin1Char('/') + extension + QLatin1String("/.")); + settings.remove(QLatin1Char('/') + extension); + mime.replace(QLatin1Char('/'), QLatin1Char('\\')); settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/Extension")); settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/CLSID")); settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/.")); @@ -455,8 +455,8 @@ static const char* const type_map[][2] = { "QFont", "IFontDisp*" }, { "QPixmap", "IPictureDisp*" }, { "QVariant", "VARIANT" }, - { "QVariantList", "SAFEARRAY(VARIANT)" }, - { "QList<QVariant>","SAFEARRAY(VARIANT)" }, + { "QVariantList", "SAFEARRAY(VARIANT)" }, + { "QList<QVariant>", "SAFEARRAY(VARIANT)" }, { "quint64", "CY" }, { "qint64", "CY" }, { "qulonglong", "CY" }, @@ -464,8 +464,8 @@ static const char* const type_map[][2] = { "QByteArray", "SAFEARRAY(BYTE)" }, { "QStringList", "SAFEARRAY(BSTR)" }, // Userdefined Qt datatypes - some not on Borland though - { "QCursor", "enum MousePointer" }, - { "Qt::FocusPolicy","enum FocusPolicy" }, + { "QCursor", "enum MousePointer" }, + { "Qt::FocusPolicy", "enum FocusPolicy" }, #ifndef Q_CC_BOR # if __REQUIRED_RPCNDR_H_VERSION__ >= Q_REQUIRED_RPCNDR_H_VERSION { "QRect", "struct QRect" }, @@ -578,7 +578,7 @@ static QByteArray renameOverloads(const QByteArray &name) int n = mapping.value(name); if (mapping.contains(name)) { int n = mapping.value(name); - newName = name + "_" + QByteArray::number(n); + newName = name + '_' + QByteArray::number(n); mapping.insert(name, n+1); } else { mapping.insert(name, 1); @@ -686,13 +686,13 @@ static QByteArray prototype(const QList<QByteArray> ¶meterTypes, const QList QByteArray type(parameterTypes.at(p)); QByteArray name(parameterNames.at(p)); - if (type.endsWith("&")) { + if (type.endsWith('&')) { out = true; type.truncate(type.length() - 1); } else if (type.endsWith("**")) { out = true; type.truncate(type.length() - 1); - } else if (type.endsWith("*") && !subtypes.contains(type)) { + } else if (type.endsWith('*') && !subtypes.contains(type)) { type.truncate(type.length() - 1); } if (type.isEmpty()) { @@ -701,14 +701,14 @@ static QByteArray prototype(const QList<QByteArray> ¶meterTypes, const QList } type = convertTypes(type, ok); if (!out) - prototype += "[in] " + type + " "; + prototype += "[in] " + type + ' '; else - prototype += "[in,out] " + type + " "; + prototype += "[in,out] " + type + ' '; if (out) - prototype += "*"; + prototype += '*'; if (name.isEmpty()) - prototype += "p" + QByteArray::number(p); + prototype += 'p' + QByteArray::number(p); else prototype += "p_" + replaceKeyword(name); @@ -728,12 +728,12 @@ static QByteArray addDefaultArguments(const QByteArray &prototype, int numDefArg QByteArray ptype(prototype); int in = -1; while (numDefArgs) { - in = ptype.lastIndexOf("]", in); + in = ptype.lastIndexOf(']', in); ptype.replace(in, 1, ",optional]"); in = ptype.indexOf(' ', in) + 1; QByteArray type = ptype.mid(in, ptype.indexOf(' ', in) - in); if (type == "enum") - type += " " + ptype.mid(in + 5, ptype.indexOf(' ', in + 5) - in - 5); + type += ' ' + ptype.mid(in + 5, ptype.indexOf(' ', in + 5) - in - 5); ptype.replace(in, type.length(), QByteArray("VARIANT /*was: ") + type + "*/"); --numDefArgs; } @@ -801,7 +801,7 @@ static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &classN for (int j = 0; j < enumerator.keyCount(); ++j) { QByteArray key(enumerator.key(j)); while (enumValues.contains(key)) { - key += "_"; + key += '_'; } enumValues.append(key); uint value = (uint)enumerator.value(j); @@ -822,32 +822,32 @@ static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &classN if (!enums.contains("MousePointer")) { enums.append("MousePointer"); out << "\tenum MousePointer {" << endl; - out << "\t\tArrowCursor = " << Qt::ArrowCursor << "," << endl; - out << "\t\tUpArrowCursor = " << Qt::UpArrowCursor << "," << endl; - out << "\t\tCrossCursor = " << Qt::CrossCursor << "," << endl; - out << "\t\tWaitCursor = " << Qt::WaitCursor << "," << endl; - out << "\t\tIBeamCursor = " << Qt::IBeamCursor << "," << endl; - out << "\t\tSizeVerCursor = " << Qt::SizeVerCursor << "," << endl; - out << "\t\tSizeHorCursor = " << Qt::SizeHorCursor << "," << endl; - out << "\t\tSizeBDiagCursor = " << Qt::SizeBDiagCursor << "," << endl; - out << "\t\tSizeFDiagCursor = " << Qt::SizeFDiagCursor << "," << endl; - out << "\t\tSizeAllCursor = " << Qt::SizeAllCursor << "," << endl; - out << "\t\tBlankCursor = " << Qt::BlankCursor << "," << endl; - out << "\t\tSplitVCursor = " << Qt::SplitVCursor << "," << endl; - out << "\t\tSplitHCursor = " << Qt::SplitHCursor << "," << endl; - out << "\t\tPointingHandCursor = " << Qt::PointingHandCursor << "," << endl; - out << "\t\tForbiddenCursor = " << Qt::ForbiddenCursor << "," << endl; - out << "\t\tWhatsThisCursor = " << Qt::WhatsThisCursor << "," << endl; + out << "\t\tArrowCursor = " << Qt::ArrowCursor << ',' << endl; + out << "\t\tUpArrowCursor = " << Qt::UpArrowCursor << ',' << endl; + out << "\t\tCrossCursor = " << Qt::CrossCursor << ',' << endl; + out << "\t\tWaitCursor = " << Qt::WaitCursor << ',' << endl; + out << "\t\tIBeamCursor = " << Qt::IBeamCursor << ',' << endl; + out << "\t\tSizeVerCursor = " << Qt::SizeVerCursor << ',' << endl; + out << "\t\tSizeHorCursor = " << Qt::SizeHorCursor << ',' << endl; + out << "\t\tSizeBDiagCursor = " << Qt::SizeBDiagCursor << ',' << endl; + out << "\t\tSizeFDiagCursor = " << Qt::SizeFDiagCursor << ',' << endl; + out << "\t\tSizeAllCursor = " << Qt::SizeAllCursor << ',' << endl; + out << "\t\tBlankCursor = " << Qt::BlankCursor << ',' << endl; + out << "\t\tSplitVCursor = " << Qt::SplitVCursor << ',' << endl; + out << "\t\tSplitHCursor = " << Qt::SplitHCursor << ',' << endl; + out << "\t\tPointingHandCursor = " << Qt::PointingHandCursor << ',' << endl; + out << "\t\tForbiddenCursor = " << Qt::ForbiddenCursor << ',' << endl; + out << "\t\tWhatsThisCursor = " << Qt::WhatsThisCursor << ',' << endl; out << "\t\tBusyCursor\t= " << Qt::BusyCursor << endl; out << "\t};" << endl << endl; } if (!enums.contains("FocusPolicy")) { enums.append("FocusPolicy"); out << "\tenum FocusPolicy {" << endl; - out << "\t\tNoFocus = " << Qt::NoFocus << "," << endl; - out << "\t\tTabFocus = " << Qt::TabFocus << "," << endl; - out << "\t\tClickFocus = " << Qt::ClickFocus << "," << endl; - out << "\t\tStrongFocus = " << Qt::StrongFocus << "," << endl; + out << "\t\tNoFocus = " << Qt::NoFocus << ',' << endl; + out << "\t\tTabFocus = " << Qt::TabFocus << ',' << endl; + out << "\t\tClickFocus = " << Qt::ClickFocus << ',' << endl; + out << "\t\tStrongFocus = " << Qt::StrongFocus << ',' << endl; out << "\t\tWheelFocus = " << Qt::WheelFocus << endl; out << "\t};" << endl << endl; } @@ -877,7 +877,7 @@ static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &classN if (!ok) out << "\t/****** Property is of unsupported datatype" << endl; - out << "\t\t[id(" << id << ")"; + out << "\t\t[id(" << id << ')'; if (!property.isWritable()) out << ", readonly"; if (isBindable && property.isScriptable(o)) @@ -886,9 +886,9 @@ static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &classN out << ", nonbrowsable"; if (isBindable) out << ", requestedit"; - if (defProp == QString::fromLatin1(name.constData())) + if (defProp == QLatin1String(name)) out << ", uidefault"; - out << "] " << type << " " << name << ";" << endl; + out << "] " << type << ' ' << name << ';' << endl; if (!ok) out << "\t******/" << endl; @@ -939,7 +939,7 @@ static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &classN if (!ok) outBuffer += "\t/****** Slot parameter uses unsupported datatype\n"; - outBuffer += "\t\t[id(" + QString::number(id).toLatin1() + ")] " + type + " " + name + "(" + ptype + ");\n"; + outBuffer += "\t\t[id(" + QString::number(id).toLatin1() + ")] " + type + ' ' + name + '(' + ptype + ");\n"; if (!ok) outBuffer += "\t******/\n"; @@ -991,7 +991,7 @@ static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &classN QList<QByteArray> parameterTypes(signal.parameterTypes()); QList<QByteArray> parameterNames(signal.parameterNames()); - bool isDefault = defSignal == QString::fromLatin1(name.constData()); + bool isDefault = defSignal == QLatin1String(name); name = renameOverloads(replaceKeyword(name)); bool ok = true; @@ -1003,10 +1003,10 @@ static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &classN if (!ok) out << "\t/****** Signal parameter uses unsupported datatype" << endl; - out << "\t\t[id(" << id << ")"; + out << "\t\t[id(" << id << ')'; if (isDefault) out << ", uidefault"; - out << "] void " << name << "(" << ptype << ");" << endl; + out << "] void " << name << '(' << ptype << ");" << endl; if (!ok) out << "\t******/" << endl; @@ -1031,7 +1031,7 @@ static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &classN const char *classVersion = mo->classInfo(mo->indexOfClassInfo("Version")).value(); if (classVersion) out << "\t\tversion(" << classVersion << ")," << endl; - out << "\t\tuuid(" << classID << ")"; + out << "\t\tuuid(" << classID << ')'; if (control) { out << ", " << endl; out << "\t\tcontrol"; @@ -1043,7 +1043,7 @@ static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &classN out << "\t]" << endl; out << "\tcoclass " << cleanClassName << endl; out << "\t{" << endl; - out << "\t\t[default] dispinterface I" << cleanClassName << ";" << endl; + out << "\t\t[default] dispinterface I" << cleanClassName << ';' << endl; if (hasEvents) out << "\t\t[default, source] dispinterface I" << cleanClassName << "Events;" << endl; out << "\t};" << endl; @@ -1068,7 +1068,7 @@ extern "C" HRESULT __stdcall DumpIDL(const QString &outfile, const QString &ver) file.remove(); QString filebase = QString::fromLocal8Bit(qAxModuleFilename); - filebase = filebase.left(filebase.lastIndexOf(QLatin1String("."))); + filebase = filebase.left(filebase.lastIndexOf(QLatin1Char('.'))); QString appID = qAxFactory()->appID().toString().toUpper(); if (QUuid(appID).isNull()) @@ -1103,7 +1103,7 @@ extern "C" HRESULT __stdcall DumpIDL(const QString &outfile, const QString &ver) out << "/****************************************************************************" << endl; out << "** Interface definition generated for ActiveQt project" << endl; out << "**" << endl; - out << "** '" << qAxModuleFilename << "'" << endl; + out << "** '" << qAxModuleFilename << '\'' << endl; out << "**" << endl; out << "** Created: " << QDateTime::currentDateTime().toString() << endl; out << "**" << endl; @@ -1121,13 +1121,13 @@ extern "C" HRESULT __stdcall DumpIDL(const QString &outfile, const QString &ver) delete_qApp = true; } - out << "[" << endl; + out << '[' << endl; out << "\tuuid(" << typeLibID << ")," << endl; out << "\tversion(" << version << ")," << endl; - out << "\thelpstring(\"" << typelib << " " << version << " Type Library\")" << endl; - out << "]" << endl; + out << "\thelpstring(\"" << typelib << ' ' << version << " Type Library\")" << endl; + out << ']' << endl; out << "library " << typelib << "Lib" << endl; - out << "{" << endl; + out << '{' << endl; out << "\timportlib(\"stdole32.tlb\");" << endl; out << "\timportlib(\"stdole2.tlb\");" << endl << endl; @@ -1188,11 +1188,12 @@ extern "C" HRESULT __stdcall DumpIDL(const QString &outfile, const QString &ver) // We have meta object information for this type. Forward declare it. if (mo) { QByteArray cleanType = qax_clean_type(*key, mo).toLatin1(); - out << "\tcoclass " << cleanType << ";" << endl; + out << "\tcoclass " << cleanType << ';' << endl; + subtypes.append(cleanType); + qRegisterMetaType(cleanType, (void**)0); + cleanType += '*'; subtypes.append(cleanType); - subtypes.append(cleanType + "*"); qRegisterMetaType(cleanType, (void**)0); - qRegisterMetaType(cleanType + "*", (void**)0); } } out << endl; @@ -1225,7 +1226,7 @@ extern "C" HRESULT __stdcall DumpIDL(const QString &outfile, const QString &ver) QByteArray cleanType = qax_clean_type(*key, mo).toLatin1(); subtypes.append(cleanType); - subtypes.append(cleanType + "*"); + subtypes.append(cleanType + '*'); res = classIDL(o, mo, QString::fromLatin1(className.constData()), isBindable, out); delete o; if (res != S_OK) diff --git a/src/activeqt/control/qaxserverbase.cpp b/src/activeqt/control/qaxserverbase.cpp index f3e1dff..19c2404 100644 --- a/src/activeqt/control/qaxserverbase.cpp +++ b/src/activeqt/control/qaxserverbase.cpp @@ -2446,10 +2446,10 @@ HRESULT WINAPI QAxServerBase::Invoke(DISPID dispidMember, REFIID riid, int nameLength = 0; if (index == -1) { nameLength = name.length(); - name += "("; + name += '('; // no parameter - shortcut if (!pDispParams->cArgs) - index = mo->indexOfSlot((name + ")")); + index = mo->indexOfSlot((name + ')')); // search if (index == -1) { for (int i = 0; i < mo->methodCount(); ++i) { @@ -2463,7 +2463,7 @@ HRESULT WINAPI QAxServerBase::Invoke(DISPID dispidMember, REFIID riid, if (index == -1) { QRegExp regexp(QLatin1String("_([0-9])\\(")); if (regexp.lastIndexIn(QString::fromLatin1(name.constData())) != -1) { - name = name.left(name.length() - regexp.cap(0).length()) + "("; + name = name.left(name.length() - regexp.cap(0).length()) + '('; int overload = regexp.cap(1).toInt() + 1; for (int s = 0; s < qt.object->metaObject()->methodCount(); ++s) { @@ -2559,7 +2559,7 @@ HRESULT WINAPI QAxServerBase::Invoke(DISPID dispidMember, REFIID riid, argv[p + 1] = varp + p + 1; } else { argv[p + 1] = const_cast<void*>(varp[p + 1].constData()); - if (ptype.endsWith("*")) { + if (ptype.endsWith('*')) { argv_pointer[p + 1] = argv[p + 1]; argv[p + 1] = argv_pointer + p + 1; } @@ -2590,7 +2590,7 @@ HRESULT WINAPI QAxServerBase::Invoke(DISPID dispidMember, REFIID riid, } else { argv[0] = const_cast<void*>(varp[0].constData()); } - if (type.endsWith("*")) { + if (type.endsWith('*')) { argv_pointer[0] = argv[0]; argv[0] = argv_pointer; } diff --git a/src/activeqt/control/qaxservermain.cpp b/src/activeqt/control/qaxservermain.cpp index a50fef0..e3e1e5d 100644 --- a/src/activeqt/control/qaxservermain.cpp +++ b/src/activeqt/control/qaxservermain.cpp @@ -253,7 +253,7 @@ EXTERN_C int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR, run = false; break; } else { - unprocessed += cmds.at(i) + " "; + unprocessed += cmds.at(i) + ' '; } } diff --git a/src/activeqt/shared/qaxtypes.cpp b/src/activeqt/shared/qaxtypes.cpp index ace81e7..12307f3 100644 --- a/src/activeqt/shared/qaxtypes.cpp +++ b/src/activeqt/shared/qaxtypes.cpp @@ -1111,7 +1111,7 @@ QVariant VARIANTToQVariant(const VARIANT &arg, const QByteArray &typeName, uint if (iface) { QObject *qObj = iface->qObject(); iface->Release(); - var = QVariant(qRegisterMetaType<QObject*>(qObj ? QByteArray(qObj->metaObject()->className()) + "*" : typeName), &qObj); + var = QVariant(qRegisterMetaType<QObject*>(qObj ? QByteArray(qObj->metaObject()->className()) + '*' : typeName), &qObj); } else #endif { diff --git a/src/corelib/animation/animation.pri b/src/corelib/animation/animation.pri new file mode 100644 index 0000000..cb7850c --- /dev/null +++ b/src/corelib/animation/animation.pri @@ -0,0 +1,25 @@ +# Qt core animation module + +HEADERS += \ + animation/qabstractanimation.h \ + animation/qabstractanimation_p.h \ + animation/qvariantanimation.h \ + animation/qvariantanimation_p.h \ + animation/qpropertyanimation.h \ + animation/qpropertyanimation_p.h \ + animation/qanimationgroup.h \ + animation/qanimationgroup_p.h \ + animation/qsequentialanimationgroup.h \ + animation/qsequentialanimationgroup_p.h \ + animation/qparallelanimationgroup.h \ + animation/qparallelanimationgroup_p.h \ + animation/qpauseanimation.h + +SOURCES += \ + animation/qabstractanimation.cpp \ + animation/qvariantanimation.cpp \ + animation/qpropertyanimation.cpp \ + animation/qanimationgroup.cpp \ + animation/qsequentialanimationgroup.cpp \ + animation/qparallelanimationgroup.cpp \ + animation/qpauseanimation.cpp diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp new file mode 100644 index 0000000..16307e6 --- /dev/null +++ b/src/corelib/animation/qabstractanimation.cpp @@ -0,0 +1,733 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QAbstractAnimation + \ingroup animation + \brief The QAbstractAnimation class is the base of all animations. + \since 4.6 + + The class defines the functions for the functionality shared by + all animations. By inheriting this class, you can create custom + animations that plug into the rest of the animation framework. + + The progress of an animation is given by its current time + (currentTime()), which is measured in milliseconds from the start + of the animation (0) to its end (duration()). The value is updated + automatically while the animation is running. It can also be set + directly with setCurrentTime(). + + At any point an animation is in one of three states: + \l{QAbstractAnimation::}{Running}, + \l{QAbstractAnimation::}{Stopped}, or + \l{QAbstractAnimation::}{Paused}--as defined by the + \l{QAbstractAnimation::}{State} enum. The current state can be + changed by calling start(), stop(), pause(), or resume(). An + animation will always reset its \l{currentTime()}{current time} + when it is started. If paused, it will continue with the same + current time when resumed. When an animation is stopped, it cannot + be resumed, but will keep its current time (until started again). + QAbstractAnimation will emit stateChanged() whenever its state + changes. + + An animation can loop any number of times by setting the loopCount + property. When an animation's current time reaches its duration(), + it will reset the current time and keep running. A loop count of 1 + (the default value) means that the animation will run one time. + Note that a duration of -1 means that the animation will run until + stopped; the current time will increase indefinitely. When the + current time equals duration() and the animation is in its + final loop, the \l{QAbstractAnimation::}{Stopped} state is + entered, and the finished() signal is emitted. + + QAbstractAnimation provides pure virtual functions used by + subclasses to track the progress of the animation: duration() and + updateCurrentTime(). The duration() function lets you report a + duration for the animation (as discussed above). The current time + is delivered by the animation framework through calls to + updateCurrentTime(). By reimplementing this function, you can + track the animation progress. Note that neither the interval + between calls nor the number of calls to this function are + defined; though, it will normally be 60 updates per second. + + By reimplementing updateState(), you can track the animation's + state changes, which is particularly useful for animations that + are not driven by time. + + \sa QVariantAnimation, QPropertyAnimation, QAnimationGroup, {The Animation Framework} +*/ + +/*! + \enum QAbstractAnimation::DeletionPolicy + + \value KeepWhenStopped The animation will not be deleted when stopped. + \value DeleteWhenStopped The animation will be automatically deleted when + stopped. +*/ + +/*! + \fn QAbstractAnimation::finished() + + QAbstractAnimation emits this signal after the animation has stopped and + has reached the end. + + This signal is emitted after stateChanged(). + + \sa stateChanged() +*/ + +/*! + \fn QAbstractAnimation::stateChanged(QAbstractAnimation::State oldState, QAbstractAnimation::State newState) + + QAbstractAnimation emits this signal whenever the state of the animation has + changed from \a oldState to \a newState. This signal is emitted after the virtual + updateState() function is called. + + \sa updateState() +*/ + +/*! + \fn QAbstractAnimation::currentLoopChanged(int currentLoop) + + QAbstractAnimation emits this signal whenever the current loop + changes. \a currentLoop is the current loop. + + \sa currentLoop(), loopCount() +*/ + +/*! + \fn QAbstractAnimation::directionChanged(QAbstractAnimation::Direction newDirection); + + QAbstractAnimation emits this signal whenever the direction has been + changed. \a newDirection is the new direction. + + \sa direction +*/ + +#ifndef QT_NO_ANIMATION + +#include "qabstractanimation.h" +#include "qanimationgroup.h" +#include <QtCore/qdebug.h> + +#include "qabstractanimation_p.h" + +#include <QtCore/qmath.h> +#include <QtCore/qthreadstorage.h> +#include <QtCore/qcoreevent.h> +#include <QtCore/qpointer.h> + +#define DEFAULT_TIMER_INTERVAL 16 + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer); + +QUnifiedTimer::QUnifiedTimer() : QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), consistentTiming(false) +{ +} + +QUnifiedTimer *QUnifiedTimer::instance() +{ + QUnifiedTimer *inst; + if (!unifiedTimer()->hasLocalData()) { + inst = new QUnifiedTimer; + unifiedTimer()->setLocalData(inst); + } else { + inst = unifiedTimer()->localData(); + } + return inst; +} + +void QUnifiedTimer::updateRecentlyStartedAnimations() +{ + if (animationsToStart.isEmpty()) + return; + + animations += animationsToStart; + updateTimer(); //we make sure we start the timer there + + animationsToStart.clear(); +} + +void QUnifiedTimer::timerEvent(QTimerEvent *event) +{ + //this is simply the time we last received a tick + const int oldLastTick = lastTick; + if (time.isValid()) + lastTick = consistentTiming ? oldLastTick + timingInterval : time.elapsed(); + + //we transfer the waiting animations into the "really running" state + updateRecentlyStartedAnimations(); + + if (event->timerId() == startStopAnimationTimer.timerId()) { + startStopAnimationTimer.stop(); + if (animations.isEmpty()) { + animationTimer.stop(); + time = QTime(); + } else { + animationTimer.start(timingInterval, this); + lastTick = 0; + time.start(); + } + } else if (event->timerId() == animationTimer.timerId()) { + const int delta = lastTick - oldLastTick; + for (int i = 0; i < animations.count(); ++i) { + QAbstractAnimation *animation = animations.at(i); + int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime + + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta); + animation->setCurrentTime(elapsed); + } + } +} + +void QUnifiedTimer::updateTimer() +{ + //we delay the call to start and stop for the animation timer so that if you + //stop and start animations in batch you don't stop/start the timer too often. + if (!startStopAnimationTimer.isActive()) + startStopAnimationTimer.start(0, this); // we delay the actual start of the animation +} + +void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation) +{ + if (animations.contains(animation) ||animationsToStart.contains(animation)) + return; + animationsToStart << animation; + updateTimer(); +} + +void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) +{ + animations.removeAll(animation); + animationsToStart.removeAll(animation); + updateTimer(); +} + + +void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) +{ + Q_Q(QAbstractAnimation); + if (state == newState) + return; + + QAbstractAnimation::State oldState = state; + int oldCurrentTime = currentTime; + int oldCurrentLoop = currentLoop; + QAbstractAnimation::Direction oldDirection = direction; + + state = newState; + + QPointer<QAbstractAnimation> guard(q); + + guard->updateState(oldState, newState); + + //this is to be safe if updateState changes the state + if (state == oldState) + return; + + // Notify state change + if (guard) + emit guard->stateChanged(oldState, newState); + + // Enter running state. + switch (state) + { + case QAbstractAnimation::Paused: + case QAbstractAnimation::Running: + { + // Rewind + if (oldState == QAbstractAnimation::Stopped) { + if (guard) { + if (direction == QAbstractAnimation::Forward) + q->setCurrentTime(0); + else + q->setCurrentTime(loopCount == -1 ? q->duration() : q->totalDuration()); + } + + // Check if the setCurrentTime() function called stop(). + // This can happen for a 0-duration animation + if (state == QAbstractAnimation::Stopped) + return; + } + + // Register timer if our parent is not running. + if (state == QAbstractAnimation::Running && guard) { + if (!group || group->state() == QAbstractAnimation::Stopped) { + QUnifiedTimer::instance()->registerAnimation(q); + } + } else { + //new state is paused + QUnifiedTimer::instance()->unregisterAnimation(q); + } + } + break; + case QAbstractAnimation::Stopped: + // Leave running state. + int dura = q->duration(); + if (deleteWhenStopped && guard) + q->deleteLater(); + + QUnifiedTimer::instance()->unregisterAnimation(q); + + if (dura == -1 || loopCount < 0 + || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount)) + || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) { + if (guard) + emit q->finished(); + } + break; + } + +} + +/*! + Constructs the QAbstractAnimation base class, and passes \a parent to + QObject's constructor. + + \sa QVariantAnimation, QAnimationGroup +*/ +QAbstractAnimation::QAbstractAnimation(QObject *parent) + : QObject(*new QAbstractAnimationPrivate, 0) +{ + // Allow auto-add on reparent + setParent(parent); +} + +/*! + \internal +*/ +QAbstractAnimation::QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent) + : QObject(dd, 0) +{ + // Allow auto-add on reparent + setParent(parent); +} + +/*! + Stops the animation if it's running, then destroys the + QAbstractAnimation. If the animation is part of a QAnimationGroup, it is + automatically removed before it's destroyed. +*/ +QAbstractAnimation::~QAbstractAnimation() +{ + Q_D(QAbstractAnimation); + //we can't call stop here. Otherwise we get pure virtual calls + if (d->state != Stopped) { + QAbstractAnimation::State oldState = d->state; + d->state = Stopped; + emit stateChanged(oldState, d->state); + QUnifiedTimer::instance()->unregisterAnimation(this); + } +} + +/*! + \property QAbstractAnimation::state + \brief state of the animation. + + This property describes the current state of the animation. When the + animation state changes, QAbstractAnimation emits the stateChanged() + signal. +*/ +QAbstractAnimation::State QAbstractAnimation::state() const +{ + Q_D(const QAbstractAnimation); + return d->state; +} + +/*! + If this animation is part of a QAnimationGroup, this function returns a + pointer to the group; otherwise, it returns 0. + + \sa QAnimationGroup::addAnimation() +*/ +QAnimationGroup *QAbstractAnimation::group() const +{ + Q_D(const QAbstractAnimation); + return d->group; +} + +/*! + \enum QAbstractAnimation::State + + This enum describes the state of the animation. + + \value Stopped The animation is not running. This is the initial state + of QAbstractAnimation, and the state QAbstractAnimation reenters when finished. The current + time remain unchanged until either setCurrentTime() is + called, or the animation is started by calling start(). + + \value Paused The animation is paused (i.e., temporarily + suspended). Calling resume() will resume animation activity. + + \value Running The animation is running. While control is in the event + loop, QAbstractAnimation will update its current time at regular intervals, + calling updateCurrentTime() when appropriate. + + \sa state(), stateChanged() +*/ + +/*! + \enum QAbstractAnimation::Direction + + This enum describes the direction of the animation when in \l Running state. + + \value Forward The current time of the animation increases with time (i.e., + moves from 0 and towards the end / duration). + + \value Backward The current time of the animation decreases with time (i.e., + moves from the end / duration and towards 0). + + \sa direction +*/ + +/*! + \property QAbstractAnimation::direction + \brief the direction of the animation when it is in \l Running + state. + + This direction indicates whether the time moves from 0 towards the + animation duration, or from the value of the duration and towards 0 after + start() has been called. + + By default, this property is set to \l Forward. +*/ +QAbstractAnimation::Direction QAbstractAnimation::direction() const +{ + Q_D(const QAbstractAnimation); + return d->direction; +} +void QAbstractAnimation::setDirection(Direction direction) +{ + Q_D(QAbstractAnimation); + if (d->direction == direction) + return; + + d->direction = direction; + if (state() == Stopped) { + if (direction == Backward) { + d->currentTime = duration(); + d->currentLoop = d->loopCount - 1; + } else { + d->currentTime = 0; + d->currentLoop = 0; + } + } + updateDirection(direction); + emit directionChanged(direction); +} + +/*! + \property QAbstractAnimation::duration + \brief the duration of the animation. + + If the duration is -1, it means that the duration is undefined. + In this case, loopCount is ignored. +*/ + +/*! + \property QAbstractAnimation::loopCount + \brief the loop count of the animation + + This property describes the loop count of the animation as an integer. + By default this value is 1, indicating that the animation + should run once only, and then stop. By changing it you can let the + animation loop several times. With a value of 0, the animation will not + run at all, and with a value of -1, the animation will loop forever + until stopped. + It is not supported to have loop on an animation that has an undefined + duration. It will only run once. +*/ +int QAbstractAnimation::loopCount() const +{ + Q_D(const QAbstractAnimation); + return d->loopCount; +} +void QAbstractAnimation::setLoopCount(int loopCount) +{ + Q_D(QAbstractAnimation); + d->loopCount = loopCount; +} + +/*! + \property QAbstractAnimation::currentLoop + \brief the current loop of the animation + + This property describes the current loop of the animation. By default, + the animation's loop count is 1, and so the current loop will + always be 0. If the loop count is 2 and the animation runs past its + duration, it will automatically rewind and restart at current time 0, and + current loop 1, and so on. + + When the current loop changes, QAbstractAnimation emits the + currentLoopChanged() signal. +*/ +int QAbstractAnimation::currentLoop() const +{ + Q_D(const QAbstractAnimation); + return d->currentLoop; +} + +/*! + \fn virtual int QAbstractAnimation::duration() const = 0 + + This pure virtual function returns the duration of the animation, and + defines for how long QAbstractAnimation should update the current + time. This duration is local, and does not include the loop count. + + A return value of -1 indicates that the animation has no defined duration; + the animation should run forever until stopped. This is useful for + animations that are not time driven, or where you cannot easily predict + its duration (e.g., event driven audio playback in a game). + + If the animation is a parallel QAnimationGroup, the duration will be the longest + duration of all its animations. If the animation is a sequential QAnimationGroup, + the duration will be the sum of the duration of all its animations. + \sa loopCount +*/ + +/*! + Returns the total and effective duration of the animation, including the + loop count. + + \sa duration(), currentTime +*/ +int QAbstractAnimation::totalDuration() const +{ + Q_D(const QAbstractAnimation); + if (d->loopCount < 0) + return -1; + int dura = duration(); + if (dura == -1) + return -1; + return dura * d->loopCount; +} + +/*! + \property QAbstractAnimation::currentTime + \brief the current time and progress of the animation + + This property describes the animation's current time. You can change the + current time by calling setCurrentTime, or you can call start() and let + the animation run, setting the current time automatically as the animation + progresses. + + The animation's current time starts at 0, and ends at duration(). If the + animation's loopCount is larger than 1, the current time will rewind and + start at 0 again for the consecutive loops. If the animation has a pause. + currentTime will also include the duration of the pause. + + \sa loopCount + */ +int QAbstractAnimation::currentTime() const +{ + Q_D(const QAbstractAnimation); + return d->currentTime; +} +void QAbstractAnimation::setCurrentTime(int msecs) +{ + Q_D(QAbstractAnimation); + msecs = qMax(msecs, 0); + + // Calculate new time and loop. + int dura = duration(); + int totalDura = (d->loopCount < 0 || dura == -1) ? -1 : dura * d->loopCount; + if (totalDura != -1) + msecs = qMin(totalDura, msecs); + d->totalCurrentTime = msecs; + + // Update new values. + int oldLoop = d->currentLoop; + d->currentLoop = ((dura <= 0) ? 0 : (msecs / dura)); + if (d->currentLoop == d->loopCount) { + //we're at the end + d->currentTime = qMax(0, dura); + d->currentLoop = qMax(0, d->loopCount - 1); + } else { + if (d->direction == Forward) { + d->currentTime = (dura <= 0) ? msecs : (msecs % dura); + } else { + d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1; + if (d->currentTime == dura) + --d->currentLoop; + } + } + + updateCurrentTime(msecs); + if (d->currentLoop != oldLoop) + emit currentLoopChanged(d->currentLoop); + + // All animations are responsible for stopping the animation when their + // own end state is reached; in this case the animation is time driven, + // and has reached the end. + if ((d->direction == Forward && d->totalCurrentTime == totalDura) + || (d->direction == Backward && d->totalCurrentTime == 0)) { + stop(); + } +} + +/*! + Starts the animation. The \a policy argument says whether or not the + animation should be deleted when it's done. When the animation starts, the + stateChanged() signal is emitted, and state() returns Running. When control + reaches the event loop, the animation will run by itself, periodically + calling updateCurrentTime() as the animation progresses. + + If the animation is currently stopped or has already reached the end, + calling start() will rewind the animation and start again from the beginning. + When the animation reaches the end, the animation will either stop, or + if the loop level is more than 1, it will rewind and continue from the beginning. + + If the animation is already running, this function does nothing. + + \sa stop(), state() +*/ +void QAbstractAnimation::start(DeletionPolicy policy) +{ + Q_D(QAbstractAnimation); + if (d->state == Running) + return; + d->setState(Running); + d->deleteWhenStopped = policy; +} + +/*! + Stops the animation. When the animation is stopped, it emits the stateChanged() + signal, and state() returns Stopped. The current time is not changed. + + If the animation stops by itself after reaching the end (i.e., + currentTime() == duration() and currentLoop() > loopCount() - 1), the + finished() signal is emitted. + + \sa start(), state() + */ +void QAbstractAnimation::stop() +{ + Q_D(QAbstractAnimation); + + d->setState(Stopped); +} + +/*! + Pauses the animation. When the animation is paused, state() returns Paused. + The currenttime will remain unchanged until resume() or start() is called. + If you want to continue from the current time, call resume(). + + + \sa start(), state(), resume() + */ +void QAbstractAnimation::pause() +{ + Q_D(QAbstractAnimation); + if (d->state == Stopped) { + qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation"); + return; + } + + d->setState(Paused); +} + +/*! + Resumes the animation after it was paused. When the animation is resumed, + it emits the resumed() and stateChanged() signals. The currenttime is not + changed. + + \sa start(), pause(), state() + */ +void QAbstractAnimation::resume() +{ + Q_D(QAbstractAnimation); + if (d->state != Paused) { + qWarning("QAbstractAnimation::resume: " + "Cannot resume an animation that is not paused"); + return; + } + + d->setState(Running); +} + +/*! + \reimp +*/ +bool QAbstractAnimation::event(QEvent *event) +{ + return QObject::event(event); +} + +/*! + \fn virtual void QAbstractAnimation::updateCurrentTime(int msecs) = 0; + + This pure virtual function is called every time the animation's current + time changes. The \a msecs argument is the current time. + + \sa updateState() +*/ + +/*! + This virtual function is called by QAbstractAnimation when the state + of the animation is changed from \a oldState to \a newState. + + \sa start(), stop(), pause(), resume() +*/ +void QAbstractAnimation::updateState(QAbstractAnimation::State oldState, + QAbstractAnimation::State newState) +{ + Q_UNUSED(oldState); + Q_UNUSED(newState); +} + +/*! + This virtual function is called by QAbstractAnimation when the direction + of the animation is changed. The \a direction argument is the new direction. + + \sa setDirection(), direction() +*/ +void QAbstractAnimation::updateDirection(QAbstractAnimation::Direction direction) +{ + Q_UNUSED(direction); +} + + +QT_END_NAMESPACE + +#include "moc_qabstractanimation.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h new file mode 100644 index 0000000..d6d50dc --- /dev/null +++ b/src/corelib/animation/qabstractanimation.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTANIMATION_H +#define QABSTRACTANIMATION_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QAnimationGroup; +class QSequentialAnimationGroup; + +class QAbstractAnimationPrivate; +class Q_CORE_EXPORT QAbstractAnimation : public QObject +{ + Q_OBJECT + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount) + Q_PROPERTY(int currentTime READ currentTime WRITE setCurrentTime) + Q_PROPERTY(int currentLoop READ currentLoop NOTIFY currentLoopChanged) + Q_PROPERTY(Direction direction READ direction WRITE setDirection NOTIFY directionChanged) + Q_PROPERTY(int duration READ duration) + +public: + enum Direction { + Forward, + Backward + }; + + enum State { + Stopped, + Paused, + Running + }; + + enum DeletionPolicy { + KeepWhenStopped = 0, + DeleteWhenStopped + }; + + QAbstractAnimation(QObject *parent = 0); + virtual ~QAbstractAnimation(); + + State state() const; + + QAnimationGroup *group() const; + + Direction direction() const; + void setDirection(Direction direction); + + int loopCount() const; + void setLoopCount(int loopCount); + int currentLoop() const; + + virtual int duration() const = 0; + int totalDuration() const; + + int currentTime() const; + +Q_SIGNALS: + void finished(); + void stateChanged(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + void currentLoopChanged(int currentLoop); + void directionChanged(QAbstractAnimation::Direction); + +public Q_SLOTS: + void start(QAbstractAnimation::DeletionPolicy policy = KeepWhenStopped); + void pause(); + void resume(); + void stop(); + void setCurrentTime(int msecs); + +protected: + QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent = 0); + bool event(QEvent *event); + + virtual void updateCurrentTime(int msecs) = 0; + virtual void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + virtual void updateDirection(QAbstractAnimation::Direction direction); + +private: + Q_DISABLE_COPY(QAbstractAnimation) + Q_DECLARE_PRIVATE(QAbstractAnimation) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QABSTRACTANIMATION_H diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h new file mode 100644 index 0000000..7a4bfcf --- /dev/null +++ b/src/corelib/animation/qabstractanimation_p.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTANIMATION_P_H +#define QABSTRACTANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qbasictimer.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qtimer.h> +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QAnimationGroup; +class QAbstractAnimation; +class QAbstractAnimationPrivate : public QObjectPrivate +{ +public: + QAbstractAnimationPrivate() + : state(QAbstractAnimation::Stopped), + direction(QAbstractAnimation::Forward), + deleteWhenStopped(false), + totalCurrentTime(0), + currentTime(0), + loopCount(1), + currentLoop(0), + group(0) + { + } + + virtual ~QAbstractAnimationPrivate() {} + + static QAbstractAnimationPrivate *get(QAbstractAnimation *q) + { + return q->d_func(); + } + + QAbstractAnimation::State state; + QAbstractAnimation::Direction direction; + bool deleteWhenStopped; + void setState(QAbstractAnimation::State state); + + int totalCurrentTime; + int currentTime; + int loopCount; + int currentLoop; + + QAnimationGroup *group; + +private: + Q_DECLARE_PUBLIC(QAbstractAnimation) +}; + + +class QUnifiedTimer : public QObject +{ +private: + QUnifiedTimer(); + +public: + //XXX this is needed by dui + static Q_CORE_EXPORT QUnifiedTimer *instance(); + + void registerAnimation(QAbstractAnimation *animation); + void unregisterAnimation(QAbstractAnimation *animation); + + //defines the timing interval. Default is DEFAULT_TIMER_INTERVAL + void setTimingInterval(int interval) + { + timingInterval = interval; + if (animationTimer.isActive()) { + //we changed the timing interval + animationTimer.start(timingInterval, this); + } + } + + /* + this allows to have a consistent timer interval at each tick from the timer + not taking the real time that passed into account. + */ + void setConsistentTiming(bool consistent) { consistentTiming = consistent; } + + int elapsedTime() const { return lastTick; } + +protected: + void timerEvent(QTimerEvent *); + void updateTimer(); + +private: + void updateRecentlyStartedAnimations(); + + QBasicTimer animationTimer, startStopAnimationTimer; + QTime time; + int lastTick; + int timingInterval; + bool consistentTiming; + QList<QAbstractAnimation*> animations, animationsToStart; +}; + +QT_END_NAMESPACE +#endif diff --git a/src/corelib/animation/qanimationgroup.cpp b/src/corelib/animation/qanimationgroup.cpp new file mode 100644 index 0000000..839b522 --- /dev/null +++ b/src/corelib/animation/qanimationgroup.cpp @@ -0,0 +1,309 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QAnimationGroup + \brief The QAnimationGroup class is an abstract base class for groups of animations. + \since 4.6 + \ingroup animation + + An animation group is a container for animations (subclasses of + QAbstractAnimation). A group is usually responsible for managing + the \l{QAbstractAnimation::State}{state} of its animations, i.e., + it decides when to start, stop, resume, and pause them. Currently, + Qt provides two such groups: QParallelAnimationGroup and + QSequentialAnimationGroup. Look up their class descriptions for + details. + + Since QAnimationGroup inherits from QAbstractAnimation, you can + combine groups, and easily construct complex animation graphs. + You can query QAbstractAnimation for the group it belongs to + (using the \l{QAbstractAnimation::}{group()} function). + + To start a top-level animation group, you simply use the + \l{QAbstractAnimation::}{start()} function from + QAbstractAnimation. By a top-level animation group, we think of a + group that itself is not contained within another group. Starting + sub groups directly is not supported, and may lead to unexpected + behavior. + + \omit OK, we'll put in a snippet on this here \endomit + + QAnimationGroup provides methods for adding and retrieving + animations. Besides that, you can remove animations by calling + remove(), and clear the animation group by calling + clearAnimations(). You may keep track of changes in the group's + animations by listening to QEvent::ChildAdded and + QEvent::ChildRemoved events. + + \omit OK, let's find a snippet here as well. \endomit + + QAnimationGroup takes ownership of the animations it manages, and + ensures that they are deleted when the animation group is deleted. + + You can also use a \l{The State Machine Framework}{state machine} + to create complex animations. The framework provides a special + state, QAnimationState, that plays an animation upon entry and + transitions to a new state when the animation has finished + playing. This technique can also be combined with using animation + groups. + + \sa QAbstractAnimation, QVariantAnimation, {The Animation Framework} +*/ + +#ifndef QT_NO_ANIMATION + +#include "qanimationgroup.h" +#include <QtCore/qdebug.h> +#include <QtCore/qcoreevent.h> +#include "qanimationgroup_p.h" + +QT_BEGIN_NAMESPACE + + +/*! + Constructs a QAnimationGroup. + \a parent is passed to QObject's constructor. +*/ +QAnimationGroup::QAnimationGroup(QObject *parent) + : QAbstractAnimation(*new QAnimationGroupPrivate, parent) +{ +} + +/*! + \internal +*/ +QAnimationGroup::QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent) + : QAbstractAnimation(dd, parent) +{ +} + +/*! + Destroys the animation group. It will also destroy all its animations. +*/ +QAnimationGroup::~QAnimationGroup() +{ +} + +/*! + Returns a pointer to the animation at \a index in this group. This + function is useful when you need access to a particular animation. \a + index is between 0 and animationCount() - 1. + + \sa animationCount(), indexOfAnimation() +*/ +QAbstractAnimation *QAnimationGroup::animationAt(int index) const +{ + Q_D(const QAnimationGroup); + + if (index < 0 || index >= d->animations.size()) { + qWarning("QAnimationGroup::animationAt: index is out of bounds"); + return 0; + } + + return d->animations.at(index); +} + + +/*! + Returns the number of animations managed by this group. + + \sa indexOfAnimation(), addAnimation(), animationAt() +*/ +int QAnimationGroup::animationCount() const +{ + Q_D(const QAnimationGroup); + return d->animations.size(); +} + +/*! + Returns the index of \a animation. The returned index can be passed + to the other functions that take an index as an argument. + + \sa insertAnimationAt(), animationAt(), takeAnimationAt() +*/ +int QAnimationGroup::indexOfAnimation(QAbstractAnimation *animation) const +{ + Q_D(const QAnimationGroup); + return d->animations.indexOf(animation); +} + +/*! + Adds \a animation to this group. This will call insertAnimationAt with + index equals to animationCount(). + + \note The group takes ownership of the animation. + + \sa removeAnimation() +*/ +void QAnimationGroup::addAnimation(QAbstractAnimation *animation) +{ + Q_D(QAnimationGroup); + insertAnimationAt(d->animations.count(), animation); +} + +/*! + Inserts \a animation into this animation group at \a index. + If \a index is 0 the animation is inserted at the beginning. + If \a index is animationCount(), the animation is inserted at the end. + + \note The group takes ownership of the animation. + + \sa takeAnimationAt(), addAnimation(), indexOfAnimation(), removeAnimation() +*/ +void QAnimationGroup::insertAnimationAt(int index, QAbstractAnimation *animation) +{ + Q_D(QAnimationGroup); + + if (index < 0 || index > d->animations.size()) { + qWarning("QAnimationGroup::insertAnimationAt: index is out of bounds"); + return; + } + + if (QAnimationGroup *oldGroup = animation->group()) + oldGroup->removeAnimation(animation); + + d->animations.insert(index, animation); + QAbstractAnimationPrivate::get(animation)->group = this; + // this will make sure that ChildAdded event is sent to 'this' + animation->setParent(this); + d->animationInsertedAt(index); +} + +/*! + Removes \a animation from this group. The ownership of \a animation is + transferred to the caller. + + \sa takeAnimationAt(), insertAnimationAt(), addAnimation() +*/ +void QAnimationGroup::removeAnimation(QAbstractAnimation *animation) +{ + Q_D(QAnimationGroup); + + if (!animation) { + qWarning("QAnimationGroup::remove: cannot remove null animation"); + return; + } + int index = d->animations.indexOf(animation); + if (index == -1) { + qWarning("QAnimationGroup::remove: animation is not part of this group"); + return; + } + + takeAnimationAt(index); +} + +/*! + Returns the animation at \a index and removes it from the animation group. + + \note The ownership of the animation is transferred to the caller. + + \sa removeAnimation(), addAnimation(), insertAnimationAt(), indexOfAnimation() +*/ +QAbstractAnimation *QAnimationGroup::takeAnimationAt(int index) +{ + Q_D(QAnimationGroup); + if (index < 0 || index >= d->animations.size()) { + qWarning("QAnimationGroup::takeAnimationAt: no animation at index %d", index); + return 0; + } + QAbstractAnimation *animation = d->animations.at(index); + QAbstractAnimationPrivate::get(animation)->group = 0; + // ### removing from list before doing setParent to avoid inifinite recursion + // in ChildRemoved event + d->animations.removeAt(index); + animation->setParent(0); + d->animationRemovedAt(index); + return animation; +} + +/*! + Removes and deletes all animations in this animation group, and resets the current + time to 0. + + \sa addAnimation(), removeAnimation() +*/ +void QAnimationGroup::clearAnimations() +{ + Q_D(QAnimationGroup); + qDeleteAll(d->animations); +} + +/*! + \reimp +*/ +bool QAnimationGroup::event(QEvent *event) +{ + Q_D(QAnimationGroup); + if (event->type() == QEvent::ChildAdded) { + QChildEvent *childEvent = static_cast<QChildEvent *>(event); + if (QAbstractAnimation *a = qobject_cast<QAbstractAnimation *>(childEvent->child())) { + if (a->group() != this) + addAnimation(a); + } + } else if (event->type() == QEvent::ChildRemoved) { + QChildEvent *childEvent = static_cast<QChildEvent *>(event); + QAbstractAnimation *a = static_cast<QAbstractAnimation *>(childEvent->child()); + // You can only rely on the child being a QObject because in the QEvent::ChildRemoved + // case it might be called from the destructor. + int index = d->animations.indexOf(a); + if (index != -1) + takeAnimationAt(index); + } + return QAbstractAnimation::event(event); +} + + +void QAnimationGroupPrivate::animationRemovedAt(int index) +{ + Q_Q(QAnimationGroup); + Q_UNUSED(index); + if (animations.isEmpty()) { + currentTime = 0; + q->stop(); + } +} + +QT_END_NAMESPACE + +#include "moc_qanimationgroup.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qanimationgroup.h b/src/corelib/animation/qanimationgroup.h new file mode 100644 index 0000000..263bc38 --- /dev/null +++ b/src/corelib/animation/qanimationgroup.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANIMATIONGROUP_H +#define QANIMATIONGROUP_H + +#include <QtCore/qabstractanimation.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QAnimationGroupPrivate; +class Q_CORE_EXPORT QAnimationGroup : public QAbstractAnimation +{ + Q_OBJECT + +public: + QAnimationGroup(QObject *parent = 0); + ~QAnimationGroup(); + + QAbstractAnimation *animationAt(int index) const; + int animationCount() const; + int indexOfAnimation(QAbstractAnimation *animation) const; + void addAnimation(QAbstractAnimation *animation); + void insertAnimationAt(int index, QAbstractAnimation *animation); + void removeAnimation(QAbstractAnimation *animation); + QAbstractAnimation *takeAnimationAt(int index); + void clearAnimations(); + +protected: + QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent); + bool event(QEvent *event); + +private: + Q_DISABLE_COPY(QAnimationGroup) + Q_DECLARE_PRIVATE(QAnimationGroup) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QANIMATIONGROUP_H diff --git a/src/corelib/animation/qanimationgroup_p.h b/src/corelib/animation/qanimationgroup_p.h new file mode 100644 index 0000000..a7bd0fa --- /dev/null +++ b/src/corelib/animation/qanimationgroup_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANIMATIONGROUP_P_H +#define QANIMATIONGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qanimationgroup.h" + +#include <QtCore/qlist.h> + +#include "qabstractanimation_p.h" + +QT_BEGIN_NAMESPACE + +class QAnimationGroupPrivate : public QAbstractAnimationPrivate +{ + Q_DECLARE_PUBLIC(QAnimationGroup) +public: + QAnimationGroupPrivate() + { } + + virtual void animationInsertedAt(int index) { Q_UNUSED(index) }; + virtual void animationRemovedAt(int index); + + QList<QAbstractAnimation *> animations; +}; + +QT_END_NAMESPACE + +#endif //QANIMATIONGROUP_P_H diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp new file mode 100644 index 0000000..13f6073 --- /dev/null +++ b/src/corelib/animation/qparallelanimationgroup.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QParallelAnimationGroup + \brief The QParallelAnimationGroup class provides a parallel group of animations. + \since 4.6 + \ingroup animation + + QParallelAnimationGroup--a \l{QAnimationGroup}{container for + animations}--starts all its animations when it is + \l{QAbstractAnimation::start()}{started} itself, i.e., runs all + animations in parallel. The animation group finishes when the + longest lasting animation has finished. + + You can treat QParallelAnimation as any other QAbstractAnimation, + e.g., pause, resume, or add it to other animation groups. + + \code + QParallelAnimationGroup *group = new QParallelAnimationGroup; + group->addAnimation(anim1); + group->addAnimation(anim2); + + group->start(); + \endcode + + In this example, \c anim1 and \c anim2 are two + \l{QPropertyAnimation}s that have already been set up. + + \sa QAnimationGroup, QPropertyAnimation, {The Animation Framework} +*/ + +#ifndef QT_NO_ANIMATION + +#include "qparallelanimationgroup.h" +#include "qparallelanimationgroup_p.h" +//#define QANIMATION_DEBUG +QT_BEGIN_NAMESPACE + +/*! + Constructs a QParallelAnimationGroup. + \a parent is passed to QObject's constructor. +*/ +QParallelAnimationGroup::QParallelAnimationGroup(QObject *parent) + : QAnimationGroup(*new QParallelAnimationGroupPrivate, parent) +{ +} + +/*! + \internal +*/ +QParallelAnimationGroup::QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd, + QObject *parent) + : QAnimationGroup(dd, parent) +{ +} + +/*! + Destroys the animation group. It will also destroy all its animations. +*/ +QParallelAnimationGroup::~QParallelAnimationGroup() +{ +} + +/*! + \reimp +*/ +int QParallelAnimationGroup::duration() const +{ + Q_D(const QParallelAnimationGroup); + int ret = 0; + + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); + const int currentDuration = animation->totalDuration(); + if (currentDuration == -1) + return -1; // Undetermined length + + ret = qMax(ret, currentDuration); + } + + return ret; +} + +/*! + \reimp +*/ +void QParallelAnimationGroup::updateCurrentTime(int) +{ + Q_D(QParallelAnimationGroup); + if (d->animations.isEmpty()) + return; + + if (d->currentLoop > d->lastLoop) { + // simulate completion of the loop + int dura = duration(); + if (dura > 0) { + foreach (QAbstractAnimation *animation, d->animations) { + animation->setCurrentTime(dura); // will stop + } + } + } else if (d->currentLoop < d->lastLoop) { + // simulate completion of the loop seeking backwards + foreach (QAbstractAnimation *animation, d->animations) { + animation->setCurrentTime(0); + animation->stop(); + } + } + + bool timeFwd = ((d->currentLoop == d->lastLoop && d->currentTime >= d->lastCurrentTime) + || d->currentLoop > d->lastLoop); +#ifdef QANIMATION_DEBUG + qDebug("QParallellAnimationGroup %5d: setCurrentTime(%d), loop:%d, last:%d, timeFwd:%d, lastcurrent:%d, %d", + __LINE__, d->currentTime, d->currentLoop, d->lastLoop, timeFwd, d->lastCurrentTime, state()); +#endif + // finally move into the actual time of the current loop + foreach (QAbstractAnimation *animation, d->animations) { + const int dura = animation->totalDuration(); + if (dura == -1 && d->isUncontrolledAnimationFinished(animation)) + continue; + if (dura == -1 || (d->currentTime <= dura && dura != 0) + || (dura == 0 && d->currentLoop != d->lastLoop)) { + switch (state()) { + case Running: + animation->start(); + break; + case Paused: + animation->pause(); + break; + case Stopped: + default: + break; + } + } + + if (dura <= 0) { + if (dura == -1) + animation->setCurrentTime(d->currentTime); + continue; + } + + if ((timeFwd && d->lastCurrentTime <= dura) + || (!timeFwd && d->currentTime <= dura)) + animation->setCurrentTime(d->currentTime); + if (d->currentTime > dura) + animation->stop(); + } + d->lastLoop = d->currentLoop; + d->lastCurrentTime = d->currentTime; +} + +/*! + \reimp +*/ +void QParallelAnimationGroup::updateState(QAbstractAnimation::State oldState, + QAbstractAnimation::State newState) +{ + Q_D(QParallelAnimationGroup); + QAnimationGroup::updateState(oldState, newState); + + switch (newState) { + case Stopped: + foreach (QAbstractAnimation *animation, d->animations) + animation->stop(); + d->disconnectUncontrolledAnimations(); + break; + case Paused: + foreach (QAbstractAnimation *animation, d->animations) + animation->pause(); + break; + case Running: + d->connectUncontrolledAnimations(); + foreach (QAbstractAnimation *animation, d->animations) { + animation->stop(); + animation->setDirection(d->direction); + animation->start(); + } + break; + } +} + +void QParallelAnimationGroupPrivate::_q_uncontrolledAnimationFinished() +{ + Q_Q(QParallelAnimationGroup); + + QAbstractAnimation *animation = qobject_cast<QAbstractAnimation *>(q->sender()); + Q_ASSERT(animation); + + int uncontrolledRunningCount = 0; + if (animation->duration() == -1 || animation->loopCount() < 0) { + QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin(); + while (it != uncontrolledFinishTime.end()) { + if (it.key() == animation) { + *it = animation->currentTime(); + } + if (it.value() == -1) + ++uncontrolledRunningCount; + ++it; + } + } + + if (uncontrolledRunningCount > 0) + return; + + int maxDuration = 0; + foreach (QAbstractAnimation *a, animations) + maxDuration = qMax(maxDuration, a->totalDuration()); + + if (currentTime >= maxDuration) + q->stop(); +} + +void QParallelAnimationGroupPrivate::disconnectUncontrolledAnimations() +{ + Q_Q(QParallelAnimationGroup); + + QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin(); + while (it != uncontrolledFinishTime.end()) { + QObject::disconnect(it.key(), SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished())); + ++it; + } + + uncontrolledFinishTime.clear(); +} + +void QParallelAnimationGroupPrivate::connectUncontrolledAnimations() +{ + Q_Q(QParallelAnimationGroup); + + foreach (QAbstractAnimation *animation, animations) { + if (animation->duration() == -1 || animation->loopCount() < 0) { + uncontrolledFinishTime[animation] = -1; + QObject::connect(animation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished())); + } + } +} + +bool QParallelAnimationGroupPrivate::isUncontrolledAnimationFinished(QAbstractAnimation *anim) const +{ + return uncontrolledFinishTime.value(anim, -1) >= 0; +} + +/*! + \reimp +*/ +void QParallelAnimationGroup::updateDirection(QAbstractAnimation::Direction direction) +{ + Q_D(QParallelAnimationGroup); + //we need to update the direction of the current animation + if (state() != Stopped) { + foreach(QAbstractAnimation *anim, d->animations) { + anim->setDirection(direction); + } + } else { + if (direction == Forward) { + d->lastLoop = 0; + d->lastCurrentTime = 0; + } else { + // Looping backwards with loopCount == -1 does not really work well... + d->lastLoop = (d->loopCount == -1 ? 0 : d->loopCount - 1); + d->lastCurrentTime = duration(); + } + } +} + +/*! + \reimp +*/ +bool QParallelAnimationGroup::event(QEvent *event) +{ + return QAnimationGroup::event(event); +} + +QT_END_NAMESPACE + +#include "moc_qparallelanimationgroup.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qparallelanimationgroup.h b/src/corelib/animation/qparallelanimationgroup.h new file mode 100644 index 0000000..57a8146 --- /dev/null +++ b/src/corelib/animation/qparallelanimationgroup.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPARALLELANIMATIONGROUP_H +#define QPARALLELANIMATIONGROUP_H + +#include <QtCore/qanimationgroup.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QParallelAnimationGroupPrivate; +class Q_CORE_EXPORT QParallelAnimationGroup : public QAnimationGroup +{ + Q_OBJECT + +public: + QParallelAnimationGroup(QObject *parent = 0); + ~QParallelAnimationGroup(); + + int duration() const; + +protected: + QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd, QObject *parent); + bool event(QEvent *event); + + void updateCurrentTime(int msecs); + void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + void updateDirection(QAbstractAnimation::Direction direction); + +private: + Q_DISABLE_COPY(QParallelAnimationGroup) + Q_DECLARE_PRIVATE(QParallelAnimationGroup) + Q_PRIVATE_SLOT(d_func(), void _q_uncontrolledAnimationFinished()) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPARALLELANIMATIONGROUP diff --git a/src/corelib/animation/qparallelanimationgroup_p.h b/src/corelib/animation/qparallelanimationgroup_p.h new file mode 100644 index 0000000..f36d972 --- /dev/null +++ b/src/corelib/animation/qparallelanimationgroup_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPARALLELANIMATIONGROUP_P_H +#define QPARALLELANIMATIONGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qparallelanimationgroup.h" +#include "qanimationgroup_p.h" +#include <QtCore/QHash> + +QT_BEGIN_NAMESPACE + +class QParallelAnimationGroupPrivate : public QAnimationGroupPrivate +{ + Q_DECLARE_PUBLIC(QParallelAnimationGroup) +public: + QParallelAnimationGroupPrivate() + : lastLoop(0), lastCurrentTime(0) + { + } + + QHash<QAbstractAnimation*, int> uncontrolledFinishTime; + int lastLoop; + int lastCurrentTime; + + bool isUncontrolledAnimationFinished(QAbstractAnimation *anim) const; + void connectUncontrolledAnimations(); + void disconnectUncontrolledAnimations(); + + // private slot + void _q_uncontrolledAnimationFinished(); +}; + +QT_END_NAMESPACE + +#endif //QPARALLELANIMATIONGROUP_P_H diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp new file mode 100644 index 0000000..b175f0c --- /dev/null +++ b/src/corelib/animation/qpauseanimation.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QPauseAnimation + \brief The QPauseAnimation class provides a pause for QSequentialAnimationGroup. + \since 4.6 + \ingroup animation + + If you wish to introduce a delay between animations in a + QSequentialAnimationGroup, you can insert a QPauseAnimation. This + class does not animate anything, but does not + \l{QAbstractAnimation::finished()}{finish} before a specified + number of milliseconds have elapsed from when it was started. You + specify the duration of the pause in the constructor. It can also + be set directly with setDuration(). + + It is not necessary to construct a QPauseAnimation yourself. + QSequentialAnimationGroup provides the convenience functions + \l{QSequentialAnimationGroup::}{addPause()} and + \l{QSequentialAnimationGroup::}{insertPauseAt()}. These functions + simply take the number of milliseconds the pause should last. + + \sa QSequentialAnimationGroup +*/ + +#ifndef QT_NO_ANIMATION + +#include "qpauseanimation.h" +#include "qabstractanimation_p.h" + + +QT_BEGIN_NAMESPACE + +class QPauseAnimationPrivate : public QAbstractAnimationPrivate +{ +public: + QPauseAnimationPrivate() : QAbstractAnimationPrivate(), duration(0) + { + } + + int duration; +}; + +/*! + Constructs a QPauseAnimation. + \a parent is passed to QObject's constructor. + The default duration is 0. +*/ + +QPauseAnimation::QPauseAnimation(QObject *parent) : QAbstractAnimation(*new QPauseAnimationPrivate, parent) +{ +} + +/*! + Constructs a QPauseAnimation. + \a msecs is the duration of the pause. + \a parent is passed to QObject's constructor. +*/ + +QPauseAnimation::QPauseAnimation(int msecs, QObject *parent) : QAbstractAnimation(*new QPauseAnimationPrivate, parent) +{ + setDuration(msecs); +} + +/*! + Destroys the pause animation. +*/ +QPauseAnimation::~QPauseAnimation() +{ +} + +/*! + \property QPauseAnimation::duration + \brief the duration of the pause. + + The duration of the pause. The duration should not be negative. +*/ +int QPauseAnimation::duration() const +{ + Q_D(const QPauseAnimation); + return d->duration; +} + +void QPauseAnimation::setDuration(int msecs) +{ + if (msecs < 0) { + qWarning("QPauseAnimation::setDuration: cannot set a negative duration"); + return; + } + Q_D(QPauseAnimation); + d->duration = msecs; +} + +/*! + \reimp + */ +bool QPauseAnimation::event(QEvent *e) +{ + return QAbstractAnimation::event(e); +} + +/*! + \reimp + */ +void QPauseAnimation::updateCurrentTime(int msecs) +{ + Q_UNUSED(msecs); +} + + +QT_END_NAMESPACE + +#include "moc_qpauseanimation.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qpauseanimation.h b/src/corelib/animation/qpauseanimation.h new file mode 100644 index 0000000..cb6e041 --- /dev/null +++ b/src/corelib/animation/qpauseanimation.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAUSEANIMATION_P_H +#define QPAUSEANIMATION_P_H + +#include <QtCore/qanimationgroup.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QPauseAnimationPrivate; + +class Q_CORE_EXPORT QPauseAnimation : public QAbstractAnimation +{ + Q_OBJECT + Q_PROPERTY(int duration READ duration WRITE setDuration) +public: + QPauseAnimation(QObject *parent = 0); + QPauseAnimation(int msecs, QObject *parent = 0); + ~QPauseAnimation(); + + int duration() const; + void setDuration(int msecs); + +protected: + bool event(QEvent *e); + void updateCurrentTime(int msecs); + +private: + Q_DISABLE_COPY(QPauseAnimation) + Q_DECLARE_PRIVATE(QPauseAnimation) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPAUSEANIMATION_P_H diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp new file mode 100644 index 0000000..47361a5 --- /dev/null +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -0,0 +1,315 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QPropertyAnimation + \brief The QPropertyAnimation class animates Qt properties + \since 4.6 + \ingroup animation + + QPropertyAnimation interpolates over \l{Qt's Property System}{Qt + properties}. As property values are stored in \l{QVariant}s, the + class inherits QVariantAnimation, and supports animation of the + same \l{QVariant::Type}{variant types} as its super class. + + A class declaring properties must be a QObject. To make it + possible to animate a property, it must provide a setter (so that + QPropertyAnimation can set the property's value). Note that this + makes it possible to animate many of Qt's widgets. Let's look at + an example: + + \code + QPropertyAnimation animation(myWidget, "geometry"); + animation.setDuration(10000); + animation.setStartValue(QRect(0, 0, 100, 30)); + animation.setEndValue(QRect(250, 250, 100, 30)); + + animation.start(); + \endcode + + The property name and the QObject instance of which property + should be animated are passed to the constructor. You can then + specify the start and end value of the property. The procedure is + equal for properties in classes you have implemented + yourself--just check with QVariantAnimation that your QVariant + type is supported. + + The QVariantAnimation class description explains how to set up the + animation in detail. Note, however, that if a start value is not + set, the property will start at the value it had when the + QPropertyAnimation instance was created. + + QPropertyAnimation works like a charm on its own. For complex + animations that, for instance, contain several objects, + QAnimationGroup is provided. An animation group is an animation + that can contain other animations, and that can manage when its + animations are played. Look at QParallelAnimationGroup for an + example. + + \sa QVariantAnimation, QAnimationGroup, {The Animation Framework} +*/ + +#ifndef QT_NO_ANIMATION + +#include "qpropertyanimation.h" +#include "qanimationgroup.h" +#include <QtCore/qdebug.h> + +#include "qpropertyanimation_p.h" + +#include <QtCore/qmath.h> +#include <QtCore/qmutex.h> + +QT_BEGIN_NAMESPACE + +typedef QPair<QObject *, QByteArray> QPropertyAnimationPair; +typedef QHash<QPropertyAnimationPair, QPropertyAnimation*> QPropertyAnimationHash; +Q_GLOBAL_STATIC(QPropertyAnimationHash, _q_runningAnimations); +Q_GLOBAL_STATIC_WITH_ARGS(QMutex, guardHashLock, (QMutex::Recursive) ) + +void QPropertyAnimationPrivate::updateMetaProperty() +{ + if (!target || propertyName.isEmpty()) + return; + + if (!hasMetaProperty && !property.isValid()) { + const QMetaObject *mo = target->metaObject(); + propertyIndex = mo->indexOfProperty(propertyName); + if (propertyIndex != -1) { + hasMetaProperty = true; + property = mo->property(propertyIndex); + propertyType = property.userType(); + } else { + if (!target->dynamicPropertyNames().contains(propertyName)) + qWarning("QPropertyAnimation: you're trying to animate a non-existing property %s of your QObject", propertyName.constData()); + } + } + + if (property.isValid()) + convertValues(propertyType); +} + +void QPropertyAnimationPrivate::updateProperty(const QVariant &newValue) +{ + if (!target || state == QAbstractAnimation::Stopped) + return; + + if (hasMetaProperty) { + if (newValue.userType() == propertyType) { + //no conversion is needed, we directly call the QObject::qt_metacall + void *data = const_cast<void*>(newValue.constData()); + target->qt_metacall(QMetaObject::WriteProperty, propertyIndex, &data); + } else { + property.write(target, newValue); + } + } else { + target->setProperty(propertyName.constData(), newValue); + } +} + +void QPropertyAnimationPrivate::_q_targetDestroyed() +{ + Q_Q(QPropertyAnimation); + //we stop here so that this animation is removed from the global hash + q->stop(); + target = 0; +} + +/*! + Construct a QPropertyAnimation object. \a parent is passed to QObject's + constructor. +*/ +QPropertyAnimation::QPropertyAnimation(QObject *parent) + : QVariantAnimation(*new QPropertyAnimationPrivate, parent) +{ +} + +/*! + Construct a QPropertyAnimation object. \a parent is passed to QObject's + constructor. The animation changes the property \a propertyName on \a + target. The default duration is 250ms. + + \sa targetObject, propertyName +*/ +QPropertyAnimation::QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent) + : QVariantAnimation(*new QPropertyAnimationPrivate, parent) +{ + setTargetObject(target); + setPropertyName(propertyName); +} + +/*! + Destroys the QPropertyAnimation instance. + */ +QPropertyAnimation::~QPropertyAnimation() +{ + stop(); +} + +/*! + \property QPropertyAnimation::targetObject + \brief the target QObject for this animation. + + This property defines the target QObject for this animation. + */ +QObject *QPropertyAnimation::targetObject() const +{ + Q_D(const QPropertyAnimation); + return d->target; +} + +void QPropertyAnimation::setTargetObject(QObject *target) +{ + Q_D(QPropertyAnimation); + if (d->target == target) + return; + + if (d->state != QAbstractAnimation::Stopped) { + qWarning("QPropertyAnimation::setTargetObject: you can't change the target of a running animation"); + return; + } + + //we need to get notified when the target is destroyed + if (d->target) + disconnect(d->target, SIGNAL(destroyed()), this, SLOT(_q_targetDestroyed())); + + if (target) + connect(target, SIGNAL(destroyed()), SLOT(_q_targetDestroyed())); + + d->target = target; + d->hasMetaProperty = false; + d->updateMetaProperty(); +} + +/*! + \property QPropertyAnimation::propertyName + \brief the target property name for this animation + + This property defines the target property name for this animation. The + property name is required for the animation to operate. + */ +QByteArray QPropertyAnimation::propertyName() const +{ + Q_D(const QPropertyAnimation); + return d->propertyName; +} + +void QPropertyAnimation::setPropertyName(const QByteArray &propertyName) +{ + Q_D(QPropertyAnimation); + if (d->state != QAbstractAnimation::Stopped) { + qWarning("QPropertyAnimation::setPropertyName: you can't change the property name of a running animation"); + return; + } + + d->propertyName = propertyName; + d->hasMetaProperty = false; + d->updateMetaProperty(); +} + + +/*! + \reimp + */ +bool QPropertyAnimation::event(QEvent *event) +{ + return QVariantAnimation::event(event); +} + +/*! + This virtual function is called by QVariantAnimation whenever the current value + changes. \a value is the new, updated value. It updates the current value + of the property on the target object. + + \sa currentValue, currentTime + */ +void QPropertyAnimation::updateCurrentValue(const QVariant &value) +{ + Q_D(QPropertyAnimation); + d->updateProperty(value); +} + +/*! + \reimp + + If the startValue is not defined when the state of the animation changes from Stopped to Running, + the current property value is used as the initial value for the animation. +*/ +void QPropertyAnimation::updateState(QAbstractAnimation::State oldState, + QAbstractAnimation::State newState) +{ + Q_D(QPropertyAnimation); + + if (!d->target) { + qWarning("QPropertyAnimation::updateState: Changing state of an animation without target"); + return; + } + + QVariantAnimation::updateState(oldState, newState); + QMutexLocker locker(guardHashLock()); + QPropertyAnimationHash * hash = _q_runningAnimations(); + QPropertyAnimationPair key(d->target, d->propertyName); + if (newState == Running) { + d->updateMetaProperty(); + QPropertyAnimation *oldAnim = hash->value(key, 0); + if (oldAnim) { + // try to stop the top level group + QAbstractAnimation *current = oldAnim; + while (current->group() && current->state() != Stopped) + current = current->group(); + current->stop(); + } + hash->insert(key, this); + + // update the default start value + if (oldState == Stopped) { + d->setDefaultStartValue(d->target->property(d->propertyName.constData())); + } + } else if (hash->value(key) == this) { + hash->remove(key); + } +} + +#include "moc_qpropertyanimation.cpp" + +QT_END_NAMESPACE + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qpropertyanimation.h b/src/corelib/animation/qpropertyanimation.h new file mode 100644 index 0000000..39317ba --- /dev/null +++ b/src/corelib/animation/qpropertyanimation.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPROPERTYANIMATION_H +#define QPROPERTYANIMATION_H + +#include <QtCore/qvariantanimation.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QPropertyAnimationPrivate; +class Q_CORE_EXPORT QPropertyAnimation : public QVariantAnimation +{ + Q_OBJECT + Q_PROPERTY(QByteArray propertyName READ propertyName WRITE setPropertyName) + Q_PROPERTY(QObject* targetObject READ targetObject WRITE setTargetObject) + +public: + QPropertyAnimation(QObject *parent = 0); + QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent = 0); + ~QPropertyAnimation(); + + QObject *targetObject() const; + void setTargetObject(QObject *target); + + QByteArray propertyName() const; + void setPropertyName(const QByteArray &propertyName); + +protected: + bool event(QEvent *event); + void updateCurrentValue(const QVariant &value); + void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + +private: + Q_PRIVATE_SLOT(d_func(), void _q_targetDestroyed()); + Q_DISABLE_COPY(QPropertyAnimation) + Q_DECLARE_PRIVATE(QPropertyAnimation) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPROPERTYANIMATION_H diff --git a/src/corelib/animation/qpropertyanimation_p.h b/src/corelib/animation/qpropertyanimation_p.h new file mode 100644 index 0000000..a4387dd --- /dev/null +++ b/src/corelib/animation/qpropertyanimation_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPROPERTYANIMATION_P_H +#define QPROPERTYANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qpropertyanimation.h" +#include <QtCore/qmetaobject.h> + +#include "qvariantanimation_p.h" + +QT_BEGIN_NAMESPACE + +class QPropertyAnimationPrivate : public QVariantAnimationPrivate +{ + Q_DECLARE_PUBLIC(QPropertyAnimation) +public: + QPropertyAnimationPrivate() + : target(0), propertyType(0), propertyIndex(0), hasMetaProperty(false) + { + } + + void _q_targetDestroyed(); + + QObject *target; + + //for the QProperty + QMetaProperty property; + int propertyType; + int propertyIndex; + + bool hasMetaProperty; + QByteArray propertyName; + void updateProperty(const QVariant &); + void updateMetaProperty(); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp new file mode 100644 index 0000000..14814a7 --- /dev/null +++ b/src/corelib/animation/qsequentialanimationgroup.cpp @@ -0,0 +1,594 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QSequentialAnimationGroup + \brief The QSequentialAnimationGroup class provides a sequential group of animations. + \since 4.6 + \ingroup animation + + QSequentialAnimationGroup is a QAnimationGroup that runs its + animations in sequence, i.e., it starts one animation after + another has finished playing. The animations are played in the + order they are added to the group (using + \l{QAnimationGroup::}{addAnimation()} or + \l{QAnimationGroup::}{insertAnimationAt()}). The animation group + finishes when its last animation has finished. + + At each moment there is at most one animation that is active in + the group; it is returned by currentAnimation(). An empty group + has no current animation. + + A sequential animation group can be treated as any other + animation, i.e., it can be started, stopped, and added to other + groups. You can also call addPause() or insertPauseAt() to add a + pause to a sequential animation group. + + \code + QSequentialAnimationGroup group; + + group.addAnimation(anim1); + group.addAnimation(anim2); + + group.start(); + \endcode + + In this example, \c anim1 and \c anim2 are two already set up + \l{QPropertyAnimation}s. + + \sa QAnimationGroup, QAbstractAnimation, {The Animation Framework} +*/ + +#ifndef QT_NO_ANIMATION + +#include "qsequentialanimationgroup.h" +#include "qsequentialanimationgroup_p.h" + +#include "qpauseanimation.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + + + +bool QSequentialAnimationGroupPrivate::atEnd() const +{ + // we try to detect if we're at the end of the group + //this is true if the following conditions are true: + // 1. we're in the last loop + // 2. the direction is forward + // 3. the current animation is the last one + // 4. the current animation has reached its end + const int animTotalCurrentTime = QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime; + return (currentLoop == loopCount - 1 + && direction == QAbstractAnimation::Forward + && currentAnimation == animations.last() + && animTotalCurrentTime == animationActualTotalDuration(currentAnimationIndex)); +} + +int QSequentialAnimationGroupPrivate::animationActualTotalDuration(int index) const +{ + QAbstractAnimation *anim = animations.at(index); + int ret = anim->totalDuration(); + if (ret == -1 && actualDuration.size() > index) + ret = actualDuration.at(index); //we can try the actual duration there + return ret; +} + +QSequentialAnimationGroupPrivate::AnimationIndex QSequentialAnimationGroupPrivate::indexForTime(int msecs) const +{ + Q_Q(const QSequentialAnimationGroup); + Q_ASSERT(!animations.isEmpty()); + + AnimationIndex ret; + int duration = 0; + + // in case duration is -1, currentLoop will always be 0 + ret.timeOffset = currentLoop * q->duration(); + + for (int i = 0; i < animations.size(); ++i) { + duration = animationActualTotalDuration(i); + + // 'animation' is the current animation if one of these reasons is true: + // 1. it's duration is undefined + // 2. it ends after msecs + // 3. it is the last animation (this can happen in case there is at least 1 uncontrolled animation) + // 4. it ends exactly in msecs and the direction is backwards + if (duration == -1 || msecs < (ret.timeOffset + duration) + || (msecs == (ret.timeOffset + duration) && direction == QAbstractAnimation::Backward)) { + ret.index = i; + return ret; + } + + // 'animation' has a non-null defined duration and is not the one at time 'msecs'. + ret.timeOffset += duration; + } + + // this can only happen when one of those conditions is true: + // 1. the duration of the group is undefined and we passed its actual duration + // 2. there are only 0-duration animations in the group + ret.timeOffset -= duration; + ret.index = animations.size() - 1; + return ret; +} + +void QSequentialAnimationGroupPrivate::restart() +{ + // restarting the group by making the first/last animation the current one + if (direction == QAbstractAnimation::Forward) { + lastLoop = 0; + if (currentAnimationIndex == 0) + activateCurrentAnimation(); + else + setCurrentAnimation(0); + } else { // direction == QAbstractAnimation::Backward + lastLoop = loopCount - 1; + int index = animations.size() - 1; + if (currentAnimationIndex == index) + activateCurrentAnimation(); + else + setCurrentAnimation(index); + } +} + +/*! + \internal + This manages advancing the execution of a group running forwards (time has gone forward), + which is the same behaviour for rewinding the execution of a group running backwards + (time has gone backward). +*/ +void QSequentialAnimationGroupPrivate::advanceForwards(const AnimationIndex &newAnimationIndex) +{ + if (lastLoop < currentLoop) { + // we need to fast forward to the end + for (int i = currentAnimationIndex; i < animations.size(); ++i) { + QAbstractAnimation *anim = animations.at(i); + setCurrentAnimation(i, true); + anim->setCurrentTime(animationActualTotalDuration(i)); + } + // this will make sure the current animation is reset to the beginning + if (animations.size() == 1) + // we need to force activation because setCurrentAnimation will have no effect + activateCurrentAnimation(); + else + setCurrentAnimation(0, true); + } + + // and now we need to fast forward from the current position to + for (int i = currentAnimationIndex; i < newAnimationIndex.index; ++i) { //### WRONG, + QAbstractAnimation *anim = animations.at(i); + setCurrentAnimation(i, true); + anim->setCurrentTime(animationActualTotalDuration(i)); + } + // setting the new current animation will happen later +} + +/*! + \internal + This manages rewinding the execution of a group running forwards (time has gone forward), + which is the same behaviour for advancing the execution of a group running backwards + (time has gone backward). +*/ +void QSequentialAnimationGroupPrivate::rewindForwards(const AnimationIndex &newAnimationIndex) +{ + if (lastLoop > currentLoop) { + // we need to fast rewind to the beginning + for (int i = currentAnimationIndex; i >= 0 ; --i) { + QAbstractAnimation *anim = animations.at(i); + setCurrentAnimation(i, true); + anim->setCurrentTime(0); + } + // this will make sure the current animation is reset to the end + if (animations.size() == 1) + // we need to force activation because setCurrentAnimation will have no effect + activateCurrentAnimation(); + else + setCurrentAnimation(animations.count() - 1, true); + } + + // and now we need to fast rewind from the current position to + for (int i = currentAnimationIndex; i > newAnimationIndex.index; --i) { + QAbstractAnimation *anim = animations.at(i); + setCurrentAnimation(i, true); + anim->setCurrentTime(0); + } + // setting the new current animation will happen later +} + +/*! + \fn QSequentialAnimationGroup::currentAnimationChanged(QAbstractAnimation *current) + + QSequentialAnimationGroup emits this signal when currentAnimation + has been changed. \a current is the current animation. + + \sa currentAnimation() +*/ + + +/*! + Constructs a QSequentialAnimationGroup. + \a parent is passed to QObject's constructor. +*/ +QSequentialAnimationGroup::QSequentialAnimationGroup(QObject *parent) + : QAnimationGroup(*new QSequentialAnimationGroupPrivate, parent) +{ +} + +/*! + \internal +*/ +QSequentialAnimationGroup::QSequentialAnimationGroup(QSequentialAnimationGroupPrivate &dd, + QObject *parent) + : QAnimationGroup(dd, parent) +{ +} + +/*! + Destroys the animation group. It will also destroy all its animations. +*/ +QSequentialAnimationGroup::~QSequentialAnimationGroup() +{ +} + +/*! + Adds a pause of \a msecs to this animation group. + The pause is considered as a special type of animation, thus count() will be + increased by one. + \sa insertPauseAt(), QAnimationGroup::addAnimation() +*/ +QPauseAnimation *QSequentialAnimationGroup::addPause(int msecs) +{ + QPauseAnimation *pause = new QPauseAnimation(msecs); + addAnimation(pause); + return pause; +} + +/*! + Inserts a pause of \a msecs milliseconds at \a index in this animation + group. + + \sa addPause(), QAnimationGroup::insertAnimationAt() +*/ +QPauseAnimation *QSequentialAnimationGroup::insertPauseAt(int index, int msecs) +{ + Q_D(const QSequentialAnimationGroup); + + if (index < 0 || index > d->animations.size()) { + qWarning("QSequentialAnimationGroup::insertPauseAt: index is out of bounds"); + return 0; + } + + QPauseAnimation *pause = new QPauseAnimation(msecs); + insertAnimationAt(index, pause); + return pause; +} + + +/*! + \property QSequentialAnimationGroup::currentAnimation + Returns the animation in the current time. + + \sa currentAnimationChanged() +*/ +QAbstractAnimation *QSequentialAnimationGroup::currentAnimation() const +{ + Q_D(const QSequentialAnimationGroup); + return d->currentAnimation; +} + +/*! + \reimp +*/ +int QSequentialAnimationGroup::duration() const +{ + Q_D(const QSequentialAnimationGroup); + int ret = 0; + + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); + const int currentDuration = animation->totalDuration(); + if (currentDuration == -1) + return -1; // Undetermined length + + ret += currentDuration; + } + + return ret; +} + +/*! + \reimp +*/ +void QSequentialAnimationGroup::updateCurrentTime(int msecs) +{ + Q_D(QSequentialAnimationGroup); + if (!d->currentAnimation) + return; + + const QSequentialAnimationGroupPrivate::AnimationIndex newAnimationIndex = d->indexForTime(msecs); + + // remove unneeded animations from actualDuration list + while (newAnimationIndex.index < d->actualDuration.size()) + d->actualDuration.removeLast(); + + // newAnimationIndex.index is the new current animation + if (d->lastLoop < d->currentLoop + || (d->lastLoop == d->currentLoop && d->currentAnimationIndex < newAnimationIndex.index)) { + // advancing with forward direction is the same as rewinding with backwards direction + d->advanceForwards(newAnimationIndex); + } else if (d->lastLoop > d->currentLoop + || (d->lastLoop == d->currentLoop && d->currentAnimationIndex > newAnimationIndex.index)) { + // rewinding with forward direction is the same as advancing with backwards direction + d->rewindForwards(newAnimationIndex); + } + + d->setCurrentAnimation(newAnimationIndex.index); + + const int newCurrentTime = msecs - newAnimationIndex.timeOffset; + + if (d->currentAnimation) { + d->currentAnimation->setCurrentTime(newCurrentTime); + if (d->atEnd()) { + //we make sure that we don't exceed the duration here + d->currentTime += QAbstractAnimationPrivate::get(d->currentAnimation)->totalCurrentTime - newCurrentTime; + stop(); + } + } else { + //the only case where currentAnimation could be null + //is when all animations have been removed + Q_ASSERT(d->animations.isEmpty()); + d->currentTime = 0; + stop(); + } + + d->lastLoop = d->currentLoop; +} + +/*! + \reimp +*/ +void QSequentialAnimationGroup::updateState(QAbstractAnimation::State oldState, + QAbstractAnimation::State newState) +{ + Q_D(QSequentialAnimationGroup); + QAnimationGroup::updateState(oldState, newState); + + if (!d->currentAnimation) + return; + + switch (newState) { + case Stopped: + d->currentAnimation->stop(); + break; + case Paused: + if (oldState == d->currentAnimation->state() + && oldState == QSequentialAnimationGroup::Running) { + d->currentAnimation->pause(); + } + else + d->restart(); + break; + case Running: + if (oldState == d->currentAnimation->state() + && oldState == QSequentialAnimationGroup::Paused) + d->currentAnimation->start(); + else + d->restart(); + break; + } +} + +/*! + \reimp +*/ +void QSequentialAnimationGroup::updateDirection(QAbstractAnimation::Direction direction) +{ + Q_D(QSequentialAnimationGroup); + // we need to update the direction of the current animation + if (state() != Stopped && d->currentAnimation) + d->currentAnimation->setDirection(direction); +} + +/*! + \reimp +*/ +bool QSequentialAnimationGroup::event(QEvent *event) +{ + return QAnimationGroup::event(event); +} + +void QSequentialAnimationGroupPrivate::setCurrentAnimation(int index, bool intermediate) +{ + Q_Q(QSequentialAnimationGroup); + + index = qMin(index, animations.count() - 1); + + if (index == -1) { + Q_ASSERT(animations.isEmpty()); + currentAnimationIndex = -1; + currentAnimation = 0; + return; + } + + // need these two checks below because this func can be called after the current animation + // has been removed + if (index == currentAnimationIndex && animations.at(index) == currentAnimation) + return; + + // stop the old current animation + if (currentAnimation) + currentAnimation->stop(); + + currentAnimation = animations.at(index); + currentAnimationIndex = index; + + emit q->currentAnimationChanged(currentAnimation); + + activateCurrentAnimation(intermediate); +} + +void QSequentialAnimationGroupPrivate::activateCurrentAnimation(bool intermediate) +{ + Q_Q(QSequentialAnimationGroup); + + if (!currentAnimation) + return; + + if (state == QSequentialAnimationGroup::Stopped) + return; + + currentAnimation->stop(); + + // we ensure the direction is consistent with the group's direction + currentAnimation->setDirection(direction); + + // connects to the finish signal of uncontrolled animations + if (currentAnimation->totalDuration() == -1) + QObject::connect(currentAnimation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished())); + + currentAnimation->start(); + if (!intermediate && state == QSequentialAnimationGroup::Paused) + currentAnimation->pause(); +} + +void QSequentialAnimationGroupPrivate::_q_uncontrolledAnimationFinished() +{ + Q_Q(QSequentialAnimationGroup); + Q_ASSERT(qobject_cast<QAbstractAnimation *>(q->sender()) == currentAnimation); + + // we trust the duration returned by the animation + while (actualDuration.size() < (currentAnimationIndex + 1)) + actualDuration.append(-1); + actualDuration[currentAnimationIndex] = currentAnimation->currentTime(); + + QObject::disconnect(currentAnimation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished())); + + if ((direction == QAbstractAnimation::Forward && currentAnimation == animations.last()) + || (direction == QAbstractAnimation::Backward && currentAnimationIndex == 0)) { + // we don't handle looping of a group with undefined duration + q->stop(); + } else if (direction == QAbstractAnimation::Forward) { + // set the current animation to be the next one + setCurrentAnimation(currentAnimationIndex + 1); + } else { + // set the current animation to be the previous one + setCurrentAnimation(currentAnimationIndex - 1); + } +} + +/*! + \internal + This method is called whenever an animation is added to + the group at index \a index. + Note: We only support insertion after the current animation +*/ +void QSequentialAnimationGroupPrivate::animationInsertedAt(int index) +{ + if (currentAnimation == 0) + setCurrentAnimation(0); // initialize the current animation + + if (currentAnimationIndex == index + && currentAnimation->currentTime() == 0 && currentAnimation->currentLoop() == 0) { + //in this case we simply insert an animation before the current one has actually started + setCurrentAnimation(index); + } + + //we update currentAnimationIndex in case it has changed (the animation pointer is still valid) + currentAnimationIndex = animations.indexOf(currentAnimation); + + if (index < currentAnimationIndex || currentLoop != 0) { + qWarning("QSequentialGroup::insertAnimationAt only supports to add animations after the current one."); + return; //we're not affected because it is added after the current one + } +} + +/*! + \internal + This method is called whenever an animation is removed from + the group at index \a index. The animation is no more listed when this + method is called. +*/ +void QSequentialAnimationGroupPrivate::animationRemovedAt(int index) +{ + Q_Q(QSequentialAnimationGroup); + QAnimationGroupPrivate::animationRemovedAt(index); + + Q_ASSERT(currentAnimation); // currentAnimation should always be set + + if (actualDuration.size() > index) + actualDuration.removeAt(index); + + const int currentIndex = animations.indexOf(currentAnimation); + if (currentIndex == -1) { + //we're removing the current animation, let's update it to another one + if (index < animations.count()) + setCurrentAnimation(index); //let's try to take the next one + else if (index > 0) + setCurrentAnimation(index - 1); + else// case all animations were removed + setCurrentAnimation(-1); + } else if (currentAnimationIndex > index) { + currentAnimationIndex--; + } + + // duration of the previous animations up to the current animation + currentTime = 0; + for (int i = 0; i < currentAnimationIndex; ++i) { + const int current = animationActualTotalDuration(i); + currentTime += current; + } + + if (currentIndex != -1) { + //the current animation is not the one being removed + //so we add its current time to the current time of this group + currentTime += QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime; + } + + //let's also update the total current time + totalCurrentTime = currentTime + loopCount * q->duration(); +} + +QT_END_NAMESPACE + +#include "moc_qsequentialanimationgroup.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qsequentialanimationgroup.h b/src/corelib/animation/qsequentialanimationgroup.h new file mode 100644 index 0000000..4701a76 --- /dev/null +++ b/src/corelib/animation/qsequentialanimationgroup.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSEQUENTIALANIMATIONGROUP_H +#define QSEQUENTIALANIMATIONGROUP_H + +#include <QtCore/qanimationgroup.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QPauseAnimation; +class QSequentialAnimationGroupPrivate; + +class Q_CORE_EXPORT QSequentialAnimationGroup : public QAnimationGroup +{ + Q_OBJECT + Q_PROPERTY(QAbstractAnimation* currentAnimation READ currentAnimation NOTIFY currentAnimationChanged) + +public: + QSequentialAnimationGroup(QObject *parent = 0); + ~QSequentialAnimationGroup(); + + QPauseAnimation *addPause(int msecs); + QPauseAnimation *insertPauseAt(int index, int msecs); + + QAbstractAnimation *currentAnimation() const; + int duration() const; + +Q_SIGNALS: + void currentAnimationChanged(QAbstractAnimation *current); + +protected: + QSequentialAnimationGroup(QSequentialAnimationGroupPrivate &dd, QObject *parent); + bool event(QEvent *event); + + void updateCurrentTime(int msecs); + void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + void updateDirection(QAbstractAnimation::Direction direction); + +private: + Q_DISABLE_COPY(QSequentialAnimationGroup) + Q_DECLARE_PRIVATE(QSequentialAnimationGroup) + Q_PRIVATE_SLOT(d_func(), void _q_uncontrolledAnimationFinished()) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QSEQUENTIALANIMATIONGROUP_H diff --git a/src/corelib/animation/qsequentialanimationgroup_p.h b/src/corelib/animation/qsequentialanimationgroup_p.h new file mode 100644 index 0000000..3ac90f8 --- /dev/null +++ b/src/corelib/animation/qsequentialanimationgroup_p.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSEQUENTIALANIMATIONGROUP_P_H +#define QSEQUENTIALANIMATIONGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qsequentialanimationgroup.h" +#include "qanimationgroup_p.h" + + +QT_BEGIN_NAMESPACE + +class QSequentialAnimationGroupPrivate : public QAnimationGroupPrivate +{ + Q_DECLARE_PUBLIC(QSequentialAnimationGroup) +public: + QSequentialAnimationGroupPrivate() + : currentAnimation(0), currentAnimationIndex(-1), lastLoop(0) + { } + + + struct AnimationIndex + { + AnimationIndex() : index(0), timeOffset(0) {} + // index points to the animation at timeOffset, skipping 0 duration animations. + // Note that the index semantic is slightly different depending on the direction. + int index; // the index of the animation in timeOffset + int timeOffset; // time offset when the animation at index starts. + }; + + int animationActualTotalDuration(int index) const; + AnimationIndex indexForTime(int msecs) const; + + void setCurrentAnimation(int index, bool intermediate = false); + void activateCurrentAnimation(bool intermediate = false); + + void animationInsertedAt(int index); + void animationRemovedAt(int index); + + bool atEnd() const; + + QAbstractAnimation *currentAnimation; + int currentAnimationIndex; + + // this is the actual duration of uncontrolled animations + // it helps seeking and even going forward + QList<int> actualDuration; + + void restart(); + int lastLoop; + + // handle time changes + void rewindForwards(const AnimationIndex &newAnimationIndex); + void advanceForwards(const AnimationIndex &newAnimationIndex); + + // private slot + void _q_uncontrolledAnimationFinished(); +}; + +QT_END_NAMESPACE + +#endif //QSEQUENTIALANIMATIONGROUP_P_H diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp new file mode 100644 index 0000000..e973ec5 --- /dev/null +++ b/src/corelib/animation/qvariantanimation.cpp @@ -0,0 +1,672 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_ANIMATION + +#include "qvariantanimation.h" +#include "qvariantanimation_p.h" + +#include <QtCore/QRect> +#include <QtCore/QLineF> +#include <QtCore/QLine> +#include <QtCore/QReadWriteLock> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QVariantAnimation + \ingroup animation + \brief The QVariantAnimation class provides an abstract base class for animations. + \since 4.6 + + This class is part of \l{The Animation Framework}. It serves as a + base class for property and item animations, with functions for + shared functionality. + + QVariantAnimation cannot be used directly as it is an abstract + class; it has a pure virtual method called updateCurrentValue(). + The class performs interpolation over + \l{QVariant}s, but leaves using the interpolated values to its + subclasses. Currently, Qt provides QPropertyAnimation, which + animates Qt \l{Qt's Property System}{properties}. See the + QPropertyAnimation class description if you wish to animate such + properties. + + You can then set start and end values for the property by calling + setStartValue() and setEndValue(), and finally call start() to + start the animation. QVariantAnimation will interpolate the + property of the target object and emit valueChanged(). To react to + a change in the current value you have to reimplement the + updateCurrentValue() virtual function. + + It is also possible to set values at specified steps situated + between the start and end value. The interpolation will then + touch these points at the specified steps. Note that the start and + end values are defined as the key values at 0.0 and 1.0. + + There are two ways to affect how QVariantAnimation interpolates + the values. You can set an easing curve by calling + setEasingCurve(), and configure the duration by calling + setDuration(). You can change how the QVariants are interpolated + by creating a subclass of QVariantAnimation, and reimplementing + the virtual interpolated() function. + + Subclassing QVariantAnimation can be an alternative if you have + \l{QVariant}s that you do not wish to declare as Qt properties. + Note, however, that you in most cases will be better off declaring + your QVariant as a property. + + Not all QVariant types are supported. Below is a list of currently + supported QVariant types: + + \list + \o \l{QMetaType::}{Int} + \o \l{QMetaType::}{Double} + \o \l{QMetaType::}{Float} + \o \l{QMetaType::}{QLine} + \o \l{QMetaType::}{QLineF} + \o \l{QMetaType::}{QPoint} + \o \l{QMetaType::}{QSize} + \o \l{QMetaType::}{QSizeF} + \o \l{QMetaType::}{QRect} + \o \l{QMetaType::}{QRectF} + \endlist + + If you need to interpolate other variant types, including custom + types, you have to implement interpolation for these yourself. + You do this by reimplementing interpolated(), which returns + interpolation values for the value being interpolated. + + \omit We need some snippets around here. \endomit + + \sa QPropertyAnimation, QAbstractAnimation, {The Animation Framework} +*/ + +/*! + \fn void QVariantAnimation::valueChanged(const QVariant &value) + + QVariantAnimation emits this signal whenever the current \a value changes. + + \sa currentValue, startValue, endValue +*/ + +/*! + \fn void QVariantAnimation::updateCurrentValue(const QVariant &value) = 0; + + This pure virtual function is called every time the animation's current + value changes. The \a value argument is the new current value. + + \sa currentValue +*/ + + +static bool animationValueLessThan(const QVariantAnimation::KeyValue &p1, const QVariantAnimation::KeyValue &p2) +{ + return p1.first < p2.first; +} + +static QVariant defaultInterpolator(const void *, const void *, qreal) +{ + return QVariant(); +} + +template<> Q_INLINE_TEMPLATE QRect _q_interpolate(const QRect &f, const QRect &t, qreal progress) +{ + QRect ret; + ret.setCoords(_q_interpolate(f.left(), t.left(), progress), + _q_interpolate(f.top(), t.top(), progress), + _q_interpolate(f.right(), t.right(), progress), + _q_interpolate(f.bottom(), t.bottom(), progress)); + return ret; +} + +template<> Q_INLINE_TEMPLATE QRectF _q_interpolate(const QRectF &f, const QRectF &t, qreal progress) +{ + qreal x1, y1, w1, h1; + f.getRect(&x1, &y1, &w1, &h1); + qreal x2, y2, w2, h2; + t.getRect(&x2, &y2, &w2, &h2); + return QRectF(_q_interpolate(x1, x2, progress), _q_interpolate(y1, y2, progress), + _q_interpolate(w1, w2, progress), _q_interpolate(h1, h2, progress)); +} + +template<> Q_INLINE_TEMPLATE QLine _q_interpolate(const QLine &f, const QLine &t, qreal progress) +{ + return QLine( _q_interpolate(f.p1(), t.p1(), progress), _q_interpolate(f.p2(), t.p2(), progress)); +} + +template<> Q_INLINE_TEMPLATE QLineF _q_interpolate(const QLineF &f, const QLineF &t, qreal progress) +{ + return QLineF( _q_interpolate(f.p1(), t.p1(), progress), _q_interpolate(f.p2(), t.p2(), progress)); +} + +QVariantAnimationPrivate::QVariantAnimationPrivate() : duration(250), hasStartValue(false), + interpolator(&defaultInterpolator), + changedSignalMask(1 << QVariantAnimation::staticMetaObject.indexOfSignal("valueChanged(QVariant)")) +{ + //we keep the mask so that we emit valueChanged only when needed (for performance reasons) +} + +void QVariantAnimationPrivate::convertValues(int t) +{ + //this ensures that all the keyValues are of type t + for (int i = 0; i < keyValues.count(); ++i) { + QVariantAnimation::KeyValue &pair = keyValues[i]; + pair.second.convert(static_cast<QVariant::Type>(t)); + } + //we also need update to the current interval if needed + currentInterval.start.second.convert(static_cast<QVariant::Type>(t)); + currentInterval.end.second.convert(static_cast<QVariant::Type>(t)); + + //... and the interpolator + updateInterpolator(); +} + +void QVariantAnimationPrivate::updateInterpolator() +{ + int type = currentInterval.start.second.userType(); + if (type == currentInterval.end.second.userType()) + interpolator = getInterpolator(type); + else + interpolator = 0; + + //we make sure that the interpolator is always set to something + if (!interpolator) + interpolator = &defaultInterpolator; +} + +/*! + \internal + The goal of this function is to update the currentInterval member. As a consequence, we also + need to update the currentValue. + Set \a force to true to always recalculate the interval. +*/ +void QVariantAnimationPrivate::recalculateCurrentInterval(bool force/*=false*/) +{ + // can't interpolate if we have only 1 key value + if (keyValues.count() <= 1) + return; + + const qreal progress = easing.valueForProgress(((duration == 0) ? qreal(1) : qreal(currentTime) / qreal(duration))); + + if (force || progress < currentInterval.start.first || progress > currentInterval.end.first) { + //let's update currentInterval + QVariantAnimation::KeyValues::const_iterator itStart = qLowerBound(keyValues.constBegin(), + keyValues.constEnd(), + qMakePair(progress, QVariant()), + animationValueLessThan); + QVariantAnimation::KeyValues::const_iterator itEnd = itStart; + + // If we are at the end we should continue to use the last keyValues in case of extrapolation (progress > 1.0). + // This is because the easing function can return a value slightly outside the range [0, 1] + if (itStart != keyValues.constEnd()) { + // this can't happen because we always prepend the default start value there + if (itStart == keyValues.constBegin()) { + ++itEnd; + } else { + --itStart; + } + + // update all the values of the currentInterval + currentInterval.start = *itStart; + currentInterval.end = *itEnd; + updateInterpolator(); + } + } + setCurrentValueForProgress(progress); +} + +void QVariantAnimationPrivate::setCurrentValueForProgress(const qreal progress) +{ + Q_Q(QVariantAnimation); + + const qreal startProgress = currentInterval.start.first; + const qreal endProgress = currentInterval.end.first; + const qreal localProgress = (progress - startProgress) / (endProgress - startProgress); + + QVariant ret = q->interpolated(currentInterval.start.second, + currentInterval.end.second, + localProgress); + qSwap(currentValue, ret); + q->updateCurrentValue(currentValue); + if ((connectedSignals & changedSignalMask) && currentValue != ret) { + //the value has changed + emit q->valueChanged(currentValue); + } +} + +QVariant QVariantAnimationPrivate::valueAt(qreal step) const +{ + QVariantAnimation::KeyValues::const_iterator result = + qBinaryFind(keyValues.begin(), keyValues.end(), qMakePair(step, QVariant()), animationValueLessThan); + if (result != keyValues.constEnd()) + return result->second; + + return QVariant(); +} + +void QVariantAnimationPrivate::setValueAt(qreal step, const QVariant &value) +{ + if (step < qreal(0.0) || step > qreal(1.0)) { + qWarning("QVariantAnimation::setValueAt: invalid step = %f", step); + return; + } + + QVariantAnimation::KeyValue pair(step, value); + + QVariantAnimation::KeyValues::iterator result = qLowerBound(keyValues.begin(), keyValues.end(), pair, animationValueLessThan); + if (result == keyValues.end() || result->first != step) { + keyValues.insert(result, pair); + } else { + if (value.isValid()) + result->second = value; // replaces the previous value + else if (step == 0 && !hasStartValue && defaultStartValue.isValid()) + result->second = defaultStartValue; // resets to the default start value + else + keyValues.erase(result); // removes the previous value + } + + recalculateCurrentInterval(/*force=*/true); +} + +void QVariantAnimationPrivate::setDefaultStartValue(const QVariant &value) +{ + defaultStartValue = value; + if (!hasStartValue) + setValueAt(0, value); +} + +/*! + Construct a QVariantAnimation object. \a parent is passed to QAbstractAnimation's + constructor. +*/ +QVariantAnimation::QVariantAnimation(QObject *parent) : QAbstractAnimation(*new QVariantAnimationPrivate, parent) +{ +} + +/*! + \internal +*/ +QVariantAnimation::QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent) : QAbstractAnimation(dd, parent) +{ +} + +/*! + Destroys the animation. +*/ +QVariantAnimation::~QVariantAnimation() +{ +} + +/*! + \property QVariantAnimation::easingCurve + \brief the easing curve of the animation + + This property defines the easing curve of the animation. By + default, a linear easing curve is used, resulting in linear + interpolation. Other curves are provided, for instance, + QEasingCurve::InCirc, which provides a circular entry curve. + Another example is QEasingCurve::InOutElastic, which provides an + elastic effect on the values of the interpolated variant. + + The easing curve is used with the interpolator, the interpolated() + virtual function, the animation's duration, and iterationCount, to + control how the current value changes as the animation progresses. +*/ +QEasingCurve QVariantAnimation::easingCurve() const +{ + Q_D(const QVariantAnimation); + return d->easing; +} + +void QVariantAnimation::setEasingCurve(const QEasingCurve &easing) +{ + Q_D(QVariantAnimation); + d->easing = easing; + d->recalculateCurrentInterval(); +} + +Q_GLOBAL_STATIC(QVector<QVariantAnimation::Interpolator>, registeredInterpolators) +Q_GLOBAL_STATIC(QReadWriteLock, registeredInterpolatorsLock) + +/*! + \fn void qRegisterAnimationInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) + \relates QVariantAnimation + \threadsafe + + Registers a custom interpolator \a func for the template type \c{T}. + The interpolator has to be registered before the animation is constructed. + To unregister (and use the default interpolator) set \a func to 0. + */ + +/*! + \internal + \typedef QVariantAnimation::Interpolator + + This is a typedef for a pointer to a function with the following + signature: + \code + QVariant myInterpolator(const QVariant &from, const QVariant &to, qreal progress); + \endcode + +*/ + +/*! \internal + * Registers a custom interpolator \a func for the specific \a interpolationType. + * The interpolator has to be registered before the animation is constructed. + * To unregister (and use the default interpolator) set \a func to 0. + */ +void QVariantAnimation::registerInterpolator(QVariantAnimation::Interpolator func, int interpolationType) +{ + // will override any existing interpolators + QWriteLocker locker(registeredInterpolatorsLock()); + if (int(interpolationType) >= registeredInterpolators()->count()) + registeredInterpolators()->resize(int(interpolationType) + 1); + registeredInterpolators()->replace(interpolationType, func); +} + + +template<typename T> static inline QVariantAnimation::Interpolator castToInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) +{ + return reinterpret_cast<QVariantAnimation::Interpolator>(func); +} + +QVariantAnimation::Interpolator QVariantAnimationPrivate::getInterpolator(int interpolationType) +{ + QReadLocker locker(registeredInterpolatorsLock()); + QVariantAnimation::Interpolator ret = 0; + if (interpolationType < registeredInterpolators()->count()) { + ret = registeredInterpolators()->at(interpolationType); + if (ret) return ret; + } + + switch(interpolationType) + { + case QMetaType::Int: + return castToInterpolator(_q_interpolateVariant<int>); + case QMetaType::Double: + return castToInterpolator(_q_interpolateVariant<double>); + case QMetaType::Float: + return castToInterpolator(_q_interpolateVariant<float>); + case QMetaType::QLine: + return castToInterpolator(_q_interpolateVariant<QLine>); + case QMetaType::QLineF: + return castToInterpolator(_q_interpolateVariant<QLineF>); + case QMetaType::QPoint: + return castToInterpolator(_q_interpolateVariant<QPoint>); + case QMetaType::QPointF: + return castToInterpolator(_q_interpolateVariant<QPointF>); + case QMetaType::QSize: + return castToInterpolator(_q_interpolateVariant<QSize>); + case QMetaType::QSizeF: + return castToInterpolator(_q_interpolateVariant<QSizeF>); + case QMetaType::QRect: + return castToInterpolator(_q_interpolateVariant<QRect>); + case QMetaType::QRectF: + return castToInterpolator(_q_interpolateVariant<QRectF>); + default: + return 0; //this type is not handled + } +} + +/*! + \property QVariantAnimation::duration + \brief the duration of the animation + + This property describes the duration in milliseconds of the + animation. The default duration is 250 milliseconds. + + \sa QAbstractAnimation::duration() + */ +int QVariantAnimation::duration() const +{ + Q_D(const QVariantAnimation); + return d->duration; +} + +void QVariantAnimation::setDuration(int msecs) +{ + Q_D(QVariantAnimation); + if (msecs < 0) { + qWarning("QVariantAnimation::setDuration: cannot set a negative duration"); + return; + } + if (d->duration == msecs) + return; + d->duration = msecs; + d->recalculateCurrentInterval(); +} + +/*! + \property QVariantAnimation::startValue + \brief the optional start value of the animation + + This property describes the optional start value of the animation. If + omitted, or if a null QVariant is assigned as the start value, the + animation will use the current position of the end when the animation + is started. + + \sa endValue +*/ +QVariant QVariantAnimation::startValue() const +{ + return keyValueAt(0); +} + +void QVariantAnimation::setStartValue(const QVariant &value) +{ + setKeyValueAt(0, value); +} + +/*! + \property QVariantAnimation::endValue + \brief the end value of the animation + + This property describes the end value of the animation. + + \sa startValue + */ +QVariant QVariantAnimation::endValue() const +{ + return keyValueAt(1); +} + +void QVariantAnimation::setEndValue(const QVariant &value) +{ + setKeyValueAt(1, value); +} + + +/*! + Returns the key frame value for the given \a step. The given \a step + must be in the range 0 to 1. If there is no KeyValue for \a step, + it returns an invalid QVariant. + + \sa keyValues(), setKeyValueAt() +*/ +QVariant QVariantAnimation::keyValueAt(qreal step) const +{ + Q_D(const QVariantAnimation); + if (step == 0 && !d->hasStartValue) + return QVariant(); //special case where we don't have an explicit startValue + + return d->valueAt(step); +} + +/*! + \typedef QVariantAnimation::KeyValue + + This is a typedef for QPair<qreal, QVariant>. +*/ +/*! + \typedef QVariantAnimation::KeyValues + + This is a typedef for QVector<KeyValue> +*/ + +/*! + Creates a key frame at the given \a step with the given \a value. + The given \a step must be in the range 0 to 1. + + \sa setKeyValues(), keyValueAt() +*/ +void QVariantAnimation::setKeyValueAt(qreal step, const QVariant &value) +{ + Q_D(QVariantAnimation); + if (step == 0) + d->hasStartValue = value.isValid(); + d->setValueAt(step, value); +} + +/*! + Returns the key frames of this animation. + + \sa keyValueAt(), setKeyValues() +*/ +QVariantAnimation::KeyValues QVariantAnimation::keyValues() const +{ + Q_D(const QVariantAnimation); + QVariantAnimation::KeyValues ret = d->keyValues; + //in case we added the default start value, we remove it + if (!d->hasStartValue && !ret.isEmpty() && ret.at(0).first == 0) + ret.remove(0); + return ret; +} + +/*! + Replaces the current set of key frames with the given \a keyValues. + the step of the key frames must be in the range 0 to 1. + + \sa keyValues(), keyValueAt() +*/ +void QVariantAnimation::setKeyValues(const KeyValues &keyValues) +{ + Q_D(QVariantAnimation); + d->keyValues = keyValues; + qSort(d->keyValues.begin(), d->keyValues.end(), animationValueLessThan); + d->hasStartValue = !d->keyValues.isEmpty() && d->keyValues.at(0).first == 0; + d->recalculateCurrentInterval(/*force=*/true); +} + +/*! + \property QVariantAnimation::currentValue + \brief the current value of the animation. + + This property describes the current value; an interpolated value + between the \l{startValue}{start value} and the \l{endValue}{end + value}, using the current time for progress. The value itself is + obtained from interpolated(), which is called repeatedly as the + animation is running. + + QVariantAnimation calls the virtual updateCurrentValue() function + when the current value changes. This is particularly useful for + subclasses that need to track updates. For example, + QPropertyAnimation uses this function to animate Qt \l{Qt's + Property System}{properties}. + + \sa startValue, endValue +*/ +QVariant QVariantAnimation::currentValue() const +{ + Q_D(const QVariantAnimation); + if (!d->currentValue.isValid()) + const_cast<QVariantAnimationPrivate*>(d)->recalculateCurrentInterval(); + return d->currentValue; +} + +/*! + \reimp + */ +bool QVariantAnimation::event(QEvent *event) +{ + return QAbstractAnimation::event(event); +} + +/*! + \reimp +*/ +void QVariantAnimation::updateState(QAbstractAnimation::State oldState, + QAbstractAnimation::State newState) +{ + Q_UNUSED(oldState); + Q_UNUSED(newState); +} + +/*! + + This virtual function returns the linear interpolation between + variants \a from and \a to, at \a progress, usually a value + between 0 and 1. You can reimplement this function in a subclass + of QVariantAnimation to provide your own interpolation algorithm. + + Note that in order for the interpolation to work with a + QEasingCurve that return a value smaller than 0 or larger than 1 + (such as QEasingCurve::InBack) you should make sure that it can + extrapolate. If the semantic of the datatype does not allow + extrapolation this function should handle that gracefully. + + You should call the QVariantAnimation implementation of this + function if you want your class to handle the types already + supported by Qt (see class QVariantAnimation description for a + list of supported types). + + \sa QEasingCurve + */ +QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const +{ + return d_func()->interpolator(from.constData(), to.constData(), progress); +} + +/*! + \reimp + */ +void QVariantAnimation::updateCurrentTime(int msecs) +{ + Q_UNUSED(msecs); + d_func()->recalculateCurrentInterval(); +} + +QT_END_NAMESPACE + +#include "moc_qvariantanimation.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qvariantanimation.h b/src/corelib/animation/qvariantanimation.h new file mode 100644 index 0000000..3ae172f --- /dev/null +++ b/src/corelib/animation/qvariantanimation.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANIMATION_H +#define QANIMATION_H + +#include <QtCore/qeasingcurve.h> +#include <QtCore/qabstractanimation.h> +#include <QtCore/qvector.h> +#include <QtCore/qvariant.h> +#include <QtCore/qpair.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QVariantAnimationPrivate; +class Q_CORE_EXPORT QVariantAnimation : public QAbstractAnimation +{ + Q_OBJECT + Q_PROPERTY(QVariant startValue READ startValue WRITE setStartValue) + Q_PROPERTY(QVariant endValue READ endValue WRITE setEndValue) + Q_PROPERTY(QVariant currentValue READ currentValue NOTIFY currentValueChanged) + Q_PROPERTY(int duration READ duration WRITE setDuration) + Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve) + +public: + typedef QPair<qreal, QVariant> KeyValue; + typedef QVector<KeyValue> KeyValues; + + QVariantAnimation(QObject *parent = 0); + ~QVariantAnimation(); + + QVariant startValue() const; + void setStartValue(const QVariant &value); + + QVariant endValue() const; + void setEndValue(const QVariant &value); + + QVariant keyValueAt(qreal step) const; + void setKeyValueAt(qreal step, const QVariant &value); + + KeyValues keyValues() const; + void setKeyValues(const KeyValues &values); + + QVariant currentValue() const; + + int duration() const; + void setDuration(int msecs); + + QEasingCurve easingCurve() const; + void setEasingCurve(const QEasingCurve &easing); + + typedef QVariant (*Interpolator)(const void *from, const void *to, qreal progress); + +Q_SIGNALS: + void valueChanged(const QVariant &value); + +protected: + QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent = 0); + bool event(QEvent *event); + + void updateCurrentTime(int msecs); + void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + + virtual void updateCurrentValue(const QVariant &value) = 0; + virtual QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) const; + +private: + template <typename T> friend void qRegisterAnimationInterpolator(QVariant (*func)(const T &, const T &, qreal)); + static void registerInterpolator(Interpolator func, int interpolationType); + + Q_DISABLE_COPY(QVariantAnimation) + Q_DECLARE_PRIVATE(QVariantAnimation) +}; + +template <typename T> +void qRegisterAnimationInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) { + QVariantAnimation::registerInterpolator(reinterpret_cast<QVariantAnimation::Interpolator>(func), qMetaTypeId<T>()); +} + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QANIMATION_H diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/animation/qvariantanimation_p.h index 7d66581..aee2324 100644 --- a/src/corelib/io/qfileinfo_p.h +++ b/src/corelib/animation/qvariantanimation_p.h @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef QFILEINFO_P_H -#define QFILEINFO_P_H +#ifndef QANIMATION_P_H +#define QANIMATION_P_H // // W A R N I N G @@ -53,93 +53,71 @@ // We mean it. // -#include "qfileinfo.h" +#include "qvariantanimation.h" +#include <QtCore/qeasingcurve.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qvector.h> + +#include "qabstractanimation_p.h" QT_BEGIN_NAMESPACE -class QFileInfoPrivate +class QVariantAnimationPrivate : public QAbstractAnimationPrivate { + Q_DECLARE_PUBLIC(QVariantAnimation) public: - QFileInfoPrivate(const QFileInfo *copy=0); - ~QFileInfoPrivate(); - - void initFileEngine(const QString &); - - enum Access { - ReadAccess, - WriteAccess, - ExecuteAccess - }; - bool hasAccess(Access access) const; - - uint getFileFlags(QAbstractFileEngine::FileFlags) const; - QDateTime &getFileTime(QAbstractFileEngine::FileTime) const; - QString getFileName(QAbstractFileEngine::FileName) const; - - enum { - CachedFileFlags = 0x01, - CachedLinkTypeFlag = 0x02, - CachedBundleTypeFlag= 0x04, - CachedMTime = 0x10, - CachedCTime = 0x20, - CachedATime = 0x40, - CachedSize = 0x08 - }; - - struct Data + + QVariantAnimationPrivate(); + + static QVariantAnimationPrivate *get(QVariantAnimation *q) { - inline Data() - : ref(1), fileEngine(0), cache_enabled(1) - { - clear(); - } - - inline Data(const Data ©) - : ref(1), fileEngine(QAbstractFileEngine::create(copy.fileName)), - fileName(copy.fileName), cache_enabled(copy.cache_enabled) - { - clear(); - } - - inline ~Data() - { - delete fileEngine; - } - - inline void clear() - { - fileNames.clear(); - fileFlags = 0; - cachedFlags = 0; - } - - mutable QAtomicInt ref; - - QAbstractFileEngine *fileEngine; - mutable QString fileName; - mutable QHash<int, QString> fileNames; - mutable uint cachedFlags : 31; - mutable uint cache_enabled : 1; - mutable uint fileFlags; - mutable qint64 fileSize; - mutable QDateTime fileTimes[3]; - - inline bool getCachedFlag(uint c) const - { return cache_enabled ? (cachedFlags & c) : 0; } - - inline void setCachedFlag(uint c) - { if (cache_enabled) cachedFlags |= c; } - } *data; - - inline void reset() { - detach(); - data->clear(); + return q->d_func(); } - void detach(); + void setDefaultStartValue(const QVariant &value); + + int duration; + QEasingCurve easing; + + QVariantAnimation::KeyValues keyValues; + QVariant currentValue; + QVariant defaultStartValue; + bool hasStartValue; + + //this is used to keep track of the KeyValue interval in which we currently are + struct + { + QVariantAnimation::KeyValue start, end; + } currentInterval; + + QVariantAnimation::Interpolator interpolator; + + const quint32 changedSignalMask; + + void setCurrentValueForProgress(const qreal progress); + void recalculateCurrentInterval(bool force=false); + void setValueAt(qreal, const QVariant &); + QVariant valueAt(qreal step) const; + void convertValues(int t); + + void updateInterpolator(); + + //XXX this is needed by dui + static Q_CORE_EXPORT QVariantAnimation::Interpolator getInterpolator(int interpolationType); }; +//this should make the interpolation faster +template<typename T> inline T _q_interpolate(const T &f, const T &t, qreal progress) +{ + return T(f + (t - f) * progress); +} + +template<typename T > inline QVariant _q_interpolateVariant(const T &from, const T &to, qreal progress) +{ + return _q_interpolate(from, to, progress); +} + QT_END_NAMESPACE -#endif +#endif //QANIMATION_P_H diff --git a/src/corelib/arch/qatomic_mips.h b/src/corelib/arch/qatomic_mips.h index b263aab..ea9954b 100644 --- a/src/corelib/arch/qatomic_mips.h +++ b/src/corelib/arch/qatomic_mips.h @@ -103,16 +103,25 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree() #if defined(Q_CC_GNU) && !defined(Q_OS_IRIX) +#if _MIPS_SIM == _ABIO32 +#define SET_MIPS2 ".set mips2\n\t" +#else +#define SET_MIPS2 +#endif + inline bool QBasicAtomicInt::ref() { register int originalValue; register int newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "addiu %[newValue], %[originalValue], %[one]\n" "sc %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -125,12 +134,15 @@ inline bool QBasicAtomicInt::deref() { register int originalValue; register int newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "addiu %[newValue], %[originalValue], %[minusOne]\n" "sc %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -143,7 +155,9 @@ inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) { register int result; register int tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" "bnez %[result], 0f\n" @@ -153,6 +167,7 @@ inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) "beqz %[tempValue], 0b\n" "nop\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -166,7 +181,9 @@ inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) { register int result; register int tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" "bnez %[result], 0f\n" @@ -177,6 +194,7 @@ inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) "nop\n" "sync\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -190,7 +208,9 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) { register int result; register int tempValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" "ll %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" @@ -201,6 +221,7 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) "beqz %[tempValue], 0b\n" "nop\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -219,12 +240,15 @@ inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) { register int originalValue; register int tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" "sc %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -237,13 +261,16 @@ inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) { register int originalValue; register int tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" "sc %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" "sync\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -256,13 +283,16 @@ inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) { register int originalValue; register int tempValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" "ll %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" "sc %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -280,12 +310,15 @@ inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) { register int originalValue; register int newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" "sc %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -298,13 +331,16 @@ inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) { register int originalValue; register int newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" "sc %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" "sync\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -317,13 +353,16 @@ inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) { register int originalValue; register int newValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" "ll %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" "sc %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -350,7 +389,9 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValu { register T *result; register T *tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" "bnez %[result], 0f\n" @@ -360,6 +401,7 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValu "beqz %[tempValue], 0b\n" "nop\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -374,7 +416,9 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValu { register T *result; register T *tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" "bnez %[result], 0f\n" @@ -385,6 +429,7 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValu "nop\n" "sync\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -399,7 +444,9 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValu { register T *result; register T *tempValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" LLP" %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" @@ -410,6 +457,7 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValu "beqz %[tempValue], 0b\n" "nop\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -430,12 +478,15 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue) { register T *originalValue; register T *tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" SCP" %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -449,13 +500,16 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreAcquire(T *newValue) { register T *originalValue; register T *tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" SCP" %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" "sync\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -469,13 +523,16 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelease(T *newValue) { register T *originalValue; register T *tempValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" LLP" %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" SCP" %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -495,12 +552,15 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelaxed(qptrdiff valueTo { register T *originalValue; register T *newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" SCP" %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -514,13 +574,16 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddAcquire(qptrdiff valueTo { register T *originalValue; register T *newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" SCP" %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" "sync\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -534,13 +597,16 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelease(qptrdiff valueTo { register T *originalValue; register T *newValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" LLP" %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" SCP" %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) diff --git a/src/corelib/codecs/qtsciicodec_p.h b/src/corelib/codecs/qtsciicodec_p.h index 8f11e48..425e7fd 100644 --- a/src/corelib/codecs/qtsciicodec_p.h +++ b/src/corelib/codecs/qtsciicodec_p.h @@ -88,7 +88,7 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_CODECS -class Q_CORE_EXPORT QTsciiCodec : public QTextCodec { +class QTsciiCodec : public QTextCodec { public: ~QTsciiCodec(); diff --git a/src/corelib/concurrent/qfutureinterface.h b/src/corelib/concurrent/qfutureinterface.h index 85d03c9..345bebe 100644 --- a/src/corelib/concurrent/qfutureinterface.h +++ b/src/corelib/concurrent/qfutureinterface.h @@ -165,6 +165,8 @@ public: QFutureInterface &operator=(const QFutureInterface &other) { + if (referenceCountIsOne()) + resultStore().clear(); QFutureInterfaceBase::operator=(other); return *this; } diff --git a/src/corelib/concurrent/qfuturewatcher.cpp b/src/corelib/concurrent/qfuturewatcher.cpp index ea35e9e..39d7698 100644 --- a/src/corelib/concurrent/qfuturewatcher.cpp +++ b/src/corelib/concurrent/qfuturewatcher.cpp @@ -465,7 +465,7 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event) break; emit q->progressValueChanged(event->index1); - if (event->text != QString()) // ### + if (!event->text.isNull()) // ### q->progressTextChanged(event->text); break; case QFutureCallOutEvent::ProgressRange: diff --git a/src/corelib/concurrent/qfuturewatcher_p.h b/src/corelib/concurrent/qfuturewatcher_p.h index 324839d..d53a1bd 100644 --- a/src/corelib/concurrent/qfuturewatcher_p.h +++ b/src/corelib/concurrent/qfuturewatcher_p.h @@ -63,8 +63,8 @@ QT_BEGIN_NAMESPACE class QFutureWatcherBase; -class Q_CORE_EXPORT QFutureWatcherBasePrivate : public QObjectPrivate, - public QFutureCallOutInterface +class QFutureWatcherBasePrivate : public QObjectPrivate, + public QFutureCallOutInterface { Q_DECLARE_PUBLIC(QFutureWatcherBase) diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index f99d57f..db51d43 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -5,6 +5,7 @@ DEFINES += QT_BUILD_CORE_LIB QT_NO_USING_NAMESPACE win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x67000000 include(../qbase.pri) +include(animation/animation.pri) include(arch/arch.pri) include(concurrent/concurrent.pri) include(global/global.pri) @@ -14,6 +15,7 @@ include(io/io.pri) include(plugin/plugin.pri) include(kernel/kernel.pri) include(codecs/codecs.pri) +include(statemachine/statemachine.pri) include(xml/xml.pri) mac|darwin:LIBS += -framework ApplicationServices diff --git a/src/corelib/global/qfeatures.txt b/src/corelib/global/qfeatures.txt index 5d63e46..23ec7b0 100644 --- a/src/corelib/global/qfeatures.txt +++ b/src/corelib/global/qfeatures.txt @@ -1157,6 +1157,14 @@ Requires: PROPERTIES Name: Accessibility SeeAlso: ??? +Feature: ANIMATION +Description: Provides a framework for animations. +Section: Utilities +Requires: PROPERTIES +Name: Animation +SeeAlso: ??? + + # SVG Feature: SVG diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index ce98ec4..763935e 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -125,7 +125,8 @@ QT_BEGIN_NAMESPACE If you want to use QFlags for your own enum types, use the Q_DECLARE_FLAGS() and Q_DECLARE_OPERATORS_FOR_FLAGS(). - For example: + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 1 @@ -442,14 +443,18 @@ QT_BEGIN_NAMESPACE function. You can retrieve the minimum and maximum of two given objects using qMin() and qMax() respectively. All these functions return a corresponding template type; the template types can be - replaced by any other type. For example: + replaced by any other type. + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 3 <QtGlobal> also contains functions that generate messages from the given string argument: qCritical(), qDebug(), qFatal() and qWarning(). These functions call the message handler with the - given message. For example: + given message. + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 4 @@ -694,7 +699,9 @@ QT_BEGIN_NAMESPACE \relates <QtGlobal> Wraps the signed 64-bit integer \a literal in a - platform-independent way. For example: + platform-independent way. + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 8 @@ -705,7 +712,9 @@ QT_BEGIN_NAMESPACE \relates <QtGlobal> Wraps the unsigned 64-bit integer \a literal in a - platform-independent way. For example: + platform-independent way. + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 9 @@ -734,7 +743,11 @@ QT_BEGIN_NAMESPACE /*! \fn const T &qAbs(const T &value) \relates <QtGlobal> - Returns the absolute value of \a value. For example: + Compares \a value to the 0 of type T and returns the absolute + value. Thus if T is \e {double}, then \a value is compared to + \e{(double) 0}. + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 10 */ @@ -742,7 +755,9 @@ QT_BEGIN_NAMESPACE /*! \fn int qRound(qreal value) \relates <QtGlobal> - Rounds \a value to the nearest integer. For example: + Rounds \a value to the nearest integer. + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 11 */ @@ -750,7 +765,9 @@ QT_BEGIN_NAMESPACE /*! \fn qint64 qRound64(qreal value) \relates <QtGlobal> - Rounds \a value to the nearest 64-bit integer. For example: + Rounds \a value to the nearest 64-bit integer. + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 12 */ @@ -758,7 +775,9 @@ QT_BEGIN_NAMESPACE /*! \fn const T &qMin(const T &value1, const T &value2) \relates <QtGlobal> - Returns the minimum of \a value1 and \a value2. For example: + Returns the minimum of \a value1 and \a value2. + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 13 @@ -768,7 +787,9 @@ QT_BEGIN_NAMESPACE /*! \fn const T &qMax(const T &value1, const T &value2) \relates <QtGlobal> - Returns the maximum of \a value1 and \a value2. For example: + Returns the maximum of \a value1 and \a value2. + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 14 @@ -779,7 +800,9 @@ QT_BEGIN_NAMESPACE \relates <QtGlobal> Returns \a value bounded by \a min and \a max. This is equivalent - to qMax(\a min, qMin(\a value, \a max)). For example: + to qMax(\a min, qMin(\a value, \a max)). + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 15 @@ -925,7 +948,9 @@ QT_BEGIN_NAMESPACE 4.1.2, the QT_VERSION macro will expand to 0x040102. You can use QT_VERSION to use the latest Qt features where - available. For example: + available. + + Example: \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 16 @@ -1985,7 +2010,7 @@ void qt_message_output(QtMsgType msgType, const char *buf) mac_default_handler(buf); #elif defined(Q_OS_WINCE) QString fstr = QString::fromLatin1(buf); - fstr += QLatin1String("\n"); + fstr += QLatin1Char('\n'); OutputDebugString(reinterpret_cast<const wchar_t *> (fstr.utf16())); #else fprintf(stderr, "%s\n", buf); @@ -2243,7 +2268,7 @@ bool qputenv(const char *varName, const QByteArray& value) return _putenv_s(varName, value.constData()) == 0; #else QByteArray buffer(varName); - buffer += "="; + buffer += '='; buffer += value; return putenv(qstrdup(buffer.constData())) == 0; #endif diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index 29e356e..7f6ff20 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -434,14 +434,14 @@ QLibraryInfo::location(LibraryLocation loc) #else if (QCoreApplication::instance()) { #ifdef Q_OS_MAC - CFBundleRef bundleRef = CFBundleGetMainBundle(); - if (bundleRef) { - QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef); - if (urlRef) { - QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle); - return QDir::cleanPath(path + QLatin1String("/Contents")); - } - } + CFBundleRef bundleRef = CFBundleGetMainBundle(); + if (bundleRef) { + QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef); + if (urlRef) { + QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle); + return QDir::cleanPath(path + QLatin1String("/Contents/") + ret); + } + } #endif return QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(ret); } else { diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 4873b17..9e53d89 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -504,6 +504,7 @@ public: AA_DontCreateNativeWidgetSiblings = 4, AA_MacPluginApplication = 5, AA_DontUseNativeMenuBar = 6, + AA_MacDontSwapCtrlAndMeta = 7, // Add new attributes before this line AA_AttributeCount @@ -1326,7 +1327,8 @@ public: DirectConnection, QueuedConnection, AutoCompatConnection, - BlockingQueuedConnection + BlockingQueuedConnection, + UniqueConnection = 0x80 }; enum ShortcutContext { diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 3690d4b..8f37e25 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -10,9 +10,9 @@ HEADERS += \ io/qdiriterator.h \ io/qfile.h \ io/qfileinfo.h \ - io/qfileinfo_p.h \ io/qiodevice.h \ io/qiodevice_p.h \ + io/qnoncontiguousbytedevice_p.h \ io/qprocess.h \ io/qprocess_p.h \ io/qtextstream.h \ @@ -38,6 +38,7 @@ SOURCES += \ io/qfile.cpp \ io/qfileinfo.cpp \ io/qiodevice.cpp \ + io/qnoncontiguousbytedevice.cpp \ io/qprocess.cpp \ io/qtextstream.cpp \ io/qtemporaryfile.cpp \ diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 9990696..e324ffe 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -514,7 +514,7 @@ void QDataStream::setByteOrder(ByteOrder bo) \value Qt_4_2 Version 8 (Qt 4.2) \value Qt_4_3 Version 9 (Qt 4.3) \value Qt_4_4 Version 10 (Qt 4.4) - \value Qt_4_5 Version 10 (Qt 4.5) + \value Qt_4_5 Version 11 (Qt 4.5) \omitvalue Qt_4_6 \sa setVersion(), version() @@ -622,11 +622,16 @@ QDataStream &QDataStream::operator>>(qint16 &i) setStatus(ReadPastEnd); } } else { - register uchar *p = (uchar *)(&i); + union { + qint16 val1; + char val2[2]; + } x; + char *p = x.val2; char b[2]; if (dev->read(b, 2) == 2) { *p++ = b[1]; *p = b[0]; + i = x.val1; } else { setStatus(ReadPastEnd); } @@ -660,13 +665,18 @@ QDataStream &QDataStream::operator>>(qint32 &i) setStatus(ReadPastEnd); } } else { // swap bytes - uchar *p = (uchar *)(&i); + union { + qint32 val1; + char val2[4]; + } x; + char *p = x.val2; char b[4]; if (dev->read(b, 4) == 4) { *p++ = b[3]; *p++ = b[2]; *p++ = b[1]; *p = b[0]; + i = x.val1; } else { setStatus(ReadPastEnd); } @@ -703,7 +713,12 @@ QDataStream &QDataStream::operator>>(qint64 &i) setStatus(ReadPastEnd); } } else { // swap bytes - uchar *p = (uchar *)(&i); + union { + qint64 val1; + char val2[8]; + } x; + + char *p = x.val2; char b[8]; if (dev->read(b, 8) == 8) { *p++ = b[7]; @@ -714,6 +729,7 @@ QDataStream &QDataStream::operator>>(qint64 &i) *p++ = b[2]; *p++ = b[1]; *p = b[0]; + i = x.val1; } else { setStatus(ReadPastEnd); } @@ -751,13 +767,19 @@ QDataStream &QDataStream::operator>>(float &f) setStatus(ReadPastEnd); } } else { // swap bytes - uchar *p = (uchar *)(&f); + union { + float val1; + char val2[4]; + } x; + + char *p = x.val2; char b[4]; if (dev->read(b, 4) == 4) { *p++ = b[3]; *p++ = b[2]; *p++ = b[1]; *p = b[0]; + f = x.val1; } else { setStatus(ReadPastEnd); } @@ -788,7 +810,11 @@ QDataStream &QDataStream::operator>>(double &f) setStatus(ReadPastEnd); } } else { // swap bytes - register uchar *p = (uchar *)(&f); + union { + double val1; + char val2[8]; + } x; + char *p = x.val2; char b[8]; if (dev->read(b, 8) == 8) { *p++ = b[7]; @@ -799,13 +825,18 @@ QDataStream &QDataStream::operator>>(double &f) *p++ = b[2]; *p++ = b[1]; *p = b[0]; + f = x.val1; } else { setStatus(ReadPastEnd); } } #else //non-standard floating point format - register uchar *p = (uchar *)(&f); + union { + double val1; + char val2[8]; + } x; + char *p = x.val2; char b[8]; if (dev->read(b, 8) == 8) { if (noswap) { @@ -827,6 +858,7 @@ QDataStream &QDataStream::operator>>(double &f) *p++ = b[Q_DF(1)]; *p = b[Q_DF(0)]; } + f = x.val1; } else { setStatus(ReadPastEnd); } @@ -970,7 +1002,12 @@ QDataStream &QDataStream::operator<<(qint16 i) if (noswap) { dev->write((char *)&i, sizeof(qint16)); } else { // swap bytes - register uchar *p = (uchar *)(&i); + union { + qint16 val1; + char val2[2]; + } x; + x.val1 = i; + char *p = x.val2; char b[2]; b[1] = *p++; b[0] = *p; @@ -992,7 +1029,12 @@ QDataStream &QDataStream::operator<<(qint32 i) if (noswap) { dev->write((char *)&i, sizeof(qint32)); } else { // swap bytes - register uchar *p = (uchar *)(&i); + union { + qint32 val1; + char val2[4]; + } x; + x.val1 = i; + char *p = x.val2; char b[4]; b[3] = *p++; b[2] = *p++; @@ -1022,13 +1064,18 @@ QDataStream &QDataStream::operator<<(qint64 i) { CHECK_STREAM_PRECOND(*this) if (version() < 6) { - quint32 i1 = i & 0xffffffff; - quint32 i2 = i >> 32; - *this << i2 << i1; + quint32 i1 = i & 0xffffffff; + quint32 i2 = i >> 32; + *this << i2 << i1; } else if (noswap) { // no conversion needed dev->write((char *)&i, sizeof(qint64)); } else { // swap bytes - register uchar *p = (uchar *)(&i); + union { + qint64 val1; + char val2[8]; + } x; + x.val1 = i; + char *p = x.val2; char b[8]; b[7] = *p++; b[6] = *p++; @@ -1077,7 +1124,12 @@ QDataStream &QDataStream::operator<<(float f) if (noswap) { // no conversion needed dev->write((char *)&g, sizeof(float)); } else { // swap bytes - register uchar *p = (uchar *)(&g); + union { + float val1; + char val2[4]; + } x; + x.val1 = f; + char *p = x.val2; char b[4]; b[3] = *p++; b[2] = *p++; @@ -1103,7 +1155,12 @@ QDataStream &QDataStream::operator<<(double f) if (noswap) { dev->write((char *)&f, sizeof(double)); } else { - register uchar *p = (uchar *)(&f); + union { + double val1; + char val2[8]; + } x; + x.val1 = f; + char *p = x.val2; char b[8]; b[7] = *p++; b[6] = *p++; @@ -1116,7 +1173,12 @@ QDataStream &QDataStream::operator<<(double f) dev->write(b, 8); } #else - register uchar *p = (uchar *)(&f); + union { + double val1; + char val2[8]; + } x; + x.val1 = f; + char *p = x.val2; char b[8]; if (noswap) { b[Q_DF(0)] = *p++; diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 8334146..54121f6 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -51,6 +51,7 @@ #include <QtCore/qstring.h> #include <QtCore/qvector.h> #include <QtCore/qset.h> +#include <QtCore/qcontiguouscache.h> QT_BEGIN_HEADER @@ -84,11 +85,11 @@ public: delete stream; } } - inline QDebug &space() { stream->space = true; stream->ts << " "; return *this; } + inline QDebug &space() { stream->space = true; stream->ts << ' '; return *this; } inline QDebug &nospace() { stream->space = false; return *this; } - inline QDebug &maybeSpace() { if (stream->space) stream->ts << " "; return *this; } + inline QDebug &maybeSpace() { if (stream->space) stream->ts << ' '; return *this; } - inline QDebug &operator<<(QChar t) { stream->ts << "\'" << t << "\'"; return maybeSpace(); } + inline QDebug &operator<<(QChar t) { stream->ts << '\'' << t << '\''; return maybeSpace(); } inline QDebug &operator<<(QBool t) { stream->ts << (bool(t) ? "true" : "false"); return maybeSpace(); } inline QDebug &operator<<(bool t) { stream->ts << (t ? "true" : "false"); return maybeSpace(); } inline QDebug &operator<<(char t) { stream->ts << t; return maybeSpace(); } @@ -105,10 +106,10 @@ public: inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); } inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); } inline QDebug &operator<<(const char* t) { stream->ts << QString::fromAscii(t); return maybeSpace(); } - inline QDebug &operator<<(const QString & t) { stream->ts << "\"" << t << "\""; return maybeSpace(); } + inline QDebug &operator<<(const QString & t) { stream->ts << '\"' << t << '\"'; return maybeSpace(); } inline QDebug &operator<<(const QStringRef & t) { return operator<<(t.toString()); } - inline QDebug &operator<<(const QLatin1String &t) { stream->ts << "\"" << t.latin1() << "\""; return maybeSpace(); } - inline QDebug &operator<<(const QByteArray & t) { stream->ts << "\"" << t << "\""; return maybeSpace(); } + inline QDebug &operator<<(const QLatin1String &t) { stream->ts << '\"' << t.latin1() << '\"'; return maybeSpace(); } + inline QDebug &operator<<(const QByteArray & t) { stream->ts << '\"' << t << '\"'; return maybeSpace(); } inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); } inline QDebug &operator<<(QTextStreamFunction f) { stream->ts << f; @@ -158,13 +159,13 @@ template <class T> inline QDebug operator<<(QDebug debug, const QList<T> &list) #endif { - debug.nospace() << "("; + debug.nospace() << '('; for (Q_TYPENAME QList<T>::size_type i = 0; i < list.count(); ++i) { if (i) debug << ", "; debug << list.at(i); } - debug << ")"; + debug << ')'; return debug.space(); } @@ -191,9 +192,9 @@ inline QDebug operator<<(QDebug debug, const QMap<aKey, aT> &map) debug.nospace() << "QMap("; for (typename QMap<aKey, aT>::const_iterator it = map.constBegin(); it != map.constEnd(); ++it) { - debug << "(" << it.key() << ", " << it.value() << ")"; + debug << '(' << it.key() << ", " << it.value() << ')'; } - debug << ")"; + debug << ')'; return debug.space(); } @@ -208,8 +209,8 @@ inline QDebug operator<<(QDebug debug, const QHash<aKey, aT> &hash) debug.nospace() << "QHash("; for (typename QHash<aKey, aT>::const_iterator it = hash.constBegin(); it != hash.constEnd(); ++it) - debug << "(" << it.key() << ", " << it.value() << ")"; - debug << ")"; + debug << '(' << it.key() << ", " << it.value() << ')'; + debug << ')'; return debug.space(); } @@ -221,7 +222,7 @@ template <class T1, class T2> inline QDebug operator<<(QDebug debug, const QPair<T1, T2> &pair) #endif { - debug.nospace() << "QPair(" << pair.first << "," << pair.second << ")"; + debug.nospace() << "QPair(" << pair.first << ',' << pair.second << ')'; return debug.space(); } @@ -232,6 +233,24 @@ inline QDebug operator<<(QDebug debug, const QSet<T> &set) return operator<<(debug, set.toList()); } +#if defined(FORCE_UREF) +template <class T> +inline QDebug &operator<<(QDebug debug, const QContiguousCache<T> &cache) +#else +template <class T> +inline QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache) +#endif +{ + debug.nospace() << "QContiguousCache("; + for (int i = cache.firstIndex(); i <= cache.lastIndex(); ++i) { + debug << cache[i]; + if (i != cache.lastIndex()) + debug << ", "; + } + debug << ')'; + return debug.space(); +} + #if !defined(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); } diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index d62328f..7d330e6 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -50,6 +50,7 @@ #include "qstring.h" #include "qregexp.h" #include "qvector.h" +#include "qalgorithms.h" #ifdef QT_BUILD_CORE_LIB # include "qresource.h" #endif @@ -192,32 +193,28 @@ QDirPrivate::~QDirPrivate() /* For sorting */ struct QDirSortItem { - QString filename_cache; - QString suffix_cache; + mutable QString filename_cache; + mutable QString suffix_cache; QFileInfo item; }; -static int qt_cmp_si_sort_flags; -#if defined(Q_C_CALLBACKS) -extern "C" { -#endif -#ifdef Q_OS_WINCE -static int __cdecl qt_cmp_si(const void *n1, const void *n2) -#else -static int qt_cmp_si(const void *n1, const void *n2) -#endif -{ - if (!n1 || !n2) - return 0; +class QDirSortItemComparator { + int qt_cmp_si_sort_flags; +public: + QDirSortItemComparator(int flags) : qt_cmp_si_sort_flags(flags) {} + bool operator()(const QDirSortItem &, const QDirSortItem &); +}; - QDirSortItem* f1 = (QDirSortItem*)n1; - QDirSortItem* f2 = (QDirSortItem*)n2; +bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortItem &n2) +{ + const QDirSortItem* f1 = &n1; + const QDirSortItem* f2 = &n2; if ((qt_cmp_si_sort_flags & QDir::DirsFirst) && (f1->item.isDir() != f2->item.isDir())) - return f1->item.isDir() ? -1 : 1; + return f1->item.isDir(); if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir())) - return f1->item.isDir() ? 1 : -1; + return !f1->item.isDir(); int r = 0; int sortBy = (qt_cmp_si_sort_flags & QDir::SortByMask) @@ -266,18 +263,11 @@ static int qt_cmp_si(const void *n1, const void *n2) : f1->filename_cache.compare(f2->filename_cache); } - if (r == 0) // Enforce an order - the order the items appear in the array - r = (char*)n1 - (char*)n2; - if (qt_cmp_si_sort_flags & QDir::Reversed) - return -r; - return r; + return r > 0; + return r < 0; } -#if defined(Q_C_CALLBACKS) -} -#endif - inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QStringList &l, QStringList *names, QFileInfoList *infos) const { @@ -294,9 +284,8 @@ inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QStringList &l, path += QLatin1Char('/'); si[i].item = QFileInfo(path + l.at(i)); } - qt_cmp_si_sort_flags = sort; if ((sort & QDir::SortByMask) != QDir::Unsorted) - qsort(si, i, sizeof(si[0]), qt_cmp_si); + qStableSort(si, si+i, QDirSortItemComparator(sort)); // put them back in the list(s) for (int j = 0; j<i; j++) { if(infos) @@ -2428,7 +2417,7 @@ QDebug operator<<(QDebug debug, QDir::Filters filters) if (filters & QDir::System) flags << QLatin1String("System"); if (filters & QDir::CaseSensitive) flags << QLatin1String("CaseSensitive"); } - debug << "QDir::Filters(" << qPrintable(flags.join(QLatin1String("|"))) << ")"; + debug << "QDir::Filters(" << qPrintable(flags.join(QLatin1String("|"))) << ')'; return debug; } @@ -2450,8 +2439,8 @@ QDebug operator<<(QDebug debug, QDir::SortFlags sorting) if (sorting & QDir::LocaleAware) flags << QLatin1String("LocaleAware"); if (sorting & QDir::Type) flags << QLatin1String("Type"); debug << "QDir::SortFlags(" << qPrintable(type) - << "|" - << qPrintable(flags.join(QLatin1String("|"))) << ")"; + << '|' + << qPrintable(flags.join(QLatin1String("|"))) << ')'; } return debug; } @@ -2463,9 +2452,9 @@ QDebug operator<<(QDebug debug, const QDir &dir) << qPrintable(dir.nameFilters().join(QLatin1String(","))) << "}, " << dir.sorting() - << "," + << ',' << dir.filter() - << ")"; + << ')'; return debug.space(); } diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index b14f436..81bfb27 100644 --- a/src/corelib/io/qdiriterator.cpp +++ b/src/corelib/io/qdiriterator.cpp @@ -201,8 +201,8 @@ void QDirIteratorPrivate::advance() QString subDir = it->currentFilePath(); #ifdef Q_OS_WIN - if (currentFileInfo.isSymLink()) - subDir = currentFileInfo.canonicalFilePath(); + if (nextFileInfo.isSymLink()) + subDir = nextFileInfo.canonicalFilePath(); #endif pushSubDirectory(subDir, it->nameFilters(), it->filters()); } diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 04750b0..4deaddb 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -719,38 +719,47 @@ QFile::rename(const QString &newName) return true; } - QFile in(fileName()); + if (isSequential()) { + d->setError(QFile::RenameError, tr("Will not rename sequential file using block copy")); + return false; + } + QFile out(newName); - if (in.open(QIODevice::ReadOnly)) { + if (open(QIODevice::ReadOnly)) { if (out.open(QIODevice::WriteOnly | QIODevice::Truncate)) { bool error = false; char block[4096]; - qint64 read; - while ((read = in.read(block, sizeof(block))) > 0) { - if (read != out.write(block, read)) { + qint64 bytes; + while ((bytes = read(block, sizeof(block))) > 0) { + if (bytes != out.write(block, bytes)) { d->setError(QFile::RenameError, out.errorString()); error = true; break; } } - if (read == -1) { - d->setError(QFile::RenameError, in.errorString()); + if (bytes == -1) { + d->setError(QFile::RenameError, errorString()); error = true; } if(!error) { - if (!in.remove()) { + if (!remove()) { d->setError(QFile::RenameError, tr("Cannot remove source file")); error = true; } } if (error) out.remove(); - else + else { + setPermissions(permissions()); + unsetError(); setFileName(newName); + } + close(); return !error; } + close(); } - d->setError(QFile::RenameError, out.isOpen() ? in.errorString() : out.errorString()); + d->setError(QFile::RenameError, out.isOpen() ? errorString() : out.errorString()); } return false; } diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index a8d28cb..36b1ed8 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -571,7 +571,6 @@ void QFileInfo::setFile(const QFile &file) void QFileInfo::setFile(const QDir &dir, const QString &file) { - Q_D(QFileInfo); *this = QFileInfo(dir.filePath(file)); } diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index e073a08..65cfb71 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -118,7 +118,7 @@ public: void stop(); -private slots: +private Q_SLOTS: void timeout(); }; diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 61ea7cc..07f3c9c 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -312,6 +312,10 @@ bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh) if (ret == -1) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(int(errno))); + + this->openMode = QIODevice::NotOpen; + this->fh = 0; + return false; } } @@ -335,6 +339,7 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, int fd) if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append))) openMode |= QFile::Truncate; + d->openMode = openMode; d->lastFlushFailed = false; d->closeFileHandle = false; d->nativeFilePath.clear(); @@ -367,6 +372,10 @@ bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd) if (ret == -1) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(int(errno))); + + this->openMode = QIODevice::NotOpen; + this->fd = -1; + return false; } } @@ -868,6 +877,119 @@ bool QFSFileEngine::supportsExtension(Extension extension) const return false; } +/*! \fn bool QFSFileEngine::caseSensitive() const + Returns true for Windows, false for Unix. +*/ + +/*! \fn bool QFSFileEngine::copy(const QString ©Name) + + For windows, copy the file to file \a copyName. + + Not implemented for Unix. +*/ + +/*! \fn QString QFSFileEngine::currentPath(const QString &fileName) + For Unix, returns the current working directory for the file + engine. + + For Windows, returns the canonicalized form of the current path used + by the file engine for the drive specified by \a fileName. On + Windows, each drive has its own current directory, so a different + path is returned for file names that include different drive names + (e.g. A: or C:). + + \sa setCurrentPath() +*/ + +/*! \fn QFileInfoList QFSFileEngine::drives() + For Windows, returns the list of drives in the file system as a list + of QFileInfo objects. On unix, Mac OS X and Windows CE, only the + root path is returned. On Windows, this function returns all drives + (A:\, C:\, D:\, etc.). + + For Unix, the list contains just the root path "/". +*/ + +/*! \fn QString QFSFileEngine::fileName(FileName file) const + \reimp +*/ + +/*! \fn QDateTime QFSFileEngine::fileTime(FileTime time) const + \reimp +*/ + +/*! \fn QString QFSFileEngine::homePath() + Returns the home path of the current user. + + \sa rootPath() +*/ + +/*! \fn bool QFSFileEngine::isRelativePath() const + \reimp +*/ + +/*! \fn bool QFSFileEngine::link(const QString &newName) + + Creates a link from the file currently specified by fileName() to + \a newName. What a link is depends on the underlying filesystem + (be it a shortcut on Windows or a symbolic link on Unix). Returns + true if successful; otherwise returns false. +*/ + +/*! \fn bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const + \reimp +*/ + +/*! \fn uint QFSFileEngine::ownerId(FileOwner own) const + In Unix, if stat() is successful, the \c uid is returned if + \a own is the owner. Otherwise the \c gid is returned. If stat() + is unsuccessful, -2 is reuturned. + + For Windows, -2 is always returned. +*/ + +/*! \fn QString QFSFileEngine::owner(FileOwner own) const + \reimp +*/ + +/*! \fn bool QFSFileEngine::remove() + \reimp +*/ + +/*! \fn bool QFSFileEngine::rename(const QString &newName) + \reimp +*/ + +/*! \fn bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const + \reimp +*/ + +/*! \fn QString QFSFileEngine::rootPath() + Returns the root path. + + \sa homePath() +*/ + +/*! \fn bool QFSFileEngine::setCurrentPath(const QString &path) + Sets the current path (e.g., for QDir), to \a path. Returns true if the + new path exists; otherwise this function does nothing, and returns false. + + \sa currentPath() +*/ + +/*! \fn bool QFSFileEngine::setPermissions(uint perms) + \reimp +*/ + +/*! \fn bool QFSFileEngine::setSize(qint64 size) + \reimp +*/ + +/*! \fn QString QFSFileEngine::tempPath() + Returns the temporary path (i.e., a path in which it is safe + to store temporary files). +*/ + QT_END_NAMESPACE #endif // QT_NO_FSFILEENGINE diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 8a0a3f5..3c443ff 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -83,12 +83,12 @@ static QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QString & } else if (flags & QIODevice::WriteOnly) { mode = "wb"; if (flags & QIODevice::ReadOnly) - mode += "+"; + mode += '+'; } if (flags & QIODevice::Append) { mode = "ab"; if (flags & QIODevice::ReadOnly) - mode += "+"; + mode += '+'; } return mode; } @@ -273,9 +273,8 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 len) int oldFlags = fcntl(QT_FILENO(fh), F_GETFL); for (int i = 0; i < 2; ++i) { // Unix: Make the underlying file descriptor non-blocking - int v = 1; if ((oldFlags & O_NONBLOCK) == 0) - fcntl(QT_FILENO(fh), F_SETFL, oldFlags | O_NONBLOCK, &v, sizeof(v)); + fcntl(QT_FILENO(fh), F_SETFL, oldFlags | O_NONBLOCK); // Cross platform stdlib read size_t read = 0; @@ -293,8 +292,7 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 len) // Unix: Restore the blocking state of the underlying socket if ((oldFlags & O_NONBLOCK) == 0) { - int v = 1; - fcntl(QT_FILENO(fh), F_SETFL, oldFlags, &v, sizeof(v)); + fcntl(QT_FILENO(fh), F_SETFL, oldFlags); if (readBytes == 0) { int readByte = 0; do { @@ -311,8 +309,7 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 len) } // Unix: Restore the blocking state of the underlying socket if ((oldFlags & O_NONBLOCK) == 0) { - int v = 1; - fcntl(QT_FILENO(fh), F_SETFL, oldFlags, &v, sizeof(v)); + fcntl(QT_FILENO(fh), F_SETFL, oldFlags); } if (readBytes == 0 && !feof(fh)) { // if we didn't read anything and we're not at EOF, it must be an error @@ -726,7 +723,7 @@ QString QFSFileEngine::fileName(FileName file) const bool isDir = ret.endsWith(QLatin1Char('/')); ret = QDir::cleanPath(ret); if (isDir) - ret += QLatin1String("/"); + ret += QLatin1Char('/'); if (file == AbsolutePathName) { int slash = ret.lastIndexOf(QLatin1Char('/')); if (slash == -1) @@ -780,7 +777,7 @@ QString QFSFileEngine::fileName(FileName file) const #endif if (len > 0) { QString ret; - if (S_ISDIR(d->st.st_mode) && s[0] != '/') { + if (d->doStat() && S_ISDIR(d->st.st_mode) && s[0] != '/') { QDir parent(d->filePath); parent.cdUp(); ret = parent.path(); diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index 63506c2..9da9e66 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -433,7 +433,7 @@ static QString nativeAbsoluteFilePathW(const QString &path) if (retLen != 0) ret = QString::fromUtf16((unsigned short *)buf.data(), retLen); #else - if (path.startsWith(QLatin1String("/")) || path.startsWith(QLatin1String("\\"))) + if (path.startsWith(QLatin1Char('/')) || path.startsWith(QLatin1Char('\\'))) ret = QDir::toNativeSeparators(path); else ret = QDir::toNativeSeparators(QDir::cleanPath(qfsPrivateCurrentDir + QLatin1Char('/') + path)); @@ -946,9 +946,6 @@ bool QFSFileEnginePrivate::nativeIsSequential() const return false; } -/*! - \reimp -*/ bool QFSFileEngine::remove() { Q_D(QFSFileEngine); @@ -959,9 +956,6 @@ bool QFSFileEngine::remove() }); } -/*! - \reimp -*/ bool QFSFileEngine::copy(const QString ©Name) { Q_D(QFSFileEngine); @@ -974,9 +968,6 @@ bool QFSFileEngine::copy(const QString ©Name) }); } -/*! - \reimp -*/ bool QFSFileEngine::rename(const QString &newName) { Q_D(QFSFileEngine); @@ -1017,9 +1008,6 @@ static inline bool mkDir(const QString &path) }); } -/*! - \reimp -*/ static inline bool rmDir(const QString &path) { QT_WA({ @@ -1029,9 +1017,6 @@ static inline bool rmDir(const QString &path) }); } -/*! - \reimp -*/ static inline bool isDirPath(const QString &dirPath, bool *existed) { QString path = dirPath; @@ -1054,9 +1039,6 @@ static inline bool isDirPath(const QString &dirPath, bool *existed) return fileAttrib & FILE_ATTRIBUTE_DIRECTORY; } -/*! - \reimp -*/ bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const { QString dirName = name; @@ -1097,9 +1079,6 @@ bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) con return mkDir(name); } -/*! - \reimp -*/ bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const { QString dirName = name; @@ -1120,20 +1099,11 @@ bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) co return rmDir(name); } -/*! - \reimp -*/ bool QFSFileEngine::caseSensitive() const { return false; } -/*! - Sets the current path (e.g., for QDir), to \a path. Returns true if the - new path exists; otherwise this function does nothing, and returns false. - - \sa currentPath() -*/ bool QFSFileEngine::setCurrentPath(const QString &path) { if (!QDir(path).exists()) @@ -1153,16 +1123,6 @@ bool QFSFileEngine::setCurrentPath(const QString &path) #endif } -/*! - Returns the canonicalized form of the current path used by the file - engine for the drive specified by \a fileName. - - On Windows, each drive has its own current directory, so a different - path is returned for file names that include different drive names - (e.g. A: or C:). - - \sa setCurrentPath() -*/ QString QFSFileEngine::currentPath(const QString &fileName) { #if !defined(Q_OS_WINCE) @@ -1219,11 +1179,6 @@ QString QFSFileEngine::currentPath(const QString &fileName) #endif } -/*! - Returns the home path of the current user. - - \sa rootPath() -*/ QString QFSFileEngine::homePath() { QString ret; @@ -1277,11 +1232,6 @@ QString QFSFileEngine::homePath() return QDir::fromNativeSeparators(ret); } -/*! - Returns the root path. - - \sa homePath() -*/ QString QFSFileEngine::rootPath() { #if defined(Q_OS_WINCE) @@ -1290,7 +1240,7 @@ QString QFSFileEngine::rootPath() QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData()); if(ret.isEmpty()) ret = QLatin1String("c:"); - ret += QLatin1String("/"); + ret += QLatin1Char('/'); #elif defined(Q_OS_OS2EMX) char dir[4]; _abspath(dir, QLatin1String("/"), _MAX_PATH); @@ -1299,10 +1249,6 @@ QString QFSFileEngine::rootPath() return ret; } -/*! - Returns the temporary path (i.e., a path in which it is safe to store - temporary files). -*/ QString QFSFileEngine::tempPath() { QString ret; @@ -1330,11 +1276,6 @@ QString QFSFileEngine::tempPath() return ret; } -/*! - Returns the list of drives in the file system as a list of QFileInfo - objects. On unix, Mac OS X and Windows CE, only the root path is returned. - On Windows, this function returns all drives (A:\, C:\, D:\, etc.). -*/ QFileInfoList QFSFileEngine::drives() { QFileInfoList ret; @@ -1347,19 +1288,17 @@ QFileInfoList QFSFileEngine::drives() exit(1); driveBits &= 0x3ffffff; #endif - char driveName[4]; - - qstrcpy(driveName, "A:/"); + char driveName[] = "A:/"; while(driveBits) { if(driveBits & 1) - ret.append(QString::fromLatin1(driveName).toUpper()); + ret.append(QString::fromLatin1(driveName)); driveName[0]++; driveBits = driveBits >> 1; } return ret; #else - ret.append(QString::fromLatin1("/").toUpper()); + ret.append(QString::fromLatin1("/")); return ret; #endif } @@ -1392,8 +1331,6 @@ bool QFSFileEnginePrivate::doStat() const if (tmpAttributes != -1) { fileAttrib = tmpAttributes; could_stat = true; - } else { - return false; } #endif } else { @@ -1556,9 +1493,6 @@ QString QFSFileEnginePrivate::getLink() const return readLink(filePath); } -/*! - \reimp -*/ bool QFSFileEngine::link(const QString &newName) { #if !defined(Q_OS_WINCE) @@ -1816,9 +1750,6 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil return ret; } -/*! - \reimp -*/ QString QFSFileEngine::fileName(FileName file) const { Q_D(const QFSFileEngine); @@ -1839,10 +1770,10 @@ QString QFSFileEngine::fileName(FileName file) const if(slash == -1) { if(d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) return d->filePath.left(2); - return QString::fromLatin1("."); + return QString(QLatin1Char('.')); } else { if(!slash) - return QString::fromLatin1("/"); + return QString(QLatin1Char('/')); if(slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) slash++; return d->filePath.left(slash); @@ -1900,7 +1831,7 @@ QString QFSFileEngine::fileName(FileName file) const if (slash == -1) ret = QDir::currentPath(); else if (slash == 0) - ret = QLatin1String("/"); + ret = QString(QLatin1Char('/')); ret = ret.left(slash); } return ret; @@ -1912,9 +1843,6 @@ QString QFSFileEngine::fileName(FileName file) const return d->filePath; } -/*! - \reimp -*/ bool QFSFileEngine::isRelativePath() const { Q_D(const QFSFileEngine); @@ -1924,18 +1852,12 @@ bool QFSFileEngine::isRelativePath() const || (d->filePath.at(0) == QLatin1Char('/') && d->filePath.at(1) == QLatin1Char('/'))))); // drive, e.g. a: } -/*! - \reimp -*/ uint QFSFileEngine::ownerId(FileOwner /*own*/) const { static const uint nobodyID = (uint) -2; return nobodyID; } -/*! - \reimp -*/ QString QFSFileEngine::owner(FileOwner own) const { #if !defined(QT_NO_LIBRARY) @@ -1971,12 +1893,9 @@ QString QFSFileEngine::owner(FileOwner own) const #else Q_UNUSED(own); #endif - return QString(QLatin1String("")); + return QString(); } -/*! - \reimp -*/ bool QFSFileEngine::setPermissions(uint perms) { Q_D(QFSFileEngine); @@ -2003,9 +1922,6 @@ bool QFSFileEngine::setPermissions(uint perms) return ret; } -/*! - \reimp -*/ bool QFSFileEngine::setSize(qint64 size) { Q_D(QFSFileEngine); @@ -2075,9 +1991,6 @@ static inline QDateTime fileTimeToQDateTime(const FILETIME *time) return ret; } -/*! - \reimp -*/ QDateTime QFSFileEngine::fileTime(FileTime time) const { Q_D(const QFSFileEngine); diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index b6c4eb1..8924b77 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -949,9 +949,9 @@ QByteArray QIODevice::readAll() QByteArray tmp; if (d->isSequential() || size() == 0) { - // Read it in chunks, bytesAvailable() is unreliable for sequential - // devices. - const int chunkSize = 4096; + // Read it in chunks. Use bytesAvailable() as an unreliable hint for + // sequential devices, but try to read 4K as a minimum. + int chunkSize = qMax(qint64(4096), bytesAvailable()); qint64 totalRead = 0; forever { tmp.resize(tmp.size() + chunkSize); @@ -960,6 +960,7 @@ QByteArray QIODevice::readAll() if (readBytes <= 0) return tmp; totalRead += readBytes; + chunkSize = qMax(qint64(4096), bytesAvailable()); } } else { // Read it all in one go. @@ -1744,7 +1745,7 @@ QDebug operator<<(QDebug debug, QIODevice::OpenMode modes) } qSort(modeList); debug << modeList.join(QLatin1String("|")); - debug << ")"; + debug << ')'; return debug; } #endif diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp new file mode 100644 index 0000000..f50acdb --- /dev/null +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -0,0 +1,544 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnoncontiguousbytedevice_p.h" +#include <QObject> +#include <QBuffer> +#include <QDebug> +#include <QFile> + +QT_BEGIN_NAMESPACE + +/*! + \class QNonContiguousByteDevice + \brief A QNonContiguousByteDevice is a representation of a + file, array or buffer that allows access with a read pointer. + \since 4.6 + + \inmodule QtCore + + The goal of this class is to have a data representation that + allows us to avoid doing a memcpy as we have to do with QIODevice. + + \sa QNonContiguousByteDeviceFactory + + \internal +*/ +/*! + \fn virtual const char* QNonContiguousByteDevice::readPointer(qint64 maximumLength, qint64 &len) + + Return a byte pointer for at most \a maximumLength bytes of that device. + if \a maximumLength is -1, the caller does not care about the length and + the device may return what it desires to. + The actual number of bytes the pointer is valid for is returned in + the \a len variable. + \a len will be -1 if EOF or an error occurs. + If it was really EOF can then afterwards be checked with atEnd() + Returns 0 if it is not possible to read at that position. + + \sa atEnd() + + \internal +*/ +/*! + \fn virtual bool QNonContiguousByteDevice::advanceReadPointer(qint64 amount) + + will advance the internal read pointer by \a amount bytes. + The old readPointer is invalid after this call. + + \sa readPointer() + + \internal +*/ +/*! + \fn virtual bool QNonContiguousByteDevice::atEnd() + + Returns true if everything has been read and the read + pointer cannot be advanced anymore. + + \sa readPointer(), advanceReadPointer(), reset() + + \internal +*/ +/*! + \fn virtual bool QNonContiguousByteDevice::reset() + + Moves the internal read pointer back to the beginning. + Returns false if this was not possible. + + \sa atEnd(), disableReset() + + \internal +*/ +/*! + \fn void QNonContiguousByteDevice::disableReset() + + Disable the reset() call, e.g. it will always + do nothing and return false. + + \sa reset() + + \internal +*/ +/*! + \fn virtual qint64 QNonContiguousByteDevice::size() + + Returns the size of the complete device or -1 if unknown. + May also return less/more than what can be actually read with readPointer() + + \internal +*/ +/*! + \fn void QNonContiguousByteDevice::readyRead() + + Emitted when there is data available + + \internal +*/ +/*! + \fn void QNonContiguousByteDevice::readProgress(qint64 current, qint64 total) + + Emitted when data has been "read" by advancing the read pointer + + \internal +*/ + +QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)0), resetDisabled(false) +{ +}; + +QNonContiguousByteDevice::~QNonContiguousByteDevice() +{ +}; + +void QNonContiguousByteDevice::disableReset() +{ + resetDisabled = true; +} + +QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b) : QNonContiguousByteDevice() +{ + buffer = b; + byteArray = QByteArray::fromRawData(buffer->buffer().constData() + buffer->pos(), buffer->size() - buffer->pos()); + arrayImpl = new QNonContiguousByteDeviceByteArrayImpl(&byteArray); + arrayImpl->setParent(this); + connect(arrayImpl, SIGNAL(readyRead()), SIGNAL(readyRead())); + connect(arrayImpl, SIGNAL(readProgress(qint64,qint64)), SIGNAL(readProgress(qint64,qint64))); +} + +QNonContiguousByteDeviceBufferImpl::~QNonContiguousByteDeviceBufferImpl() +{ +} + +const char* QNonContiguousByteDeviceBufferImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + return arrayImpl->readPointer(maximumLength, len); +} + +bool QNonContiguousByteDeviceBufferImpl::advanceReadPointer(qint64 amount) +{ + return arrayImpl->advanceReadPointer(amount); +} + +bool QNonContiguousByteDeviceBufferImpl::atEnd() +{ + return arrayImpl->atEnd(); +} + +bool QNonContiguousByteDeviceBufferImpl::reset() +{ + if (resetDisabled) + return false; + return arrayImpl->reset(); +} + +qint64 QNonContiguousByteDeviceBufferImpl::size() +{ + return arrayImpl->size(); +} + +QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba) : QNonContiguousByteDevice(), currentPosition(0) +{ + byteArray = ba; +} + +QNonContiguousByteDeviceByteArrayImpl::~QNonContiguousByteDeviceByteArrayImpl() +{ +} + +const char* QNonContiguousByteDeviceByteArrayImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + if (atEnd()) { + len = -1; + return 0; + } + + if (maximumLength != -1) + len = qMin(maximumLength, size() - currentPosition); + else + len = size() - currentPosition; + + return byteArray->constData() + currentPosition; +} + +bool QNonContiguousByteDeviceByteArrayImpl::advanceReadPointer(qint64 amount) +{ + currentPosition += amount; + emit readProgress(currentPosition, size()); + return true; +} + +bool QNonContiguousByteDeviceByteArrayImpl::atEnd() +{ + return currentPosition >= size(); +} + +bool QNonContiguousByteDeviceByteArrayImpl::reset() +{ + if (resetDisabled) + return false; + + currentPosition = 0; + return true; +} + +qint64 QNonContiguousByteDeviceByteArrayImpl::size() +{ + return byteArray->size(); +} + +QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb) + : QNonContiguousByteDevice(), currentPosition(0) +{ + ringBuffer = rb; +} + +QNonContiguousByteDeviceRingBufferImpl::~QNonContiguousByteDeviceRingBufferImpl() +{ +}; + +const char* QNonContiguousByteDeviceRingBufferImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + if (atEnd()) { + len = -1; + return 0; + } + + const char *returnValue = ringBuffer->readPointerAtPosition(currentPosition, len); + + if (maximumLength != -1) + len = qMin(len, maximumLength); + + return returnValue; +}; + +bool QNonContiguousByteDeviceRingBufferImpl::advanceReadPointer(qint64 amount) +{ + currentPosition += amount; + emit readProgress(currentPosition, size()); + return true; +}; + +bool QNonContiguousByteDeviceRingBufferImpl::atEnd() +{ + return currentPosition >= size(); +}; + +bool QNonContiguousByteDeviceRingBufferImpl::reset() +{ + if (resetDisabled) + return false; + + currentPosition = 0; + return true; +}; + +qint64 QNonContiguousByteDeviceRingBufferImpl::size() +{ + return ringBuffer->size(); +}; + +QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d) + : QNonContiguousByteDevice(), + currentReadBuffer(0), currentReadBufferSize(16*1024), + currentReadBufferAmount(0), currentReadBufferPosition(0), totalAdvancements(0), + eof(false) +{ + device = d; + initialPosition = d->pos(); + connect(device, SIGNAL(readyRead()), this, SIGNAL(readyRead()), Qt::QueuedConnection); + connect(device, SIGNAL(readChannelFinished()), this, SIGNAL(readyRead()), Qt::QueuedConnection); +}; + +QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl() +{ + delete currentReadBuffer; +}; + +const char* QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + if (eof == true) { + len = -1; + return 0; + } + + if (currentReadBuffer == 0) + currentReadBuffer = new QByteArray(currentReadBufferSize, '\0'); // lazy alloc + + if (maximumLength == -1) + maximumLength = currentReadBufferSize; + + if (currentReadBufferAmount - currentReadBufferPosition > 0) { + len = currentReadBufferAmount - currentReadBufferPosition; + return currentReadBuffer->data() + currentReadBufferPosition; + } + + qint64 haveRead = device->read(currentReadBuffer->data(), qMin(maximumLength, currentReadBufferSize)); + + if ((haveRead == -1) || (haveRead == 0 && device->atEnd() && !device->isSequential())) { + eof = true; + len = -1; + // size was unknown before, emit a readProgress with the final size + if (size() == -1) + emit readProgress(totalAdvancements, totalAdvancements); + return 0; + } + + currentReadBufferAmount = haveRead; + currentReadBufferPosition = 0; + + len = haveRead; + return currentReadBuffer->data(); +}; + +bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount) +{ + totalAdvancements += amount; + + // normal advancement + currentReadBufferPosition += amount; + + // advancing over that what has actually been read before + if (currentReadBufferPosition > currentReadBufferAmount) { + qint64 i = currentReadBufferPosition - currentReadBufferAmount; + while (i > 0) { + if (device->getChar(0) == false) { + emit readProgress(totalAdvancements - i, size()); + return false; // ### FIXME handle eof + } + i--; + } + + currentReadBufferPosition = 0; + currentReadBufferAmount = 0; + } + + if (size() == -1) + emit readProgress(totalAdvancements, totalAdvancements); + else + emit readProgress(totalAdvancements, size()); + + return true; +}; + +bool QNonContiguousByteDeviceIoDeviceImpl::atEnd() +{ + return eof == true; +}; + +bool QNonContiguousByteDeviceIoDeviceImpl::reset() +{ + if (resetDisabled) + return false; + + if (device->seek(initialPosition)) { + eof = false; // assume eof is false, it will be true after a read has been attempted + return true; + } + + return false; +}; + +qint64 QNonContiguousByteDeviceIoDeviceImpl::size() +{ + // note that this is different from the size() implementation of QIODevice! + + if (device->isSequential()) + return -1; + + return device->size() - initialPosition; +}; + +QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0) +{ + byteDevice = bd; + connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead())); + + open(ReadOnly); +} + +QByteDeviceWrappingIoDevice::~QByteDeviceWrappingIoDevice() +{ + +} + +bool QByteDeviceWrappingIoDevice::isSequential() const +{ + return (byteDevice->size() == -1); +} + +bool QByteDeviceWrappingIoDevice::atEnd() const +{ + return byteDevice->atEnd(); +} + +bool QByteDeviceWrappingIoDevice::reset() +{ + return byteDevice->reset(); +} + +qint64 QByteDeviceWrappingIoDevice::size() const +{ + if (isSequential()) + return 0; + + return byteDevice->size(); +} + + +qint64 QByteDeviceWrappingIoDevice::readData( char * data, qint64 maxSize) +{ + qint64 len; + const char *readPointer = byteDevice->readPointer(maxSize, len); + if (len == -1) + return -1; + + memcpy(data, readPointer, len); + byteDevice->advanceReadPointer(len); + return len; +} + +qint64 QByteDeviceWrappingIoDevice::writeData( const char* data, qint64 maxSize) +{ + Q_UNUSED(data); + Q_UNUSED(maxSize); + return -1; +} + +/*! + \class QNonContiguousByteDeviceFactory + \since 4.6 + + \inmodule QtCore + + Creates a QNonContiguousByteDevice out of a QIODevice, + QByteArray etc. + + \sa QNonContiguousByteDevice + + \internal +*/ + +/*! + \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device); + + Create a QNonContiguousByteDevice out of a QIODevice. + For QFile, QBuffer and all other QIoDevice, sequential or not. + + \internal +*/ +QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device) +{ + // shortcut if it is a QBuffer + if (QBuffer* buffer = qobject_cast<QBuffer*>(device)) { + return new QNonContiguousByteDeviceBufferImpl(buffer); + } + + // ### FIXME special case if device is a QFile that supports map() + // then we can actually deal with the file without using read/peek + + // generic QIODevice + return new QNonContiguousByteDeviceIoDeviceImpl(device); // FIXME +}; + +/*! + \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer); + + Create a QNonContiguousByteDevice out of a QRingBuffer. + + \internal +*/ +QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer) +{ + return new QNonContiguousByteDeviceRingBufferImpl(ringBuffer); +}; + +/*! + \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray); + + Create a QNonContiguousByteDevice out of a QByteArray. + + \internal +*/ +QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray) +{ + return new QNonContiguousByteDeviceByteArrayImpl(byteArray); +}; + +/*! + \fn static QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice); + + Wrap the \a byteDevice (possibly again) into a QIODevice. + + \internal +*/ +QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice) +{ + // ### FIXME if it already has been based on QIoDevice, we could that one out again + // and save some calling + + // needed for FTP backend + + return new QByteDeviceWrappingIoDevice(byteDevice); +} + +QT_END_NAMESPACE + diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h new file mode 100644 index 0000000..acfc6eb --- /dev/null +++ b/src/corelib/io/qnoncontiguousbytedevice_p.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNONCONTIGUOUSBYTEDEVICE_H +#define QNONCONTIGUOUSBYTEDEVICE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QObject> +#include <QtCore/qbytearray.h> +#include <QtCore/qbuffer.h> +#include <QtCore/qiodevice.h> +#include "private/qringbuffer_p.h" + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QNonContiguousByteDevice : public QObject +{ + Q_OBJECT +public: + virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0; + virtual bool advanceReadPointer(qint64 amount) = 0; + virtual bool atEnd() = 0; + virtual bool reset() = 0; + void disableReset(); + virtual qint64 size() = 0; + +protected: + QNonContiguousByteDevice(); + virtual ~QNonContiguousByteDevice(); + + bool resetDisabled; +Q_SIGNALS: + void readyRead(); + void readProgress(qint64 current, qint64 total); +}; + +class Q_CORE_EXPORT QNonContiguousByteDeviceFactory +{ +public: + static QNonContiguousByteDevice* create(QIODevice *device); + static QNonContiguousByteDevice* create(QByteArray *byteArray); + static QNonContiguousByteDevice* create(QRingBuffer *ringBuffer); + static QIODevice* wrap(QNonContiguousByteDevice* byteDevice); +}; + +// the actual implementations +// + +class QNonContiguousByteDeviceByteArrayImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba); + ~QNonContiguousByteDeviceByteArrayImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QByteArray* byteArray; + qint64 currentPosition; +}; + +class QNonContiguousByteDeviceRingBufferImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb); + ~QNonContiguousByteDeviceRingBufferImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QRingBuffer* ringBuffer; + qint64 currentPosition; +}; + + +class QNonContiguousByteDeviceIoDeviceImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d); + ~QNonContiguousByteDeviceIoDeviceImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QIODevice* device; + QByteArray* currentReadBuffer; + qint64 currentReadBufferSize; + qint64 currentReadBufferAmount; + qint64 currentReadBufferPosition; + qint64 totalAdvancements; + bool eof; + qint64 initialPosition; +}; + +class QNonContiguousByteDeviceBufferImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceBufferImpl(QBuffer *b); + ~QNonContiguousByteDeviceBufferImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QBuffer* buffer; + QByteArray byteArray; + QNonContiguousByteDeviceByteArrayImpl* arrayImpl; +}; + +// ... and the reverse thing +class QByteDeviceWrappingIoDevice : public QIODevice +{ + Q_OBJECT +public: + QByteDeviceWrappingIoDevice (QNonContiguousByteDevice *bd); + ~QByteDeviceWrappingIoDevice (); + virtual bool isSequential () const; + virtual bool atEnd () const; + virtual bool reset (); + virtual qint64 size () const; +protected: + virtual qint64 readData ( char * data, qint64 maxSize ); + virtual qint64 writeData ( const char * data, qint64 maxSize ); + + QNonContiguousByteDevice *byteDevice; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 30f4291..afeaad6 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -1586,7 +1586,7 @@ void QProcess::start(const QString &program, const QStringList &arguments, OpenM } #if defined QPROCESS_DEBUG - qDebug() << "QProcess::start(" << program << "," << arguments << "," << mode << ")"; + qDebug() << "QProcess::start(" << program << ',' << arguments << ',' << mode << ')'; #endif d->outputReadBuffer.clear(); diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 2f05f6e..e87c314 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -140,15 +140,6 @@ static void qt_native_close(int fd) } while (ret == -1 && errno == EINTR); } -static void qt_native_sigaction(int signum, const struct sigaction *act, - struct sigaction *oldact) -{ - int ret; - do { - ret = ::sigaction(signum, act, oldact); - } while (ret == -1 && errno == EINTR); -} - static void qt_native_dup2(int oldfd, int newfd) { int ret; @@ -255,7 +246,7 @@ QProcessManager::QProcessManager() memset(&action, 0, sizeof(action)); action.sa_handler = qt_sa_sigchld_handler; action.sa_flags = SA_NOCLDSTOP; - qt_native_sigaction(SIGCHLD, &action, &oldAction); + ::sigaction(SIGCHLD, &action, &oldAction); if (oldAction.sa_handler != qt_sa_sigchld_handler) qt_sa_old_sigchld_handler = oldAction.sa_handler; } @@ -282,9 +273,9 @@ QProcessManager::~QProcessManager() memset(&action, 0, sizeof(action)); action.sa_handler = qt_sa_old_sigchld_handler; action.sa_flags = SA_NOCLDSTOP; - qt_native_sigaction(SIGCHLD, &action, &oldAction); + ::sigaction(SIGCHLD, &action, &oldAction); if (oldAction.sa_handler != qt_sa_sigchld_handler) { - qt_native_sigaction(SIGCHLD, &oldAction, 0); + ::sigaction(SIGCHLD, &oldAction, 0); } } @@ -394,17 +385,10 @@ static void qt_create_pipe(int *pipe) qt_native_close(pipe[0]); if (pipe[1] != -1) qt_native_close(pipe[1]); -#ifdef Q_OS_IRIX - if (::socketpair(AF_UNIX, SOCK_STREAM, 0, pipe) == -1) { - qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s", - pipe, qPrintable(qt_error_string(errno))); - } -#else if (::pipe(pipe) != 0) { qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s", pipe, qPrintable(qt_error_string(errno))); } -#endif ::fcntl(pipe[0], F_SETFD, FD_CLOEXEC); ::fcntl(pipe[1], F_SETFD, FD_CLOEXEC); } @@ -596,29 +580,27 @@ void QProcessPrivate::startProcess() processManager()->start(); // Initialize pipes + if (!createChannel(stdinChannel) || + !createChannel(stdoutChannel) || + !createChannel(stderrChannel)) + return; qt_create_pipe(childStartedPipe); + qt_create_pipe(deathPipe); + ::fcntl(deathPipe[0], F_SETFD, FD_CLOEXEC); + ::fcntl(deathPipe[1], F_SETFD, FD_CLOEXEC); + if (threadData->eventDispatcher) { startupSocketNotifier = new QSocketNotifier(childStartedPipe[0], QSocketNotifier::Read, q); QObject::connect(startupSocketNotifier, SIGNAL(activated(int)), q, SLOT(_q_startupNotification())); - } - qt_create_pipe(deathPipe); - ::fcntl(deathPipe[0], F_SETFD, FD_CLOEXEC); - ::fcntl(deathPipe[1], F_SETFD, FD_CLOEXEC); - if (threadData->eventDispatcher) { deathNotifier = new QSocketNotifier(deathPipe[0], QSocketNotifier::Read, q); QObject::connect(deathNotifier, SIGNAL(activated(int)), q, SLOT(_q_processDied())); } - if (!createChannel(stdinChannel) || - !createChannel(stdoutChannel) || - !createChannel(stderrChannel)) - return; - // Start the process (platform dependent) q->setProcessState(QProcess::Starting); @@ -906,7 +888,7 @@ static void qt_ignore_sigpipe() struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; - qt_native_sigaction(SIGPIPE, &noaction, 0); + ::sigaction(SIGPIPE, &noaction, 0); } } @@ -1276,7 +1258,7 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; - qt_native_sigaction(SIGPIPE, &noaction, 0); + ::sigaction(SIGPIPE, &noaction, 0); ::setsid(); @@ -1322,7 +1304,7 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; - qt_native_sigaction(SIGPIPE, &noaction, 0); + ::sigaction(SIGPIPE, &noaction, 0); // '\1' means execv failed char c = '\1'; @@ -1333,7 +1315,7 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; - qt_native_sigaction(SIGPIPE, &noaction, 0); + ::sigaction(SIGPIPE, &noaction, 0); // '\2' means internal error char c = '\2'; diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 5d862e5..179c3d0 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -272,12 +272,12 @@ static QString qt_create_commandline(const QString &program, const QStringList & QString args; if (!program.isEmpty()) { QString programName = program; - if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1String(" "))) - programName = QLatin1String("\"") + programName + QLatin1String("\""); - programName.replace(QLatin1String("/"), QLatin1String("\\")); + if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1Char(' '))) + programName = QLatin1Char('\"') + programName + QLatin1Char('\"'); + programName.replace(QLatin1Char('/'), QLatin1Char('\\')); // add the prgram as the first arg ... it works better - args = programName + QLatin1String(" "); + args = programName + QLatin1Char(' '); } for (int i=0; i<arguments.size(); ++i) { @@ -285,16 +285,16 @@ static QString qt_create_commandline(const QString &program, const QStringList & // in the case of \" already being in the string the \ must also be escaped tmp.replace( QLatin1String("\\\""), QLatin1String("\\\\\"") ); // escape a single " because the arguments will be parsed - tmp.replace( QLatin1String("\""), QLatin1String("\\\"") ); + tmp.replace( QLatin1Char('\"'), QLatin1String("\\\"") ); if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) { // The argument must not end with a \ since this would be interpreted // as escaping the quote -- rather put the \ behind the quote: e.g. // rather use "foo"\ than "foo\" - QString endQuote(QLatin1String("\"")); + QString endQuote(QLatin1Char('\"')); int i = tmp.length(); while (i>0 && tmp.at(i-1) == QLatin1Char('\\')) { --i; - endQuote += QLatin1String("\\"); + endQuote += QLatin1Char('\\'); } args += QLatin1String(" \"") + tmp.left(i) + endQuote; } else { @@ -427,7 +427,7 @@ void QProcessPrivate::startProcess() QString fullPathProgram = program; if (!QDir::isAbsolutePath(fullPathProgram)) fullPathProgram = QFileInfo(fullPathProgram).absoluteFilePath(); - fullPathProgram.replace(QLatin1String("/"), QLatin1String("\\")); + fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\')); success = CreateProcessW((WCHAR*)fullPathProgram.utf16(), (WCHAR*)args.utf16(), 0, 0, false, 0, 0, 0, 0, pid); @@ -887,8 +887,8 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a #if defined(Q_OS_WINCE) QString fullPathProgram = program; if (!QDir::isAbsolutePath(fullPathProgram)) - fullPathProgram.prepend(QDir::currentPath().append(QLatin1String("/"))); - fullPathProgram.replace(QLatin1String("/"), QLatin1String("\\")); + fullPathProgram.prepend(QDir::currentPath().append(QLatin1Char('/'))); + fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\')); success = CreateProcessW((WCHAR*)fullPathProgram.utf16(), (WCHAR*)args.utf16(), 0, 0, false, CREATE_NEW_CONSOLE, 0, 0, 0, &pinfo); diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index 779a742..94dfd4d 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -449,7 +449,7 @@ QString QResource::absoluteFilePath() const } /*! - Returns true if the resource really exists in the resource heirarchy, + Returns true if the resource really exists in the resource hierarchy, false otherwise. */ @@ -623,14 +623,14 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const QString root = mappingRoot(); if(!root.isEmpty()) { if(root == path) { - path = QLatin1String("/"); + path = QLatin1Char('/'); } else { - if(!root.endsWith(QLatin1String("/"))) - root += QLatin1String("/"); + if(!root.endsWith(QLatin1Char('/'))) + root += QLatin1Char('/'); if(path.size() >= root.size() && path.startsWith(root)) path = path.mid(root.length()-1); if(path.isEmpty()) - path = QLatin1String("/"); + path = QLatin1Char('/'); } } } diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index 484e79a..6152518 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -2295,7 +2295,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, As mentioned in the \l{Fallback Mechanism} section, QSettings stores settings for an application in up to four locations, depending on whether the settings are user-specific or - system-wide and whether the the settings are application-specific + system-wide and whether the settings are application-specific or organization-wide. For simplicity, we're assuming the organization is called MySoft and the application is called Star Runner. @@ -3468,7 +3468,7 @@ void QSettings::setPath(Format format, Scope scope, const QString &path) \typedef QSettings::SettingsMap Typedef for QMap<QString, QVariant>. - + \sa registerFormat() */ @@ -3479,6 +3479,11 @@ void QSettings::setPath(Format format, Scope scope, const QString &path) \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 27 + \c ReadFunc is used in \c registerFormat() as a pointer to a function + that reads a set of key/value pairs. \c ReadFunc should read all the + options in one pass, and return all the settings in the \c SettingsMap + container, which is initially empty. + \sa WriteFunc, registerFormat() */ @@ -3489,6 +3494,10 @@ void QSettings::setPath(Format format, Scope scope, const QString &path) \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 28 + \c WriteFunc is used in \c registerFormat() as a pointer to a function + that writes a set of key/value pairs. \c WriteFunc is only called once, + so you need to output the settings in one go. + \sa ReadFunc, registerFormat() */ @@ -3504,7 +3513,7 @@ void QSettings::setPath(Format format, Scope scope, const QString &path) extension associated to the format (without the '.'). The \a readFunc and \a writeFunc parameters are pointers to - functions that read and write a set of (key, value) pairs. The + functions that read and write a set of key/value pairs. The QIODevice parameter to the read and write functions is always opened in binary mode (i.e., without the QIODevice::Text flag). diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h index dd72fd9..93d07e0 100644 --- a/src/corelib/io/qsettings_p.h +++ b/src/corelib/io/qsettings_p.h @@ -146,7 +146,7 @@ inline QString QSettingsGroup::toString() const return result; } -class Q_CORE_EXPORT QConfFile +class QConfFile { public: ParsedSettingsMap mergedKeyMap() const; diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp index a08c969..57f65d6 100644 --- a/src/corelib/io/qsettings_win.cpp +++ b/src/corelib/io/qsettings_win.cpp @@ -148,7 +148,7 @@ static QString errorCodeToString(DWORD errorCode) if (data != 0) LocalFree(data); }) - if (result.endsWith(QLatin1String("\n"))) + if (result.endsWith(QLatin1Char('\n'))) result.truncate(result.length() - 1); return result; diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 4856353..728bf4f 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -203,7 +203,7 @@ static int _gettemp(char *path, int *doopen, int domkdir, int slen) if (QDir::isAbsolutePath(QString::fromLatin1(path))) targetPath = QLatin1String(path); else - targetPath = QDir::currentPath().append(QLatin1String("/")) + QLatin1String(path); + targetPath = QDir::currentPath().append(QLatin1Char('/')) + QLatin1String(path); if ((*doopen = QT_OPEN(targetPath.toLocal8Bit(), O_CREAT|O_EXCL|O_RDWR @@ -291,12 +291,22 @@ class QTemporaryFileEngine : public QFSFileEngine { Q_DECLARE_PRIVATE(QFSFileEngine) public: - QTemporaryFileEngine(const QString &file) : QFSFileEngine(file) { } + QTemporaryFileEngine(const QString &file, bool fileIsTemplate = true) + : QFSFileEngine(file), filePathIsTemplate(fileIsTemplate) + { + } + ~QTemporaryFileEngine(); + bool isReallyOpen(); + void setFileName(const QString &file); + bool open(QIODevice::OpenMode flags); bool remove(); + bool rename(const QString &newName); bool close(); + + bool filePathIsTemplate; }; QTemporaryFileEngine::~QTemporaryFileEngine() @@ -304,16 +314,41 @@ QTemporaryFileEngine::~QTemporaryFileEngine() QFSFileEngine::close(); } +bool QTemporaryFileEngine::isReallyOpen() +{ + Q_D(QFSFileEngine); + + if (!((0 == d->fh) && (-1 == d->fd) +#if defined Q_OS_WIN + && (INVALID_HANDLE_VALUE == d->fileHandle) +#endif + )) + return true; + + return false; + +} + +void QTemporaryFileEngine::setFileName(const QString &file) +{ + // Really close the file, so we don't leak + QFSFileEngine::close(); + QFSFileEngine::setFileName(file); +} + bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) { Q_D(QFSFileEngine); + Q_ASSERT(!isReallyOpen()); + + if (!filePathIsTemplate) + return QFSFileEngine::open(openMode); QString qfilename = d->filePath; if(!qfilename.contains(QLatin1String("XXXXXX"))) qfilename += QLatin1String(".XXXXXX"); int suffixLength = qfilename.length() - (qfilename.lastIndexOf(QLatin1String("XXXXXX"), -1, Qt::CaseSensitive) + 6); - d->closeFileHandle = true; char *filename = qstrdup(qfilename.toLocal8Bit()); #ifndef Q_WS_WIN @@ -321,16 +356,20 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (fd != -1) { // First open the fd as an external file descriptor to // initialize the engine properly. - QFSFileEngine::open(openMode, fd); + if (QFSFileEngine::open(openMode, fd)) { - // Allow the engine to close the handle even if it's "external". - d->closeFileHandle = true; + // Allow the engine to close the handle even if it's "external". + d->closeFileHandle = true; - // Restore the file names (open() resets them). - d->filePath = QString::fromLocal8Bit(filename); //changed now! - d->nativeInitFileName(); - delete [] filename; - return true; + // Restore the file names (open() resets them). + d->filePath = QString::fromLocal8Bit(filename); //changed now! + filePathIsTemplate = false; + d->nativeInitFileName(); + delete [] filename; + return true; + } + + QT_CLOSE(fd); } delete [] filename; setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(errno)); @@ -342,6 +381,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) } d->filePath = QString::fromLocal8Bit(filename); + filePathIsTemplate = false; d->nativeInitFileName(); d->closeFileHandle = true; delete [] filename; @@ -355,9 +395,17 @@ bool QTemporaryFileEngine::remove() // Since the QTemporaryFileEngine::close() does not really close the file, // we must explicitly call QFSFileEngine::close() before we remove it. QFSFileEngine::close(); - bool removed = QFSFileEngine::remove(); - d->filePath.clear(); - return removed; + if (QFSFileEngine::remove()) { + d->filePath.clear(); + return true; + } + return false; +} + +bool QTemporaryFileEngine::rename(const QString &newName) +{ + QFSFileEngine::close(); + return QFSFileEngine::rename(newName); } bool QTemporaryFileEngine::close() @@ -379,17 +427,14 @@ protected: bool autoRemove; QString templateName; - mutable QTemporaryFileEngine *fileEngine; }; -QTemporaryFilePrivate::QTemporaryFilePrivate() : autoRemove(true), fileEngine(0) +QTemporaryFilePrivate::QTemporaryFilePrivate() : autoRemove(true) { } QTemporaryFilePrivate::~QTemporaryFilePrivate() { - delete fileEngine; - fileEngine = 0; } //************* QTemporaryFile @@ -421,8 +466,8 @@ QTemporaryFilePrivate::~QTemporaryFilePrivate() file will exist and be kept open internally by QTemporaryFile. The file name of the temporary file can be found by calling fileName(). - Note that this is only defined while the file is open; the function returns - an empty string before the file is opened and after it is closed. + Note that this is only defined after the file is first opened; the function + returns an empty string before this. A temporary file will have some static part of the name and some part that is calculated to be unique. The default filename \c @@ -592,7 +637,8 @@ void QTemporaryFile::setAutoRemove(bool b) QString QTemporaryFile::fileName() const { - if(!isOpen()) + Q_D(const QTemporaryFile); + if(d->fileName.isEmpty()) return QString(); return fileEngine()->fileName(QAbstractFileEngine::DefaultName); } @@ -686,8 +732,12 @@ QTemporaryFile *QTemporaryFile::createLocalFile(QFile &file) QAbstractFileEngine *QTemporaryFile::fileEngine() const { Q_D(const QTemporaryFile); - if(!d->fileEngine) - d->fileEngine = new QTemporaryFileEngine(d->templateName); + if(!d->fileEngine) { + if (d->fileName.isEmpty()) + d->fileEngine = new QTemporaryFileEngine(d->templateName); + else + d->fileEngine = new QTemporaryFileEngine(d->fileName, false); + } return d->fileEngine; } @@ -702,10 +752,13 @@ bool QTemporaryFile::open(OpenMode flags) { Q_D(QTemporaryFile); if (!d->fileName.isEmpty()) { - setOpenMode(flags); - return true; + if (static_cast<QTemporaryFileEngine*>(fileEngine())->isReallyOpen()) { + setOpenMode(flags); + return true; + } } + flags |= QIODevice::ReadWrite; if (QFile::open(flags)) { d->fileName = d->fileEngine->fileName(QAbstractFileEngine::DefaultName); return true; @@ -713,6 +766,8 @@ bool QTemporaryFile::open(OpenMode flags) return false; } +QT_END_NAMESPACE + #endif // QT_NO_TEMPORARYFILE -QT_END_NAMESPACE + diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 3c015da..7c925f1 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -67,8 +67,10 @@ static const int QTEXTSTREAM_BUFFERSIZE = 16384; \snippet doc/src/snippets/code/src_corelib_io_qtextstream.cpp 1 Note that you cannot use QTextStream::atEnd(), which returns true when you - have reached the end of the data stream, with stdin. - + have reached the end of the data stream, with stdin. The reason for this is + that as long as stdin doesn't give any input to the QTextStream, \c atEnd() + will return true even if the stdin is open and waiting for more characters. + Besides using QTextStream's constructors, you can also set the device or string QTextStream operates on by calling setDevice() or setString(). You can seek to a position by calling seek(), and @@ -331,7 +333,7 @@ public: this->stream = stream; } -public slots: +public Q_SLOTS: inline void flushStream() { stream->flush(); } private: @@ -2290,7 +2292,7 @@ bool QTextStreamPrivate::putNumber(qulonglong number, bool negative) // ShowBase flag set zero should be written as '00' if (number == 0 && base == 8 && numberFlags & QTextStream::ShowBase && result == QLatin1String("0")) { - result.prepend(QLatin1String("0")); + result.prepend(QLatin1Char('0')); } } return putString(result, true); diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 9ce9a2e..5846e23 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -4759,6 +4759,12 @@ void QUrl::setEncodedQueryItems(const QList<QPair<QByteArray, QByteArray> > &que Inserts the pair \a key = \a value into the query string of the URL. + The key/value pair is encoded before it is added to the query. The + pair is converted into separate strings internally. The \a key and + \a value is first encoded into UTF-8 and then delimited by the + character returned by valueDelimiter(). Each key/value pair is + delimited by the character returned by pairDelimiter(). + \sa addEncodedQueryItem() */ void QUrl::addQueryItem(const QString &key, const QString &value) @@ -5324,7 +5330,7 @@ QString QUrl::toString(FormattingOptions options) const url += QLatin1Char('/'); url += ourPath; // check if we need to remove trailing slashes - while ((options & StripTrailingSlash) && url.right(1) == QLatin1String("/")) + while ((options & StripTrailingSlash) && url.endsWith(QLatin1Char('/'))) url.chop(1); } @@ -5692,7 +5698,7 @@ QUrl QUrl::fromLocalFile(const QString &localFile) // magic for drives on windows if (deslashified.length() > 1 && deslashified.at(1) == QLatin1Char(':') && deslashified.at(0) != QLatin1Char('/')) { - url.setPath(QLatin1String("/") + deslashified); + url.setPath(QLatin1Char('/') + deslashified); // magic for shared drive on windows } else if (deslashified.startsWith(QLatin1String("//"))) { int indexOfPath = deslashified.indexOf(QLatin1Char('/'), 2); @@ -5722,7 +5728,7 @@ QString QUrl::toLocalFile() const // magic for shared drive on windows if (!d->host.isEmpty()) { tmp = QLatin1String("//") + d->host + (ourPath.length() > 0 && ourPath.at(0) != QLatin1Char('/') - ? QLatin1String("/") + ourPath : ourPath); + ? QLatin1Char('/') + ourPath : ourPath); } else { tmp = ourPath; // magic for drives on windows @@ -5970,7 +5976,7 @@ QDataStream &operator>>(QDataStream &in, QUrl &url) #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const QUrl &url) { - d.maybeSpace() << "QUrl(" << url.toString() << ")"; + d.maybeSpace() << "QUrl(" << url.toString() << ')'; return d.space(); } #endif diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index 9242092..e9c4a8d 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -223,7 +223,7 @@ public: inline QT3_SUPPORT QString ref() const { return fragment(); } inline QT3_SUPPORT void setRef(const QString &txt) { setFragment(txt); } inline QT3_SUPPORT bool hasRef() const { return !fragment().isEmpty(); } - inline QT3_SUPPORT void addPath(const QString &p) { setPath(path() + QLatin1String("/") + p); } + inline QT3_SUPPORT void addPath(const QString &p) { setPath(path() + QLatin1Char('/') + p); } QT3_SUPPORT void setFileName(const QString &txt); QT3_SUPPORT QString fileName() const; QT3_SUPPORT QString dirPath() const; diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index d90ecae..ecef555 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -12,7 +12,7 @@ HEADERS += \ kernel/qcoreevent.h \ kernel/qmetaobject.h \ kernel/qmetatype.h \ - kernel/qmimedata.h \ + kernel/qmimedata.h \ kernel/qobject.h \ kernel/qobjectdefs.h \ kernel/qsignalmapper.h \ @@ -27,8 +27,8 @@ HEADERS += \ kernel/qvariant_p.h \ kernel/qmetaobject_p.h \ kernel/qobject_p.h \ - kernel/qcoreglobaldata_p.h \ - kernel/qsharedmemory.h \ + kernel/qcoreglobaldata_p.h \ + kernel/qsharedmemory.h \ kernel/qsharedmemory_p.h \ kernel/qsystemsemaphore.h \ kernel/qsystemsemaphore_p.h \ @@ -43,7 +43,7 @@ SOURCES += \ kernel/qcoreevent.cpp \ kernel/qmetaobject.cpp \ kernel/qmetatype.cpp \ - kernel/qmimedata.cpp \ + kernel/qmimedata.cpp \ kernel/qobject.cpp \ kernel/qobjectcleanuphandler.cpp \ kernel/qsignalmapper.cpp \ @@ -53,7 +53,8 @@ SOURCES += \ kernel/qvariant.cpp \ kernel/qcoreglobaldata.cpp \ kernel/qsharedmemory.cpp \ - kernel/qsystemsemaphore.cpp + kernel/qsystemsemaphore.cpp \ + kernel/qpointer.cpp win32 { SOURCES += \ diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp index fd0e105..935c0aa 100644 --- a/src/corelib/kernel/qabstractitemmodel.cpp +++ b/src/corelib/kernel/qabstractitemmodel.cpp @@ -428,8 +428,8 @@ bool QPersistentModelIndex::isValid() const QDebug operator<<(QDebug dbg, const QModelIndex &idx) { #ifndef Q_BROKEN_DEBUG_STREAM - dbg.nospace() << "QModelIndex(" << idx.row() << "," << idx.column() - << "," << idx.internalPointer() << "," << idx.model() << ")"; + dbg.nospace() << "QModelIndex(" << idx.row() << ',' << idx.column() + << ',' << idx.internalPointer() << ',' << idx.model() << ')'; return dbg.space(); #else qWarning("This compiler doesn't support streaming QModelIndex to QDebug"); @@ -525,7 +525,7 @@ void QAbstractItemModelPrivate::rowsInserted(const QModelIndex &parent, if (data->index.isValid()) { persistent.insertMultiAtEnd(data->index, data); } else { - qWarning() << "QAbstractItemModel::endInsertRows: Invalid index (" << old.row() + count << "," << old.column() << ") in model" << q_func(); + qWarning() << "QAbstractItemModel::endInsertRows: Invalid index (" << old.row() + count << ',' << old.column() << ") in model" << q_func(); } } } @@ -574,7 +574,7 @@ void QAbstractItemModelPrivate::rowsRemoved(const QModelIndex &parent, if (data->index.isValid()) { persistent.insertMultiAtEnd(data->index, data); } else { - qWarning() << "QAbstractItemModel::endRemoveRows: Invalid index (" << old.row() - count << "," << old.column() << ") in model" << q_func(); + qWarning() << "QAbstractItemModel::endRemoveRows: Invalid index (" << old.row() - count << ',' << old.column() << ") in model" << q_func(); } } QVector<QPersistentModelIndexData *> persistent_invalidated = persistent.invalidated.pop(); @@ -619,7 +619,7 @@ void QAbstractItemModelPrivate::columnsInserted(const QModelIndex &parent, if (data->index.isValid()) { persistent.insertMultiAtEnd(data->index, data); } else { - qWarning() << "QAbstractItemModel::endInsertColumns: Invalid index (" << old.row() << "," << old.column() + count << ") in model" << q_func(); + qWarning() << "QAbstractItemModel::endInsertColumns: Invalid index (" << old.row() << ',' << old.column() + count << ") in model" << q_func(); } } } @@ -669,7 +669,7 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent, if (data->index.isValid()) { persistent.insertMultiAtEnd(data->index, data); } else { - qWarning() << "QAbstractItemModel::endRemoveColumns: Invalid index (" << old.row() << "," << old.column() - count << ") in model" << q_func(); + qWarning() << "QAbstractItemModel::endRemoveColumns: Invalid index (" << old.row() << ',' << old.column() - count << ") in model" << q_func(); } } QVector<QPersistentModelIndexData *> persistent_invalidated = persistent.invalidated.pop(); diff --git a/src/corelib/kernel/qabstractitemmodel_p.h b/src/corelib/kernel/qabstractitemmodel_p.h index df1a6ce..27f1b28 100644 --- a/src/corelib/kernel/qabstractitemmodel_p.h +++ b/src/corelib/kernel/qabstractitemmodel_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE -class Q_CORE_EXPORT QPersistentModelIndexData +class QPersistentModelIndexData { public: QPersistentModelIndexData() : model(0) {} diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index c21cf87..cb40f19 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -1710,7 +1710,7 @@ QString QCoreApplication::applicationDirPath() } QCoreApplicationPrivate *d = self->d_func(); - if (d->cachedApplicationDirPath == QString()) + if (d->cachedApplicationDirPath.isNull()) d->cachedApplicationDirPath = QFileInfo(applicationFilePath()).path(); return d->cachedApplicationDirPath; } @@ -1738,7 +1738,7 @@ QString QCoreApplication::applicationFilePath() } QCoreApplicationPrivate *d = self->d_func(); - if (d->cachedApplicationFilePath != QString()) + if (!d->cachedApplicationFilePath.isNull()) return d->cachedApplicationFilePath; #if defined( Q_WS_WIN ) @@ -1798,7 +1798,7 @@ QString QCoreApplication::applicationFilePath() */ QByteArray pEnv = qgetenv("PATH"); QDir currentDir = QDir::current(); - QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1String(":")); + QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1Char(':')); for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) { if ((*p).isEmpty()) continue; @@ -1908,7 +1908,7 @@ QStringList QCoreApplication::arguments() wchar_t tempFilename[MAX_PATH+1]; if (GetModuleFileNameW(0, tempFilename, MAX_PATH)) { tempFilename[MAX_PATH] = 0; - cmdline.prepend(QString(QLatin1String("\"")) + QString::fromUtf16((unsigned short *)tempFilename) + QString(QLatin1String("\" "))); + cmdline.prepend(QLatin1Char('\"') + QString::fromUtf16((unsigned short *)tempFilename) + QLatin1String("\" ")); } #endif // Q_OS_WINCE diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index 225821f..815a558 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -51,12 +51,11 @@ QT_BEGIN_NAMESPACE -// ############### DON'T EXPORT HERE!!! -Q_CORE_EXPORT char appFileName[MAX_PATH+1]; // application file name -Q_CORE_EXPORT char theAppName[MAX_PATH+1]; // application name -Q_CORE_EXPORT HINSTANCE appInst = 0; // handle to app instance -Q_CORE_EXPORT HINSTANCE appPrevInst = 0; // handle to prev app instance -Q_CORE_EXPORT int appCmdShow = 0; +char appFileName[MAX_PATH+1]; // application file name +char theAppName[MAX_PATH+1]; // application name +HINSTANCE appInst = 0; // handle to app instance +HINSTANCE appPrevInst = 0; // handle to prev app instance +int appCmdShow = 0; bool usingWinMain = false; // whether the qWinMain() is used or not Q_CORE_EXPORT HINSTANCE qWinAppInst() // get Windows app handle @@ -69,6 +68,12 @@ Q_CORE_EXPORT HINSTANCE qWinAppPrevInst() // get Windows prev app return appPrevInst; } +Q_CORE_EXPORT int qWinAppCmdShow() // get main window show command +{ + return appCmdShow; +} + + void set_winapp_name() { static bool already_set = false; @@ -89,6 +94,14 @@ void set_winapp_name() int l = qstrlen(theAppName); if ((l > 4) && !qstricmp(theAppName + l - 4, ".exe")) theAppName[l-4] = '\0'; // drop .exe extension + + if (appInst == 0) { + QT_WA({ + appInst = GetModuleHandle(0); + }, { + appInst = GetModuleHandleA(0); + }); + } } } @@ -134,11 +147,11 @@ Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char* str) staticCriticalSection.lock(); QT_WA({ QString s(QString::fromLocal8Bit(str)); - s += QLatin1String("\n"); + s += QLatin1Char('\n'); OutputDebugStringW((TCHAR*)s.utf16()); }, { QByteArray s(str); - s += "\n"; + s += '\n'; OutputDebugStringA(s.data()); }) staticCriticalSection.unlock(); @@ -173,14 +186,14 @@ void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam, // Create command line - set_winapp_name(); - argv = qWinCmdLine<char>(cmdParam, int(strlen(cmdParam)), argc); // Get Windows parameters appInst = instance; appPrevInst = prevInstance; appCmdShow = cmdShow; + + set_winapp_name(); } /*! @@ -618,7 +631,7 @@ QString valueCheck(uint actual, ...) #ifdef Q_CC_BOR -Q_CORE_EXPORT QString decodeMSG(const MSG& msg) +QString decodeMSG(const MSG& msg) { return QString::fromLatin1("THis is not supported on Borland"); } @@ -827,7 +840,7 @@ QString decodeMSG(const MSG& msg) FLGSTR(ISC_SHOWUICANDIDATEWINDOW << 2), FLGSTR(ISC_SHOWUICANDIDATEWINDOW << 3), FLAG_STRING()); - parameters.sprintf("Input context(%s) Show flags(%s)", (fSet?"Active":"Inactive"), showFlgs.toLatin1().data()); + parameters.sprintf("Input context(%s) Show flags(%s)", (fSet? "Active" : "Inactive"), showFlgs.toLatin1().data()); } break; #endif diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index 11a2d3c..d6b0174 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -264,6 +264,8 @@ QT_BEGIN_NAMESPACE \omitvalue NetworkReplyUpdated \omitvalue FutureCallOut \omitvalue CocoaRequestModal + \omitvalue Wrapped + \omitvalue Signal */ /*! diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h index fa472e6..18188a8 100644 --- a/src/corelib/kernel/qcoreevent.h +++ b/src/corelib/kernel/qcoreevent.h @@ -44,6 +44,7 @@ #include <QtCore/qnamespace.h> #include <QtCore/qbytearray.h> +#include <QtCore/qobjectdefs.h> QT_BEGIN_HEADER @@ -54,7 +55,9 @@ QT_MODULE(Core) class QEventPrivate; class Q_CORE_EXPORT QEvent // event base class { + Q_GADGET QDOC_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) + Q_ENUMS(Type) public: enum Type { /* @@ -266,7 +269,10 @@ public: CocoaRequestModal = 190, // Internal for requesting an application modal Cocoa Window MacGLClearDrawable = 191, // Internal Cocoa, the window has changed, so we must clear - // 512 reserved for Qt Jambi's MetaCall event + Signal = 192, + Wrapped = 193, + + // 512 reserved for Qt Jambi's MetaCall event // 513 reserved for Qt Jambi's DeleteOnMainThread event User = 1000, // first user event id diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h index 41329cf..8c08bd2 100644 --- a/src/corelib/kernel/qeventdispatcher_unix_p.h +++ b/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -153,14 +153,14 @@ public: int activateTimers(); }; -struct Q_CORE_EXPORT QSockNot +struct QSockNot { QSocketNotifier *obj; int fd; fd_set *queue; }; -class Q_CORE_EXPORT QSockNotType +class QSockNotType { public: QSockNotType(); diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index c4061f4..2dd5534 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -396,13 +396,6 @@ Q_CORE_EXPORT bool winPostMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa { return PostMessageA(hWnd, msg, wParam, lParam); }); } -Q_CORE_EXPORT bool winGetMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin, - UINT wMsgFilterMax) -{ - QT_WA({ return GetMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax); } , - { return GetMessageA(msg, hWnd, wMsgFilterMin, wMsgFilterMax); }); -} - // This function is called by a workerthread void WINAPI CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/, DWORD_PTR user, DWORD_PTR /*reserved*/, DWORD_PTR /*reserved*/) { diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 05015c0..be622d9 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -58,6 +58,7 @@ #include <qsemaphore.h> #include <private/qorderedmutexlocker_p.h> +#include <private/qmutexpool_p.h> #include <new> @@ -70,7 +71,7 @@ static int DIRECT_CONNECTION_ONLY = 0; static int *queuedConnectionTypes(const QList<QByteArray> &typeNames) { - int *types = static_cast<int *>(qMalloc((typeNames.count() + 1) * sizeof(int))); + int *types = new int [typeNames.count() + 1]; for (int i = 0; i < typeNames.count(); ++i) { const QByteArray typeName = typeNames.at(i); if (typeName.endsWith('*')) @@ -82,7 +83,7 @@ static int *queuedConnectionTypes(const QList<QByteArray> &typeNames) qWarning("QObject::connect: Cannot queue arguments of type '%s'\n" "(Make sure '%s' is registered using qRegisterMetaType().)", typeName.constData(), typeName.constData()); - qFree(types); + delete [] types; return 0; } } @@ -91,12 +92,34 @@ static int *queuedConnectionTypes(const QList<QByteArray> &typeNames) return types; } +static QBasicAtomicPointer<QMutexPool> signalSlotMutexes = Q_BASIC_ATOMIC_INITIALIZER(0); +static QBasicAtomicInt objectCount = Q_BASIC_ATOMIC_INITIALIZER(0); + +/** \internal + * mutex to be locked when accessing the connectionlists or the senders list + */ +static QMutex *signalSlotLock(const QObject *o) +{ + if (!signalSlotMutexes) { + QMutexPool *mp = new QMutexPool; + if (!signalSlotMutexes.testAndSetOrdered(0, mp)) { + delete mp; + } + } + return signalSlotMutexes->get(o); +} + extern "C" Q_CORE_EXPORT void qt_addObject(QObject *) { + objectCount.ref(); } extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) { + if(!objectCount.deref()) { + QMutexPool *old = signalSlotMutexes.fetchAndStoreAcquire(0); + delete old; + } } QObjectPrivate::QObjectPrivate(int version) @@ -216,19 +239,20 @@ public: } }; +// Used by QAccessibleWidget bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const { Q_Q(const QObject); int signal_index = q->metaObject()->indexOfSignal(signal); if (signal_index < 0) return false; - QMutexLocker locker(&threadData->mutex); + QMutexLocker locker(signalSlotLock(q)); if (connectionLists) { if (signal_index < connectionLists->count()) { const ConnectionList &connectionList = connectionLists->at(signal_index); for (int i = 0; i < connectionList.count(); ++i) { - const QObjectPrivate::Connection &c = connectionList.at(i); - if (c.receiver && c.receiver == receiver) + const QObjectPrivate::Connection *c = connectionList.at(i); + if (c->receiver == receiver) return true; } } @@ -236,6 +260,7 @@ bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const return false; } +// Used by QAccessibleWidget QObjectList QObjectPrivate::receiverList(const char *signal) const { Q_Q(const QObject); @@ -243,26 +268,27 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const int signal_index = q->metaObject()->indexOfSignal(signal); if (signal_index < 0) return returnValue; - QMutexLocker locker(&threadData->mutex); + QMutexLocker locker(signalSlotLock(q)); if (connectionLists) { if (signal_index < connectionLists->count()) { const ConnectionList &connectionList = connectionLists->at(signal_index); for (int i = 0; i < connectionList.count(); ++i) { - const QObjectPrivate::Connection &c = connectionList.at(i); - if (c.receiver) - returnValue << c.receiver; + const QObjectPrivate::Connection *c = connectionList.at(i); + if (c->receiver) + returnValue << c->receiver; } } } return returnValue; } +// Used by QAccessibleWidget QObjectList QObjectPrivate::senderList() const { QObjectList returnValue; - QMutexLocker locker(&threadData->mutex); + QMutexLocker locker(signalSlotLock(q_func())); for (int i = 0; i < senders.count(); ++i) - returnValue << senders.at(i).sender; + returnValue << senders.at(i)->sender; return returnValue; } @@ -274,33 +300,10 @@ void QObjectPrivate::addConnection(int signal, Connection *c) connectionLists->resize(signal + 1); ConnectionList &connectionList = (*connectionLists)[signal]; - connectionList.append(*c); - + connectionList.append(c); cleanConnectionLists(); } -void QObjectPrivate::removeReceiver(int signal, QObject *receiver) -{ - if (!connectionLists) - return; - - if (signal >= connectionLists->count()) - return; - - ConnectionList &connectionList = (*connectionLists)[signal]; - for (int i = 0; i < connectionList.count(); ++i) { - Connection &c = connectionList[i]; - if (c.receiver == receiver) { - c.receiver = 0; - if (c.argumentTypes && c.argumentTypes != &DIRECT_CONNECTION_ONLY) { - qFree(c.argumentTypes); - c.argumentTypes = 0; - } - connectionLists->dirty = true; - } - } -} - void QObjectPrivate::cleanConnectionLists() { if (connectionLists->dirty && !connectionLists->inUse) { @@ -308,55 +311,17 @@ void QObjectPrivate::cleanConnectionLists() for (int signal = -1; signal < connectionLists->count(); ++signal) { QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal]; for (int i = 0; i < connectionList.count(); ++i) { - const QObjectPrivate::Connection &c = connectionList.at(i); - if (!c.receiver) + QObjectPrivate::Connection *c = connectionList.at(i); + if (!c->receiver) { + delete c; connectionList.removeAt(i--); + } } } connectionLists->dirty = false; } } -void QObjectPrivate::refSender(QObject *sender, int signal) -{ - for (int i = 0; i < senders.count(); ++i) { - Sender &s = senders[i]; - if (s.sender == sender && s.signal == signal) { - ++s.ref; - return; - } - } - - Sender s = { sender, signal, 1 }; - senders.append(s); -} - -void QObjectPrivate::derefSender(QObject *sender, int signal) -{ - for (int i = 0; i < senders.count(); ++i) { - Sender &s = senders[i]; - if (s.sender == sender && s.signal == signal) { - if (--s.ref == 0) { - senders.removeAt(i); - break; - } - } - } - // Q_ASSERT_X(false, "QObjectPrivate::derefSender", "sender not found"); -} - -void QObjectPrivate::removeSender(QObject *sender, int signal) -{ - for (int i = 0; i < senders.count(); ++i) { - Sender &s = senders[i]; - if (s.sender == sender && s.signal == signal) { - senders.removeAt(i); - return; - } - } - // Q_ASSERT_X(false, "QObjectPrivate::removeSender", "sender not found"); -} - QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver, Sender *sender) { @@ -769,7 +734,7 @@ QObject::~QObject() emit destroyed(this); { - QMutexLocker locker(&d->threadData->mutex); + QMutexLocker locker(signalSlotLock(this)); // set ref to zero to indicate that this object has been deleted if (d->currentSender != 0) @@ -782,23 +747,21 @@ QObject::~QObject() for (int signal = -1; signal < d->connectionLists->count(); ++signal) { QObjectPrivate::ConnectionList &connectionList = (*d->connectionLists)[signal]; for (int i = 0; i < connectionList.count(); ++i) { - QObjectPrivate::Connection *c = &connectionList[i]; - if (!c->receiver) + QObjectPrivate::Connection *c = connectionList[i]; + if (!c->receiver) { + delete c; continue; + } - QMutex *m = &c->receiver->d_func()->threadData->mutex; + QMutex *m = signalSlotLock(c->receiver); bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m); - c = &connectionList[i]; + c = connectionList[i]; if (c->receiver) - c->receiver->d_func()->removeSender(this, signal); + c->receiver->d_func()->senders.removeOne(c); if (needToUnlock) m->unlock(); - if (c->argumentTypes && c->argumentTypes != &DIRECT_CONNECTION_ONLY) { - qFree(c->argumentTypes); - c->argumentTypes = 0; - } - c->receiver = 0; + delete c; } } @@ -811,18 +774,26 @@ QObject::~QObject() } // disconnect all senders - for (int i = 0; i < d->senders.count(); ++i) { - QObjectPrivate::Sender *s = &d->senders[i]; - if (!s->sender) - continue; + for (int i = 0; i < d->senders.count(); ) { + QObjectPrivate::Connection *s = d->senders[i]; - QMutex *m = &s->sender->d_func()->threadData->mutex; + QMutex *m = signalSlotLock(s->sender); bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m); - s = &d->senders[i]; - if (s->sender) - s->sender->d_func()->removeReceiver(s->signal, this); + if (m < locker.mutex()) { + if (i >= d->senders.count() || s != d->senders[i]) { + if (needToUnlock) + m->unlock(); + continue; + } + } + s->receiver = 0; + QObjectConnectionListVector *senderLists = s->sender->d_func()->connectionLists; + if (senderLists) + senderLists->dirty = true; + if (needToUnlock) m->unlock(); + ++i; } d->senders.clear(); @@ -866,6 +837,12 @@ QObject::~QObject() d_ptr = 0; } +QObjectPrivate::Connection::~Connection() +{ + if (argumentTypes != &DIRECT_CONNECTION_ONLY) + delete [] argumentTypes; +} + /*! \fn QMetaObject *QObject::metaObject() const @@ -2297,14 +2274,14 @@ QObject *QObject::sender() const { Q_D(const QObject); - QMutexLocker(&d->threadData->mutex); + QMutexLocker(signalSlotLock(this)); if (!d->currentSender) return 0; // Return 0 if d->currentSender isn't in d->senders bool found = false; for (int i = 0; !found && i < d->senders.count(); ++i) - found = (d->senders.at(i).sender == d->currentSender->sender); + found = (d->senders.at(i)->sender == d->currentSender->sender); if (!found) return 0; return d->currentSender->sender; @@ -2353,14 +2330,14 @@ int QObject::receivers(const char *signal) const } Q_D(const QObject); - QMutexLocker locker(&d->threadData->mutex); + QMutexLocker locker(signalSlotLock(this)); if (d->connectionLists) { if (signal_index < d->connectionLists->count()) { const QObjectPrivate::ConnectionList &connectionList = d->connectionLists->at(signal_index); for (int i = 0; i < connectionList.count(); ++i) { - const QObjectPrivate::Connection &c = connectionList.at(i); - receivers += c.receiver ? 1 : 0; + const QObjectPrivate::Connection *c = connectionList.at(i); + receivers += c->receiver ? 1 : 0; } } } @@ -2399,7 +2376,8 @@ int QObject::receivers(const char *signal) const can be connected to one slot. If a signal is connected to several slots, the slots are activated - in an arbitrary order when the signal is emitted. + in the same order as the order the connection was made, when the + signal is emitted. The function returns true if it successfully connects the signal to the slot. It will return false if it cannot create the @@ -2407,9 +2385,13 @@ int QObject::receivers(const char *signal) const existence of either \a signal or \a method, or if their signatures aren't compatible. - For every connection you make, a signal is emitted; two signals are emitted - for duplicate connections. You can break all of these connections with a - single disconnect() call. + By default, a signal is emitted for every connection you make; + two signals are emitted for duplicate connections. You can break + all of these connections with a single disconnect() call. + If you pass the Qt::UniqueConnection \a type, the connection will only + be made if it is not a duplicate. If there is already a duplicate + (exact same signal to the exact same slot on the same objects), + the connection will fail and connect will return false The optional \a type parameter describes the type of connection to establish. In particular, it determines whether a particular @@ -2542,7 +2524,8 @@ bool QObject::connect(const QObject *sender, const char *signal, } } #endif - QMetaObject::connect(sender, signal_index, receiver, method_index, type, types); + if (!QMetaObject::connect(sender, signal_index, receiver, method_index, type, types)) + return false; const_cast<QObject*>(sender)->connectNotify(signal - 1); return true; } @@ -2793,20 +2776,31 @@ bool QMetaObject::connect(const QObject *sender, int signal_index, QObject *s = const_cast<QObject *>(sender); QObject *r = const_cast<QObject *>(receiver); - QOrderedMutexLocker locker(&s->d_func()->threadData->mutex, - &r->d_func()->threadData->mutex); + QOrderedMutexLocker locker(signalSlotLock(sender), + signalSlotLock(receiver)); -#if defined(Q_CC_HPACC) && defined(QT_ARCH_PARISC) - QObjectPrivate::Connection c; - c.receiver = r; - c.method = method_index; - c.connectionType = type; - c.argumentTypes = types; -#else - QObjectPrivate::Connection c = { r, method_index, type, Q_BASIC_ATOMIC_INITIALIZER(types) }; -#endif - s->d_func()->addConnection(signal_index, &c); - r->d_func()->refSender(s, signal_index); + if (type & Qt::UniqueConnection) { + QObjectConnectionListVector *connectionLists = s->d_func()->connectionLists; + if (connectionLists && connectionLists->count() > signal_index) { + QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal_index]; + for (int i = 0; i < connectionList.count(); ++i) { + QObjectPrivate::Connection *c2 = connectionList.at(i); + if (c2->receiver == receiver && c2->method == method_index) + return false; + } + } + type &= Qt::UniqueConnection - 1; + } + + QObjectPrivate::Connection *c = new QObjectPrivate::Connection; + c->sender = s; + c->receiver = r; + c->method = method_index; + c->connectionType = type; + c->argumentTypes = types; + + s->d_func()->addConnection(signal_index, c); + r->d_func()->senders.append(c); if (signal_index < 0) sender->d_func()->connectedSignals = ~0u; @@ -2828,8 +2822,8 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, QObject *s = const_cast<QObject *>(sender); QObject *r = const_cast<QObject *>(receiver); - QMutex *senderMutex = &s->d_func()->threadData->mutex; - QMutex *receiverMutex = r ? &r->d_func()->threadData->mutex : 0; + QMutex *senderMutex = signalSlotLock(sender); + QMutex *receiverMutex = receiver ? signalSlotLock(receiver) : 0; QOrderedMutexLocker locker(senderMutex, receiverMutex); QObjectConnectionListVector *connectionLists = s->d_func()->connectionLists; @@ -2845,27 +2839,23 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, for (signal_index = -1; signal_index < connectionLists->count(); ++signal_index) { QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal_index]; for (int i = 0; i < connectionList.count(); ++i) { - QObjectPrivate::Connection *c = &connectionList[i]; + QObjectPrivate::Connection *c = connectionList[i]; if (c->receiver && (r == 0 || (c->receiver == r && (method_index < 0 || c->method == method_index)))) { - QMutex *m = &c->receiver->d_func()->threadData->mutex; + QMutex *m = signalSlotLock(c->receiver); + bool needToUnlock = false; if (!receiverMutex && senderMutex != m) { // need to relock this receiver and sender in the correct order - bool needToUnlock = QOrderedMutexLocker::relock(senderMutex, m); - c = &connectionList[i]; - if (c->receiver) - c->receiver->d_func()->derefSender(s, signal_index); - if (needToUnlock) - m->unlock(); - } else { - // no need to unlock - c->receiver->d_func()->derefSender(s, signal_index); - } - if (c->argumentTypes && c->argumentTypes != &DIRECT_CONNECTION_ONLY) { - qFree(c->argumentTypes); - c->argumentTypes = 0; + needToUnlock = QOrderedMutexLocker::relock(senderMutex, m); + c = connectionList[i]; } + if (c->receiver) + c->receiver->d_func()->senders.removeOne(c); + + if (needToUnlock) + m->unlock(); + c->receiver = 0; success = true; @@ -2876,27 +2866,22 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, } else if (signal_index < connectionLists->count()) { QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal_index]; for (int i = 0; i < connectionList.count(); ++i) { - QObjectPrivate::Connection *c = &connectionList[i]; + QObjectPrivate::Connection *c = connectionList[i]; if (c->receiver && (r == 0 || (c->receiver == r && (method_index < 0 || c->method == method_index)))) { - QMutex *m = &c->receiver->d_func()->threadData->mutex; + QMutex *m = signalSlotLock(c->receiver); + bool needToUnlock = false; if (!receiverMutex && senderMutex != m) { // need to relock this receiver and sender in the correct order - bool needToUnlock = QOrderedMutexLocker::relock(senderMutex, m); - c = &connectionList[i]; - if (c->receiver) - c->receiver->d_func()->derefSender(s, signal_index); - if (needToUnlock) - m->unlock(); - } else { - // no need to unlock - c->receiver->d_func()->derefSender(s, signal_index); - } - if (c->argumentTypes && c->argumentTypes != &DIRECT_CONNECTION_ONLY) { - qFree(c->argumentTypes); - c->argumentTypes = 0; + needToUnlock = QOrderedMutexLocker::relock(senderMutex, m); + c = connectionList[i]; } + if (c->receiver) + c->receiver->d_func()->senders.removeOne(c); + + if (needToUnlock) + m->unlock(); c->receiver = 0; success = true; @@ -2979,32 +2964,31 @@ void QMetaObject::connectSlotsByName(QObject *o) } } -static void queued_activate(QObject *sender, int signal, const QObjectPrivate::Connection &c, +static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv, QSemaphore *semaphore = 0) { - if (!c.argumentTypes || c.argumentTypes != &DIRECT_CONNECTION_ONLY) { + if (!c->argumentTypes && c->argumentTypes != &DIRECT_CONNECTION_ONLY) { QMetaMethod m = sender->metaObject()->method(signal); - QObjectPrivate::Connection &x = const_cast<QObjectPrivate::Connection &>(c); int *tmp = queuedConnectionTypes(m.parameterTypes()); if (!tmp) // cannot queue arguments tmp = &DIRECT_CONNECTION_ONLY; - if (!x.argumentTypes.testAndSetOrdered(0, tmp)) { + if (!c->argumentTypes.testAndSetOrdered(0, tmp)) { if (tmp != &DIRECT_CONNECTION_ONLY) - qFree(tmp); + delete [] tmp; } } - if (c.argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate + if (c->argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate return; int nargs = 1; // include return type - while (c.argumentTypes[nargs-1]) + while (c->argumentTypes[nargs-1]) ++nargs; int *types = (int *) qMalloc(nargs*sizeof(int)); void **args = (void **) qMalloc(nargs*sizeof(void *)); types[0] = 0; // return type args[0] = 0; // return value for (int n = 1; n < nargs; ++n) - args[n] = QMetaType::construct((types[n] = c.argumentTypes[n-1]), argv[n]); - QCoreApplication::postEvent(c.receiver, new QMetaCallEvent(c.method, + args[n] = QMetaType::construct((types[n] = c->argumentTypes[n-1]), argv[n]); + QCoreApplication::postEvent(c->receiver, new QMetaCallEvent(c->method, sender, signal, nargs, @@ -3013,13 +2997,13 @@ static void queued_activate(QObject *sender, int signal, const QObjectPrivate::C semaphore)); } -static void blocking_activate(QObject *sender, int signal, const QObjectPrivate::Connection &c, void **argv) +static void blocking_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv) { - if (QThread::currentThread() == c.receiver->thread()) { + if (QThread::currentThread() == c->receiver->thread()) { qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: " "Sender is %s(%p), receiver is %s(%p)", sender->metaObject()->className(), sender, - c.receiver->metaObject()->className(), c.receiver); + c->receiver->metaObject()->className(), c->receiver); } #ifdef QT_NO_THREAD @@ -3027,7 +3011,7 @@ static void blocking_activate(QObject *sender, int signal, const QObjectPrivate: #else QSemaphore semaphore; queued_activate(sender, signal, c, argv, &semaphore); - QMutex *mutex = &QThreadData::get2(sender->thread())->mutex; + QMutex *mutex = signalSlotLock(sender); mutex->unlock(); semaphore.acquire(); mutex->lock(); @@ -3047,7 +3031,7 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal argv ? argv : empty_argv); } - QMutexLocker locker(&sender->d_func()->threadData->mutex); + QMutexLocker locker(signalSlotLock(sender)); QThreadData *currentThreadData = QThreadData::current(); QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; @@ -3069,7 +3053,7 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal } int count = connectionLists->at(signal).count(); for (int i = 0; i < count; ++i) { - const QObjectPrivate::Connection *c = &connectionLists->at(signal)[i]; + QObjectPrivate::Connection *c = connectionLists->at(signal)[i]; if (!c->receiver) continue; @@ -3081,10 +3065,10 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal && (currentThreadData != sender->d_func()->threadData || receiver->d_func()->threadData != sender->d_func()->threadData)) || (c->connectionType == Qt::QueuedConnection)) { - queued_activate(sender, signal, *c, argv); + queued_activate(sender, signal, c, argv); continue; } else if (c->connectionType == Qt::BlockingQueuedConnection) { - blocking_activate(sender, signal, *c, argv); + blocking_activate(sender, signal, c, argv); continue; } @@ -3399,7 +3383,7 @@ void QObject::dumpObjectInfo() objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data()); Q_D(QObject); - QMutexLocker locker(&d->threadData->mutex); + QMutexLocker locker(signalSlotLock(this)); // first, look for connections where this object is the sender qDebug(" SIGNALS OUT"); @@ -3412,16 +3396,16 @@ void QObject::dumpObjectInfo() // receivers const QObjectPrivate::ConnectionList &connectionList = d->connectionLists->at(signal_index); for (int i = 0; i < connectionList.count(); ++i) { - const QObjectPrivate::Connection &c = connectionList.at(i); - if (!c.receiver) { + const QObjectPrivate::Connection *c = connectionList.at(i); + if (!c->receiver) { qDebug(" <Disconnected receiver>"); continue; } - const QMetaObject *receiverMetaObject = c.receiver->metaObject(); - const QMetaMethod method = receiverMetaObject->method(c.method); + const QMetaObject *receiverMetaObject = c->receiver->metaObject(); + const QMetaMethod method = receiverMetaObject->method(c->method); qDebug(" --> %s::%s %s", receiverMetaObject->className(), - c.receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c.receiver->objectName()), + c->receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver->objectName()), method.signature()); } } @@ -3434,13 +3418,12 @@ void QObject::dumpObjectInfo() if (!d->senders.isEmpty()) { for (int i = 0; i < d->senders.count(); ++i) { - const QObjectPrivate::Sender &s = d->senders.at(i); - const QMetaObject *senderMetaObject = s.sender->metaObject(); - const QMetaMethod signal = senderMetaObject->method(s.signal); - qDebug(" <-- %s::%s %s", - senderMetaObject->className(), - s.sender->objectName().isEmpty() ? "unnamed" : qPrintable(s.sender->objectName()), - signal.signature()); + const QObjectPrivate::Connection *s = d->senders.at(i); + const QMetaMethod slot = metaObject()->method(s->method); + qDebug(" <-- %s::%s %s", + s->sender->metaObject()->className(), + s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()), + slot.signature()); } } else { qDebug(" <None>"); @@ -3496,7 +3479,7 @@ QDebug operator<<(QDebug dbg, const QObject *o) { #ifndef Q_BROKEN_DEBUG_STREAM if (!o) return dbg << "QObject(0x0) "; - dbg.nospace() << o->metaObject()->className() << "(" << (void *)o; + dbg.nospace() << o->metaObject()->className() << '(' << (void *)o; if (!o->objectName().isEmpty()) dbg << ", name = " << o->objectName(); dbg << ')'; diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index b324334..96d79af 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -114,7 +114,6 @@ public: int signal; int ref; }; - // object currently activating the object Sender *currentSender; @@ -148,22 +147,20 @@ public: // Note: you must hold the signalSlotLock() before accessing the lists below or calling the functions struct Connection { + QObject *sender; QObject *receiver; int method; uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking QBasicAtomicPointer<int> argumentTypes; + ~Connection(); }; - typedef QList<Connection> ConnectionList; + typedef QList<Connection *> ConnectionList; QObjectConnectionListVector *connectionLists; void addConnection(int signal, Connection *c); - void removeReceiver(int signal, QObject *receiver); void cleanConnectionLists(); - QList<Sender> senders; - void refSender(QObject *sender, int signal); - void derefSender(QObject *sender, int signal); - void removeSender(QObject *sender, int signal); + ConnectionList senders; static Sender *setCurrentSender(QObject *receiver, Sender *sender); @@ -208,7 +205,7 @@ private: QSemaphore *semaphore_; }; -class Q_CORE_EXPORT QBoolBlocker +class QBoolBlocker { public: inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;} diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp index 9853079..87e154f 100644 --- a/src/corelib/kernel/qsharedmemory.cpp +++ b/src/corelib/kernel/qsharedmemory.cpp @@ -129,6 +129,10 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, detached from the segment, and no references to the segment remain. Do not mix using QtSharedMemory and QSharedMemory. Port everything to QSharedMemory. + + \warning QSharedMemory changes the key in a Qt-specific way. + It is therefore currently not possible to use the shared memory of + non-Qt applications with QSharedMemory. */ /*! diff --git a/src/corelib/kernel/qsharedmemory_unix.cpp b/src/corelib/kernel/qsharedmemory_unix.cpp index cd248dc..9187ad3 100644 --- a/src/corelib/kernel/qsharedmemory_unix.cpp +++ b/src/corelib/kernel/qsharedmemory_unix.cpp @@ -47,9 +47,10 @@ #include <qdir.h> #include <qdebug.h> +#include <errno.h> + #ifndef QT_NO_SHAREDMEMORY -#include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> diff --git a/src/corelib/kernel/qsystemsemaphore_p.h b/src/corelib/kernel/qsystemsemaphore_p.h index 81d4f10..a4a7389 100644 --- a/src/corelib/kernel/qsystemsemaphore_p.h +++ b/src/corelib/kernel/qsystemsemaphore_p.h @@ -101,9 +101,9 @@ public: QSystemSemaphore::SystemSemaphoreError error; }; -#endif // QT_NO_SYSTEMSEMAPHORE +QT_END_NAMESPACE +#endif // QT_NO_SYSTEMSEMAPHORE -QT_END_NAMESPACE #endif // QSYSTEMSEMAPHORE_P_H diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 01e81ab..08821d4 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -77,7 +77,7 @@ QT_BEGIN_NAMESPACE In multithreaded applications, you can use QTimer in any thread that has an event loop. To start an event loop from a non-GUI - thread, use QThread::exec(). Qt uses the the timer's + thread, use QThread::exec(). Qt uses the timer's \l{QObject::thread()}{thread affinity} to determine which thread will emit the \l{QTimer::}{timeout()} signal. Because of this, you must start and stop the timer in its thread; it is not possible to @@ -269,7 +269,7 @@ class QSingleShotTimer : public QObject public: ~QSingleShotTimer(); QSingleShotTimer(int msec, QObject *r, const char * m); -signals: +Q_SIGNALS: void timeout(); protected: void timerEvent(QTimerEvent *); diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index 77d6599..3e4b467 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -819,6 +819,6 @@ bool QTranslator::isEmpty() const Use translate(\a context, \a sourceText, \a comment) instead. */ -#endif // QT_NO_TRANSLATION - QT_END_NAMESPACE + +#endif // QT_NO_TRANSLATION diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index b53e91f..2ff9818 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -1021,7 +1021,7 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result, #if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) static void streamDebug(QDebug dbg, const QVariant &v) { - switch (v.type()) { + switch (v.userType()) { case QVariant::Int: dbg.nospace() << v.toInt(); break; @@ -1034,6 +1034,9 @@ static void streamDebug(QDebug dbg, const QVariant &v) case QVariant::ULongLong: dbg.nospace() << v.toULongLong(); break; + case QMetaType::Float: + dbg.nospace() << qVariantValue<float>(v); + break; case QVariant::Double: dbg.nospace() << v.toDouble(); break; @@ -1173,8 +1176,9 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; and versatile, but may prove less memory and speed efficient than storing specific types in standard data structures. - QVariant also supports the notion of null values, where you have - a defined type with no value set. + QVariant also supports the notion of null values, where you can + have a defined type with no value set. However, note that QVariant + types can only be cast when they have had a value set. \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 1 diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 08bd2d0..de1baac 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -71,7 +71,7 @@ static QString qdlerror() #else const char *err = strerror(errno); #endif - return err ? QLatin1String("(")+QString::fromLocal8Bit(err) + QLatin1String(")"): QString(); + return err ? QLatin1Char('(') + QString::fromLocal8Bit(err) + QLatin1Char(')'): QString(); } bool QLibraryPrivate::load_sys() diff --git a/src/corelib/plugin/qplugin.h b/src/corelib/plugin/qplugin.h index 4d0e53c..121a875 100644 --- a/src/corelib/plugin/qplugin.h +++ b/src/corelib/plugin/qplugin.h @@ -63,6 +63,21 @@ typedef QObject *(*QtPluginInstanceFunction)(); void Q_CORE_EXPORT qRegisterStaticPluginInstanceFunction(QtPluginInstanceFunction function); +struct qt_plugin_instance_deleter +{ + qt_plugin_instance_deleter(QPointer<QObject> &instance) + : instance_(instance) + { + } + + ~qt_plugin_instance_deleter() + { + delete instance_; + } + + QPointer<QObject> &instance_; +}; + #define Q_IMPORT_PLUGIN(PLUGIN) \ extern QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance_##PLUGIN(); \ class Static##PLUGIN##PluginInstance{ \ @@ -76,8 +91,10 @@ void Q_CORE_EXPORT qRegisterStaticPluginInstanceFunction(QtPluginInstanceFunctio #define Q_PLUGIN_INSTANCE(IMPLEMENTATION) \ { \ static QT_PREPEND_NAMESPACE(QPointer)<QT_PREPEND_NAMESPACE(QObject)> _instance; \ - if (!_instance) \ + if (!_instance) { \ + static QT_PREPEND_NAMESPACE(qt_plugin_instance_deleter) deleter(_instance); \ _instance = new IMPLEMENTATION; \ + } \ return _instance; \ } diff --git a/src/corelib/statemachine/qabstractstate.cpp b/src/corelib/statemachine/qabstractstate.cpp new file mode 100644 index 0000000..942722f --- /dev/null +++ b/src/corelib/statemachine/qabstractstate.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstractstate.h" +#include "qabstractstate_p.h" +#include "qstate.h" +#include "qstate_p.h" +#include "qstatemachine.h" +#include "qstatemachine_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAbstractState + + \brief The QAbstractState class is the base class of states of a QStateMachine. + + \since 4.6 + \ingroup statemachine + + The QAbstractState class is the abstract base class of states that are part + of a QStateMachine. It defines the interface that all state objects have in + common. QAbstractState is part of \l{The State Machine Framework}. + + The entered() signal is emitted when the state has been entered. The + exited() signal is emitted when the state has been exited. + + The parentState() function returns the state's parent state. The machine() + function returns the state machine that the state is part of. + + \section1 Subclassing + + The onEntry() function is called when the state is entered; reimplement this + function to perform custom processing when the state is entered. + + The onExit() function is called when the state is exited; reimplement this + function to perform custom processing when the state is exited. +*/ + +QAbstractStatePrivate::QAbstractStatePrivate() +{ +} + +QAbstractStatePrivate *QAbstractStatePrivate::get(QAbstractState *q) +{ + return q->d_func(); +} + +QStateMachine *QAbstractStatePrivate::machine() const +{ + Q_Q(const QAbstractState); + QObject *par = q->parent(); + while (par != 0) { + if (QStateMachine *mach = qobject_cast<QStateMachine*>(par)) + return mach; + par = par->parent(); + } + return 0; +} + +void QAbstractStatePrivate::callOnEntry(QEvent *e) +{ + Q_Q(QAbstractState); + q->onEntry(e); +} + +void QAbstractStatePrivate::callOnExit(QEvent *e) +{ + Q_Q(QAbstractState); + q->onExit(e); +} + +void QAbstractStatePrivate::emitEntered() +{ + Q_Q(QAbstractState); + emit q->entered(); +} + +void QAbstractStatePrivate::emitExited() +{ + Q_Q(QAbstractState); + emit q->exited(); +} + +/*! + Constructs a new state with the given \a parent state. +*/ +QAbstractState::QAbstractState(QState *parent) + : QObject(*new QAbstractStatePrivate, parent) +{ +} + +/*! + \internal +*/ +QAbstractState::QAbstractState(QAbstractStatePrivate &dd, QState *parent) + : QObject(dd, parent) +{ +} + +/*! + Destroys this state. +*/ +QAbstractState::~QAbstractState() +{ +} + +/*! + Returns this state's parent state, or 0 if the state has no parent state. +*/ +QState *QAbstractState::parentState() const +{ + return qobject_cast<QState*>(parent()); +} + +/*! + Returns the state machine that this state is part of, or 0 if the state is + not part of a state machine. +*/ +QStateMachine *QAbstractState::machine() const +{ + Q_D(const QAbstractState); + return d->machine(); +} + +/*! + \fn QAbstractState::onExit(QEvent *event) + + This function is called when the state is exited. The given \a event is what + caused the state to be exited. Reimplement this function to perform custom + processing when the state is exited. +*/ + +/*! + \fn QAbstractState::onEntry(QEvent *event) + + This function is called when the state is entered. The given \a event is + what caused the state to be entered. Reimplement this function to perform + custom processing when the state is entered. +*/ + +/*! + \fn QAbstractState::entered() + + This signal is emitted when the state has been entered (after onEntry() has + been called). +*/ + +/*! + \fn QAbstractState::exited() + + This signal is emitted when the state has been exited (after onExit() has + been called). +*/ + +/*! + \reimp +*/ +bool QAbstractState::event(QEvent *e) +{ + return QObject::event(e); +} + +QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qabstractstate.h b/src/corelib/statemachine/qabstractstate.h new file mode 100644 index 0000000..d0ebb52 --- /dev/null +++ b/src/corelib/statemachine/qabstractstate.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTSTATE_H +#define QABSTRACTSTATE_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QState; +class QStateMachine; + +class QAbstractStatePrivate; +class Q_CORE_EXPORT QAbstractState : public QObject +{ + Q_OBJECT +public: + ~QAbstractState(); + + QState *parentState() const; + QStateMachine *machine() const; + +Q_SIGNALS: + void entered(); + void exited(); + +protected: + QAbstractState(QState *parent = 0); + + virtual void onEntry(QEvent *event) = 0; + virtual void onExit(QEvent *event) = 0; + + bool event(QEvent *e); + +protected: + QAbstractState(QAbstractStatePrivate &dd, QState *parent); + +private: + Q_DISABLE_COPY(QAbstractState) + Q_DECLARE_PRIVATE(QAbstractState) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/statemachine/qabstractstate_p.h b/src/corelib/statemachine/qabstractstate_p.h new file mode 100644 index 0000000..b4f3108 --- /dev/null +++ b/src/corelib/statemachine/qabstractstate_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTSTATE_P_H +#define QABSTRACTSTATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QStateMachine; + +class QAbstractState; +class QAbstractStatePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QAbstractState) + +public: + QAbstractStatePrivate(); + + static QAbstractStatePrivate *get(QAbstractState *q); + + QStateMachine *machine() const; + + void callOnEntry(QEvent *e); + void callOnExit(QEvent *e); + + void emitEntered(); + void emitExited(); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp new file mode 100644 index 0000000..dfcafeb --- /dev/null +++ b/src/corelib/statemachine/qabstracttransition.cpp @@ -0,0 +1,342 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstracttransition.h" +#include "qabstracttransition_p.h" +#include "qabstractstate.h" +#include "qstate.h" +#include "qstatemachine.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAbstractTransition + + \brief The QAbstractTransition class is the base class of transitions between QAbstractState objects. + + \since 4.6 + \ingroup statemachine + + The QAbstractTransition class is the abstract base class of transitions + between states (QAbstractState objects) of a + QStateMachine. QAbstractTransition is part of \l{The State Machine + Framework}. + + The sourceState() function returns the source of the transition. The + targetStates() function returns the targets of the transition. The machine() + function returns the state machine that the transition is part of. + + Transitions can cause animations to be played. Use the addAnimation() + function to add an animation to the transition. + + \section1 Subclassing + + The eventTest() function is called by the state machine to determine whether + an event should trigger the transition. In your reimplementation you + typically check the event type and cast the event object to the proper type, + and check that one or more properties of the event meet your criteria. + + The onTransition() function is called when the transition is triggered; + reimplement this function to perform custom processing for the transition. +*/ + +/*! + \property QAbstractTransition::sourceState + + \brief the source state (parent) of this transition +*/ + +/*! + \property QAbstractTransition::targetState + + \brief the target state of this transition +*/ + +/*! + \property QAbstractTransition::targetStates + + \brief the target states of this transition + + If multiple states are specified, all must be descendants of the same + parallel group state. +*/ + +QAbstractTransitionPrivate::QAbstractTransitionPrivate() +{ +} + +QAbstractTransitionPrivate *QAbstractTransitionPrivate::get(QAbstractTransition *q) +{ + return q->d_func(); +} + +QStateMachine *QAbstractTransitionPrivate::machine() const +{ + Q_Q(const QAbstractTransition); + QObject *par = q->parent(); + while (par != 0) { + if (QStateMachine *mach = qobject_cast<QStateMachine*>(par)) + return mach; + par = par->parent(); + } + return 0; +} + +bool QAbstractTransitionPrivate::callEventTest(QEvent *e) +{ + Q_Q(QAbstractTransition); + return q->eventTest(e); +} + +void QAbstractTransitionPrivate::callOnTransition(QEvent *e) +{ + Q_Q(QAbstractTransition); + q->onTransition(e); +} + +QState *QAbstractTransitionPrivate::sourceState() const +{ + Q_Q(const QAbstractTransition); + return qobject_cast<QState*>(q->parent()); +} + +/*! + Constructs a new QAbstractTransition object with the given \a sourceState. +*/ +QAbstractTransition::QAbstractTransition(QState *sourceState) + : QObject(*new QAbstractTransitionPrivate, sourceState) +{ +} + +/*! + Constructs a new QAbstractTransition object with the given \a targets and \a + sourceState. +*/ +QAbstractTransition::QAbstractTransition(const QList<QAbstractState*> &targets, + QState *sourceState) + : QObject(*new QAbstractTransitionPrivate, sourceState) +{ + setTargetStates(targets); +} + +/*! + \internal +*/ +QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd, + QState *parent) + : QObject(dd, parent) +{ +} + +/*! + \internal +*/ +QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd, + const QList<QAbstractState*> &targets, + QState *parent) + : QObject(dd, parent) +{ + setTargetStates(targets); +} + +/*! + Destroys this transition. +*/ +QAbstractTransition::~QAbstractTransition() +{ +} + +/*! + Returns the source state of this transition, or 0 if this transition has no + source state. +*/ +QState *QAbstractTransition::sourceState() const +{ + Q_D(const QAbstractTransition); + return d->sourceState(); +} + +/*! + Returns the target state of this transition, or 0 if the transition has no + target. +*/ +QAbstractState *QAbstractTransition::targetState() const +{ + Q_D(const QAbstractTransition); + if (d->targetStates.isEmpty()) + return 0; + return d->targetStates.first(); +} + +/*! + Sets the \a target state of this transition. +*/ +void QAbstractTransition::setTargetState(QAbstractState* target) +{ + Q_D(QAbstractTransition); + if (!target) + d->targetStates.clear(); + else + setTargetStates(QList<QAbstractState*>() << target); +} + +/*! + Returns the target states of this transition, or an empty list if this + transition has no target states. +*/ +QList<QAbstractState*> QAbstractTransition::targetStates() const +{ + Q_D(const QAbstractTransition); + QList<QAbstractState*> result; + for (int i = 0; i < d->targetStates.size(); ++i) { + QAbstractState *target = d->targetStates.at(i); + if (target) + result.append(target); + } + return result; +} + +/*! + Sets the target states of this transition to be the given \a targets. +*/ +void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets) +{ + Q_D(QAbstractTransition); + + for (int i=0; i<targets.size(); ++i) { + QAbstractState *target = targets.at(i); + if (!target) { + qWarning("QAbstractTransition::setTargetStates: target state(s) cannot be null"); + return; + } + if (target->machine() != 0 && target->machine()->rootState() == target) { + qWarning("QAbstractTransition::setTargetStates: root state cannot be target of transition"); + return; + } + } + + d->targetStates.clear(); + for (int i = 0; i < targets.size(); ++i) + d->targetStates.append(targets.at(i)); +} + +/*! + Returns the state machine that this transition is part of, or 0 if the + transition is not part of a state machine. +*/ +QStateMachine *QAbstractTransition::machine() const +{ + Q_D(const QAbstractTransition); + return d->machine(); +} + +#ifndef QT_NO_ANIMATION + +/*! + Adds the given \a animation to this transition. + The transition does not take ownership of the animation. + + \sa removeAnimation(), animations() +*/ +void QAbstractTransition::addAnimation(QAbstractAnimation *animation) +{ + Q_D(QAbstractTransition); + if (!animation) { + qWarning("QAbstractTransition::addAnimation: cannot add null animation"); + return; + } + d->animations.append(animation); +} + +/*! + Removes the given \a animation from this transition. + + \sa addAnimation() +*/ +void QAbstractTransition::removeAnimation(QAbstractAnimation *animation) +{ + Q_D(QAbstractTransition); + if (!animation) { + qWarning("QAbstractTransition::removeAnimation: cannot remove null animation"); + return; + } + d->animations.removeOne(animation); +} + +/*! + Returns the list of animations associated with this transition, or an empty + list if it has no animations. + + \sa addAnimation() +*/ +QList<QAbstractAnimation*> QAbstractTransition::animations() const +{ + Q_D(const QAbstractTransition); + return d->animations; +} + +#endif + +/*! + \fn QAbstractTransition::eventTest(QEvent *event) + + This function is called to determine whether the given \a event should cause + this transition to trigger. Reimplement this function and return true if the + event should trigger the transition, otherwise return false. +*/ + +/*! + \fn QAbstractTransition::onTransition(QEvent *event) + + This function is called when the transition is triggered. The given \a event + is what caused the transition to trigger. Reimplement this function to + perform custom processing when the transition is triggered. +*/ + +/*! + \reimp +*/ +bool QAbstractTransition::event(QEvent *e) +{ + return QObject::event(e); +} + +QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h new file mode 100644 index 0000000..c63d55a --- /dev/null +++ b/src/corelib/statemachine/qabstracttransition.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTTRANSITION_H +#define QABSTRACTTRANSITION_H + +#include <QtCore/qobject.h> + +#include <QtCore/qlist.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QEvent; +class QAbstractState; +class QState; +class QStateMachine; + +#ifndef QT_NO_ANIMATION +class QAbstractAnimation; +#endif + +class QAbstractTransitionPrivate; +class Q_CORE_EXPORT QAbstractTransition : public QObject +{ + Q_OBJECT + Q_PROPERTY(QState* sourceState READ sourceState) + Q_PROPERTY(QAbstractState* targetState READ targetState WRITE setTargetState) + Q_PROPERTY(QList<QAbstractState*> targetStates READ targetStates WRITE setTargetStates) +public: + QAbstractTransition(QState *sourceState = 0); + QAbstractTransition(const QList<QAbstractState*> &targets, QState *sourceState = 0); + virtual ~QAbstractTransition(); + + QState *sourceState() const; + QAbstractState *targetState() const; + void setTargetState(QAbstractState* target); + QList<QAbstractState*> targetStates() const; + void setTargetStates(const QList<QAbstractState*> &targets); + + QStateMachine *machine() const; + +#ifndef QT_NO_ANIMATION + void addAnimation(QAbstractAnimation *animation); + void removeAnimation(QAbstractAnimation *animation); + QList<QAbstractAnimation*> animations() const; +#endif + +protected: + virtual bool eventTest(QEvent *event) = 0; + + virtual void onTransition(QEvent *event) = 0; + + bool event(QEvent *e); + +protected: + QAbstractTransition(QAbstractTransitionPrivate &dd, QState *parent); + QAbstractTransition(QAbstractTransitionPrivate &dd, + const QList<QAbstractState*> &targets, QState *parent); + +private: + Q_DISABLE_COPY(QAbstractTransition) + Q_DECLARE_PRIVATE(QAbstractTransition) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/statemachine/qabstracttransition_p.h b/src/corelib/statemachine/qabstracttransition_p.h new file mode 100644 index 0000000..f067984 --- /dev/null +++ b/src/corelib/statemachine/qabstracttransition_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTTRANSITION_P_H +#define QABSTRACTTRANSITION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qobject_p.h> + +#include <QtCore/qlist.h> +#include <QtCore/qpointer.h> + +QT_BEGIN_NAMESPACE + +class QAbstractState; +class QState; +class QStateMachine; + +class QAbstractTransition; +class Q_CORE_EXPORT QAbstractTransitionPrivate + : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QAbstractTransition) +public: + QAbstractTransitionPrivate(); + + static QAbstractTransitionPrivate *get(QAbstractTransition *q); + + bool callEventTest(QEvent *e); + void callOnTransition(QEvent *e); + QState *sourceState() const; + QStateMachine *machine() const; + + QList<QPointer<QAbstractState> > targetStates; + +#ifndef QT_NO_ANIMATION + QList<QAbstractAnimation*> animations; +#endif +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/statemachine/qeventtransition.cpp b/src/corelib/statemachine/qeventtransition.cpp new file mode 100644 index 0000000..f25d821 --- /dev/null +++ b/src/corelib/statemachine/qeventtransition.cpp @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeventtransition.h" +#include "qeventtransition_p.h" +#include "qwrappedevent.h" +#include "qstate.h" +#include "qstate_p.h" +#include "qstatemachine.h" +#include "qstatemachine_p.h" +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QEventTransition + + \brief The QEventTransition class provides a QObject-specific transition for Qt events. + + \since 4.6 + \ingroup statemachine + + A QEventTransition object binds an event to a particular QObject. + QEventTransition is part of \l{The State Machine Framework}. + + Example: + + \code + QPushButton *button = ...; + QState *s1 = ...; + QState *s2 = ...; + // If in s1 and the button receives an Enter event, transition to s2 + QEventTransition *enterTransition = new QEventTransition(button, QEvent::Enter); + enterTransition->setTargetState(s2); + s1->addTransition(enterTransition); + // If in s2 and the button receives an Exit event, transition back to s1 + QEventTransition *leaveTransition = new QEventTransition(button, QEvent::Leave); + leaveTransition->setTargetState(s1); + s2->addTransition(leaveTransition); + \endcode + + \section1 Subclassing + + When reimplementing the eventTest() function, you should first call the base + implementation to verify that the event is a QWrappedEvent for the proper + object and event type. You may then cast the event to a QWrappedEvent and + get the original event by calling QWrappedEvent::event(), and perform + additional checks on that object. + + \sa QState::addTransition() +*/ + +/*! + \property QEventTransition::eventObject + + \brief the event source that this event transition is associated with +*/ + +/*! + \property QEventTransition::eventType + + \brief the type of event that this event transition is associated with +*/ +QEventTransitionPrivate::QEventTransitionPrivate() +{ + object = 0; + eventType = QEvent::None; + registered = false; +} + +QEventTransitionPrivate *QEventTransitionPrivate::get(QEventTransition *q) +{ + return q->d_func(); +} + +void QEventTransitionPrivate::unregister() +{ + Q_Q(QEventTransition); + if (!registered || !machine()) + return; + QStateMachinePrivate::get(machine())->unregisterEventTransition(q); +} + +void QEventTransitionPrivate::maybeRegister() +{ + Q_Q(QEventTransition); + if (!machine() || !machine()->configuration().contains(sourceState())) + return; + QStateMachinePrivate::get(machine())->registerEventTransition(q); +} + +/*! + Constructs a new QEventTransition object with the given \a sourceState. +*/ +QEventTransition::QEventTransition(QState *sourceState) + : QAbstractTransition(*new QEventTransitionPrivate, sourceState) +{ +} + +/*! + Constructs a new QEventTransition object associated with events of the given + \a type for the given \a object, and with the given \a sourceState. +*/ +QEventTransition::QEventTransition(QObject *object, QEvent::Type type, + QState *sourceState) + : QAbstractTransition(*new QEventTransitionPrivate, sourceState) +{ + Q_D(QEventTransition); + d->registered = false; + d->object = object; + d->eventType = type; +} + +/*! + Constructs a new QEventTransition object associated with events of the given + \a type for the given \a object. The transition has the given \a targets and + \a sourceState. +*/ +QEventTransition::QEventTransition(QObject *object, QEvent::Type type, + const QList<QAbstractState*> &targets, + QState *sourceState) + : QAbstractTransition(*new QEventTransitionPrivate, targets, sourceState) +{ + Q_D(QEventTransition); + d->registered = false; + d->object = object; + d->eventType = type; +} + +/*! + \internal +*/ +QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QState *parent) + : QAbstractTransition(dd, parent) +{ +} + +/*! + \internal +*/ +QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QObject *object, + QEvent::Type type, QState *parent) + : QAbstractTransition(dd, parent) +{ + Q_D(QEventTransition); + d->registered = false; + d->object = object; + d->eventType = type; +} + +/*! + \internal +*/ +QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QObject *object, + QEvent::Type type, const QList<QAbstractState*> &targets, + QState *parent) + : QAbstractTransition(dd, targets, parent) +{ + Q_D(QEventTransition); + d->registered = false; + d->object = object; + d->eventType = type; +} + +/*! + Destroys this QObject event transition. +*/ +QEventTransition::~QEventTransition() +{ +} + +/*! + Returns the event type that this event transition is associated with. +*/ +QEvent::Type QEventTransition::eventType() const +{ + Q_D(const QEventTransition); + return d->eventType; +} + +/*! + Sets the event \a type that this event transition is associated with. +*/ +void QEventTransition::setEventType(QEvent::Type type) +{ + Q_D(QEventTransition); + if (d->eventType == type) + return; + d->unregister(); + d->eventType = type; + d->maybeRegister(); +} + +/*! + Returns the event source associated with this event transition. +*/ +QObject *QEventTransition::eventObject() const +{ + Q_D(const QEventTransition); + return d->object; +} + +/*! + Sets the event source associated with this event transition to be the given + \a object. +*/ +void QEventTransition::setEventObject(QObject *object) +{ + Q_D(QEventTransition); + if (d->object == object) + return; + d->unregister(); + d->object = object; + d->maybeRegister(); +} + +/*! + \reimp +*/ +bool QEventTransition::eventTest(QEvent *event) +{ + Q_D(const QEventTransition); + if (event->type() == QEvent::Wrapped) { + QWrappedEvent *we = static_cast<QWrappedEvent*>(event); + return (we->object() == d->object) + && (we->event()->type() == d->eventType); + } + return false; +} + +/*! + \reimp +*/ +void QEventTransition::onTransition(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + \reimp +*/ +bool QEventTransition::event(QEvent *e) +{ + return QAbstractTransition::event(e); +} + +QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qeventtransition.h b/src/corelib/statemachine/qeventtransition.h new file mode 100644 index 0000000..3530bdd --- /dev/null +++ b/src/corelib/statemachine/qeventtransition.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVENTTRANSITION_H +#define QEVENTTRANSITION_H + +#include <QtCore/qabstracttransition.h> +#include <QtCore/qcoreevent.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QEventTransitionPrivate; +class Q_CORE_EXPORT QEventTransition : public QAbstractTransition +{ + Q_OBJECT + Q_PROPERTY(QObject* eventObject READ eventObject WRITE setEventObject) + Q_PROPERTY(QEvent::Type eventType READ eventType WRITE setEventType) +public: + QEventTransition(QState *sourceState = 0); + QEventTransition(QObject *object, QEvent::Type type, QState *sourceState = 0); + QEventTransition(QObject *object, QEvent::Type type, + const QList<QAbstractState*> &targets, QState *sourceState = 0); + ~QEventTransition(); + + QObject *eventObject() const; + void setEventObject(QObject *object); + + QEvent::Type eventType() const; + void setEventType(QEvent::Type type); + +protected: + bool eventTest(QEvent *event); + void onTransition(QEvent *event); + + bool event(QEvent *e); + +protected: + QEventTransition(QEventTransitionPrivate &dd, QState *parent); + QEventTransition(QEventTransitionPrivate &dd, QObject *object, + QEvent::Type type, QState *parent); + QEventTransition(QEventTransitionPrivate &dd, QObject *object, + QEvent::Type type, const QList<QAbstractState*> &targets, + QState *parent); + +private: + Q_DISABLE_COPY(QEventTransition) + Q_DECLARE_PRIVATE(QEventTransition) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/statemachine/qeventtransition_p.h b/src/corelib/statemachine/qeventtransition_p.h new file mode 100644 index 0000000..600cec0 --- /dev/null +++ b/src/corelib/statemachine/qeventtransition_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVENTTRANSITION_P_H +#define QEVENTTRANSITION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qabstracttransition_p.h" + +QT_BEGIN_NAMESPACE + +class QEventTransition; +class Q_CORE_EXPORT QEventTransitionPrivate : public QAbstractTransitionPrivate +{ + Q_DECLARE_PUBLIC(QEventTransition) +public: + QEventTransitionPrivate(); + + static QEventTransitionPrivate *get(QEventTransition *q); + + void unregister(); + void maybeRegister(); + + bool registered; + QObject *object; + QEvent::Type eventType; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/statemachine/qfinalstate.cpp b/src/corelib/statemachine/qfinalstate.cpp new file mode 100644 index 0000000..0980336 --- /dev/null +++ b/src/corelib/statemachine/qfinalstate.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfinalstate.h" +#include "qabstractstate_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QFinalState + + \brief The QFinalState class provides a final state. + + \since 4.6 + \ingroup statemachine + + A final state is used to communicate that (part of) a QStateMachine has + finished its work. When a final top-level state is entered, the state + machine's \l{QStateMachine::finished()}{finished}() signal is emitted. In + general, when a final substate (a child of a QState) is entered, the parent + state's \l{QState::finished()}{finished}() signal is emitted. QFinalState + is part of \l{The State Machine Framework}. + + To use a final state, you create a QFinalState object and add a transition + to it from another state. Example: + + \code + QPushButton button; + + QStateMachine machine; + QState *s1 = new QState(); + QFinalState *s2 = new QFinalState(); + s1->addTransition(&button, SIGNAL(clicked()), s2); + machine.addState(s1); + machine.addState(s2); + + QObject::connect(&machine, SIGNAL(finished()), QApplication::instance(), SLOT(quit())); + machine.setInitialState(s1); + machine.start(); + \endcode + + \sa QStateMachine::finished(), QState::finished() +*/ + +class QFinalStatePrivate : public QAbstractStatePrivate +{ + Q_DECLARE_PUBLIC(QFinalState) + +public: + QFinalStatePrivate(); +}; + +QFinalStatePrivate::QFinalStatePrivate() +{ +} + +/*! + Constructs a new QFinalState object with the given \a parent state. +*/ +QFinalState::QFinalState(QState *parent) + : QAbstractState(*new QFinalStatePrivate, parent) +{ +} + +/*! + Destroys this final state. +*/ +QFinalState::~QFinalState() +{ +} + +/*! + \reimp +*/ +void QFinalState::onEntry(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + \reimp +*/ +void QFinalState::onExit(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + \reimp +*/ +bool QFinalState::event(QEvent *e) +{ + return QAbstractState::event(e); +} + +QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qfinalstate.h b/src/corelib/statemachine/qfinalstate.h new file mode 100644 index 0000000..fa68394 --- /dev/null +++ b/src/corelib/statemachine/qfinalstate.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFINALSTATE_H +#define QFINALSTATE_H + +#include <QtCore/qabstractstate.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QFinalStatePrivate; +class Q_CORE_EXPORT QFinalState : public QAbstractState +{ + Q_OBJECT +public: + QFinalState(QState *parent = 0); + ~QFinalState(); + +protected: + void onEntry(QEvent *event); + void onExit(QEvent *event); + + bool event(QEvent *e); + +private: + Q_DISABLE_COPY(QFinalState) + Q_DECLARE_PRIVATE(QFinalState) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp new file mode 100644 index 0000000..517faa8 --- /dev/null +++ b/src/corelib/statemachine/qhistorystate.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhistorystate.h" +#include "qhistorystate_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QHistoryState + + \brief The QHistoryState class provides a means of returning to a previously active substate. + + \since 4.6 + \ingroup statemachine + + A history state is a pseudo-state that represents the child state that the + parent state was in the last time the parent state was exited. A transition + with a history state as its target is in fact a transition to one of the + other child states of the parent state. QHistoryState is part of \l{The + State Machine Framework}. + + Use the setDefaultState() function to set the state that should be entered + if the parent state has never been entered. Example: + + \code + QStateMachine machine; + + QState *s1 = new QState(); + QState *s11 = new QState(s1); + QState *s12 = new QState(s1); + + QHistoryState *s1h = new QHistoryState(s1); + s1h->setDefaultState(s11); + + machine.addState(s1); + + QState *s2 = new QState(); + machine.addState(s2); + + QPushButton *button = new QPushButton(); + // Clicking the button will cause the state machine to enter the child state + // that s1 was in the last time s1 was exited, or the history state's default + // state if s1 has never been entered. + s1->addTransition(button, SIGNAL(clicked()), s1h); + \endcode + + By default a history state is shallow, meaning that it won't remember nested + states. This can be configured through the historyType property. +*/ + +/*! + \property QHistoryState::defaultState + + \brief the default state of this history state +*/ + +/*! + \property QHistoryState::historyType + + \brief the type of history that this history state records + + The default value of this property is QHistoryState::ShallowHistory. +*/ + +/*! + \enum QHistoryState::HistoryType + + This enum specifies the type of history that a QHistoryState records. + + \value ShallowHistory Only the immediate child states of the parent state + are recorded. In this case a transition with the history state as its + target will end up in the immediate child state that the parent was in the + last time it was exited. This is the default. + + \value DeepHistory Nested states are recorded. In this case a transition + with the history state as its target will end up in the most deeply nested + descendant state the parent was in the last time it was exited. +*/ + +QHistoryStatePrivate::QHistoryStatePrivate() + : defaultState(0) +{ +} + +QHistoryStatePrivate *QHistoryStatePrivate::get(QHistoryState *q) +{ + return q->d_func(); +} + +/*! + Constructs a new shallow history state with the given \a parent state. +*/ +QHistoryState::QHistoryState(QState *parent) + : QAbstractState(*new QHistoryStatePrivate, parent) +{ + Q_D(QHistoryState); + d->historyType = ShallowHistory; +} +/*! + Constructs a new history state of the given \a type, with the given \a + parent state. +*/ +QHistoryState::QHistoryState(HistoryType type, QState *parent) + : QAbstractState(*new QHistoryStatePrivate, parent) +{ + Q_D(QHistoryState); + d->historyType = type; +} + +/*! + Destroys this history state. +*/ +QHistoryState::~QHistoryState() +{ +} + +/*! + Returns this history state's default state. The default state indicates the + state to transition to if the parent state has never been entered before. +*/ +QAbstractState *QHistoryState::defaultState() const +{ + Q_D(const QHistoryState); + return d->defaultState; +} + +/*! + Sets this history state's default state to be the given \a state. + \a state must be a sibling of this history state. +*/ +void QHistoryState::setDefaultState(QAbstractState *state) +{ + Q_D(QHistoryState); + if (state && state->parentState() != parentState()) { + qWarning("QHistoryState::setDefaultState: state %p does not belong " + "to this history state's group (%p)", state, parentState()); + return; + } + d->defaultState = state; +} + +/*! + Returns the type of history that this history state records. +*/ +QHistoryState::HistoryType QHistoryState::historyType() const +{ + Q_D(const QHistoryState); + return d->historyType; +} + +/*! + Sets the \a type of history that this history state records. +*/ +void QHistoryState::setHistoryType(HistoryType type) +{ + Q_D(QHistoryState); + d->historyType = type; +} + +/*! + \reimp +*/ +void QHistoryState::onEntry(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + \reimp +*/ +void QHistoryState::onExit(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + \reimp +*/ +bool QHistoryState::event(QEvent *e) +{ + return QAbstractState::event(e); +} + +QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qhistorystate.h b/src/corelib/statemachine/qhistorystate.h new file mode 100644 index 0000000..a0682bd --- /dev/null +++ b/src/corelib/statemachine/qhistorystate.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHISTORYSTATE_H +#define QHISTORYSTATE_H + +#include <QtCore/qabstractstate.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QHistoryStatePrivate; +class Q_CORE_EXPORT QHistoryState : public QAbstractState +{ + Q_OBJECT + Q_PROPERTY(QAbstractState* defaultState READ defaultState WRITE setDefaultState) + Q_PROPERTY(HistoryType historyType READ historyType WRITE setHistoryType) + Q_ENUMS(HistoryType) +public: + enum HistoryType { + ShallowHistory, + DeepHistory + }; + + QHistoryState(QState *parent = 0); + QHistoryState(HistoryType type, QState *parent = 0); + ~QHistoryState(); + + QAbstractState *defaultState() const; + void setDefaultState(QAbstractState *state); + + HistoryType historyType() const; + void setHistoryType(HistoryType type); + +protected: + void onEntry(QEvent *event); + void onExit(QEvent *event); + + bool event(QEvent *e); + +private: + Q_DISABLE_COPY(QHistoryState) + Q_DECLARE_PRIVATE(QHistoryState) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/statemachine/qhistorystate_p.h b/src/corelib/statemachine/qhistorystate_p.h new file mode 100644 index 0000000..5aaa64c --- /dev/null +++ b/src/corelib/statemachine/qhistorystate_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHISTORYSTATE_P_H +#define QHISTORYSTATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qabstractstate_p.h" + +#include <QtCore/qlist.h> + +QT_BEGIN_NAMESPACE + +class QHistoryState; +class QHistoryStatePrivate : public QAbstractStatePrivate +{ + Q_DECLARE_PUBLIC(QHistoryState) + +public: + QHistoryStatePrivate(); + + static QHistoryStatePrivate *get(QHistoryState *q); + + QAbstractState *defaultState; + QHistoryState::HistoryType historyType; + QList<QAbstractState*> configuration; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/statemachine/qsignalevent.h b/src/corelib/statemachine/qsignalevent.h new file mode 100644 index 0000000..8221f68 --- /dev/null +++ b/src/corelib/statemachine/qsignalevent.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIGNALEVENT_H +#define QSIGNALEVENT_H + +#include <QtCore/qcoreevent.h> + +#include <QtCore/qlist.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class Q_CORE_EXPORT QSignalEvent : public QEvent +{ +public: + QSignalEvent(const QObject *sender, int signalIndex, + const QList<QVariant> &arguments); + ~QSignalEvent(); + + inline const QObject *sender() const { return m_sender; } + inline int signalIndex() const { return m_signalIndex; } + inline QList<QVariant> arguments() const { return m_arguments; } + +private: + const QObject *m_sender; + int m_signalIndex; + QList<QVariant> m_arguments; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/statemachine/qsignaleventgenerator_p.h b/src/corelib/statemachine/qsignaleventgenerator_p.h new file mode 100644 index 0000000..cf0ea1e --- /dev/null +++ b/src/corelib/statemachine/qsignaleventgenerator_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIGNALEVENTGENERATOR_P_H +#define QSIGNALEVENTGENERATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> + +QT_BEGIN_NAMESPACE + +class QStateMachine; + +class QSignalEventGenerator : public QObject +{ +public: + QSignalEventGenerator(QStateMachine *parent); + + static const QMetaObject staticMetaObject; + virtual const QMetaObject *metaObject() const; + virtual void *qt_metacast(const char *); + virtual int qt_metacall(QMetaObject::Call, int, void **argv); + +private: + Q_DISABLE_COPY(QSignalEventGenerator) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp new file mode 100644 index 0000000..9ffcb9c --- /dev/null +++ b/src/corelib/statemachine/qsignaltransition.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsignaltransition.h" +#include "qsignaltransition_p.h" +#include "qsignalevent.h" +#include "qstate.h" +#include "qstate_p.h" +#include "qstatemachine.h" +#include "qstatemachine_p.h" +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QSignalTransition + + \brief The QSignalTransition class provides a transition based on a Qt signal. + + \since 4.6 + \ingroup statemachine + + Typically you would use the overload of QState::addTransition() that takes a + sender and signal as arguments, rather than creating QSignalTransition + objects directly. QSignalTransition is part of \l{The State Machine + Framework}. + + You can subclass QSignalTransition and reimplement eventTest() to make a + signal transition conditional; the event object passed to eventTest() will + be a QSignalEvent object. Example: + + \code + class CheckedTransition : public QSignalTransition + { + public: + CheckedTransition(QCheckBox *check) + : QSignalTransition(check, SIGNAL(stateChanged(int))) {} + protected: + bool eventTest(QEvent *e) const { + if (!QSignalTransition::eventTest(e)) + return false; + QSignalEvent *se = static_cast<QSignalEvent*>(e); + return (se->arguments().at(0).toInt() == Qt::Checked); + } + }; + + ... + + QCheckBox *check = new QCheckBox(); + check->setTristate(true); + + QState *s1 = new QState(); + QState *s2 = new QState(); + CheckedTransition *t1 = new CheckedTransition(check); + t1->setTargetState(s2); + s1->addTransition(t1); + \endcode +*/ + +/*! + \property QSignalTransition::senderObject + + \brief the sender object that this signal transition is associated with +*/ + +/*! + \property QSignalTransition::signal + + \brief the signal that this signal transition is associated with +*/ + +QSignalTransitionPrivate::QSignalTransitionPrivate() +{ + sender = 0; + signalIndex = -1; +} + +QSignalTransitionPrivate *QSignalTransitionPrivate::get(QSignalTransition *q) +{ + return q->d_func(); +} + +void QSignalTransitionPrivate::unregister() +{ + Q_Q(QSignalTransition); + if ((signalIndex == -1) || !machine()) + return; + QStateMachinePrivate::get(machine())->unregisterSignalTransition(q); +} + +void QSignalTransitionPrivate::maybeRegister() +{ + Q_Q(QSignalTransition); + if (!machine() || !machine()->configuration().contains(sourceState())) + return; + QStateMachinePrivate::get(machine())->registerSignalTransition(q); +} + +/*! + Constructs a new signal transition with the given \a sourceState. +*/ +QSignalTransition::QSignalTransition(QState *sourceState) + : QAbstractTransition(*new QSignalTransitionPrivate, sourceState) +{ +} + +/*! + Constructs a new signal transition associated with the given \a signal of + the given \a sender, and with the given \a sourceState. +*/ +QSignalTransition::QSignalTransition(QObject *sender, const char *signal, + QState *sourceState) + : QAbstractTransition(*new QSignalTransitionPrivate, sourceState) +{ + Q_D(QSignalTransition); + d->sender = sender; + d->signal = signal; +} + +/*! + Constructs a new signal transition associated with the given \a signal of + the given \a sender. The transition has the given \a targets and \a + sourceState. +*/ +QSignalTransition::QSignalTransition(QObject *sender, const char *signal, + const QList<QAbstractState*> &targets, + QState *sourceState) + : QAbstractTransition(*new QSignalTransitionPrivate, targets, sourceState) +{ + Q_D(QSignalTransition); + d->sender = sender; + d->signal = signal; +} + +/*! + Destroys this signal transition. +*/ +QSignalTransition::~QSignalTransition() +{ +} + +/*! + Returns the sender object associated with this signal transition. +*/ +QObject *QSignalTransition::senderObject() const +{ + Q_D(const QSignalTransition); + return d->sender; +} + +/*! + Sets the \a sender object associated with this signal transition. +*/ +void QSignalTransition::setSenderObject(QObject *sender) +{ + Q_D(QSignalTransition); + if (sender == d->sender) + return; + d->unregister(); + d->sender = sender; + d->maybeRegister(); +} + +/*! + Returns the signal associated with this signal transition. +*/ +QByteArray QSignalTransition::signal() const +{ + Q_D(const QSignalTransition); + return d->signal; +} + +/*! + Sets the \a signal associated with this signal transition. +*/ +void QSignalTransition::setSignal(const QByteArray &signal) +{ + Q_D(QSignalTransition); + if (signal == d->signal) + return; + d->unregister(); + d->signal = signal; + d->maybeRegister(); +} + +/*! + \reimp + + The \a event is a QSignalEvent object. The default implementation returns + true if the event's sender and signal index match this transition, and + returns false otherwise. +*/ +bool QSignalTransition::eventTest(QEvent *event) +{ + Q_D(const QSignalTransition); + if (event->type() == QEvent::Signal) { + if (d->signalIndex == -1) + return false; + QSignalEvent *se = static_cast<QSignalEvent*>(event); + return (se->sender() == d->sender) + && (se->signalIndex() == d->signalIndex); + } + return false; +} + +/*! + \reimp +*/ +void QSignalTransition::onTransition(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + \reimp +*/ +bool QSignalTransition::event(QEvent *e) +{ + return QAbstractTransition::event(e); +} + +QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qsignaltransition.h b/src/corelib/statemachine/qsignaltransition.h new file mode 100644 index 0000000..b485785 --- /dev/null +++ b/src/corelib/statemachine/qsignaltransition.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIGNALTRANSITION_H +#define QSIGNALTRANSITION_H + +#include <QtCore/qabstracttransition.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QSignalTransitionPrivate; +class Q_CORE_EXPORT QSignalTransition : public QAbstractTransition +{ + Q_OBJECT + Q_PROPERTY(QObject* senderObject READ senderObject WRITE setSenderObject) + Q_PROPERTY(QByteArray signal READ signal WRITE setSignal) +public: + QSignalTransition(QState *sourceState = 0); + QSignalTransition(QObject *sender, const char *signal, + QState *sourceState = 0); + QSignalTransition(QObject *sender, const char *signal, + const QList<QAbstractState*> &targets, + QState *sourceState = 0); + ~QSignalTransition(); + + QObject *senderObject() const; + void setSenderObject(QObject *sender); + + QByteArray signal() const; + void setSignal(const QByteArray &signal); + +protected: + bool eventTest(QEvent *event); + void onTransition(QEvent *event); + + bool event(QEvent *e); + +private: + Q_DISABLE_COPY(QSignalTransition) + Q_DECLARE_PRIVATE(QSignalTransition) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/statemachine/qsignaltransition_p.h b/src/corelib/statemachine/qsignaltransition_p.h new file mode 100644 index 0000000..339de63 --- /dev/null +++ b/src/corelib/statemachine/qsignaltransition_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIGNALTRANSITION_P_H +#define QSIGNALTRANSITION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qabstracttransition_p.h" + +QT_BEGIN_NAMESPACE + +class QSignalTransition; +class QSignalTransitionPrivate : public QAbstractTransitionPrivate +{ + Q_DECLARE_PUBLIC(QSignalTransition) +public: + QSignalTransitionPrivate(); + + static QSignalTransitionPrivate *get(QSignalTransition *q); + + void unregister(); + void maybeRegister(); + + QObject *sender; + QByteArray signal; + int signalIndex; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp new file mode 100644 index 0000000..5463059 --- /dev/null +++ b/src/corelib/statemachine/qstate.cpp @@ -0,0 +1,483 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstate.h" +#include "qstate_p.h" +#include "qhistorystate.h" +#include "qhistorystate_p.h" +#include "qabstracttransition.h" +#include "qabstracttransition_p.h" +#include "qsignaltransition.h" +#include "qstatemachine.h" +#include "qstatemachine_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QState + + \brief The QState class provides a general-purpose state for QStateMachine. + + \since 4.6 + \ingroup statemachine + + QState objects can have child states, and can have transitions to other + states. QState is part of \l{The State Machine Framework}. + + The addTransition() function adds a transition. The removeTransition() + function removes a transition. + + The assignProperty() function is used for defining property assignments that + should be performed when a state is entered. + + Top-level states must be passed QStateMachine::rootState() as their parent + state, or added to a state machine using QStateMachine::addState(). + + \section1 States with Child States + + The childMode property determines how child states are treated. For + non-parallel state groups, the setInitialState() function must be called to + set the initial state. The child states are mutually exclusive states, and + the state machine needs to know which child state to enter when the parent + state is the target of a transition. + + The state emits the QState::finished() signal when a final child state + (QFinalState) is entered. + + The setErrorState() sets the state's error state. The error state is the + state that the state machine will transition to if an error is detected when + attempting to enter the state (e.g. because no initial state has been set). + +*/ + +/*! + \property QState::initialState + + \brief the initial state of this state (one of its child states) +*/ + +/*! + \property QState::errorState + + \brief the error state of this state +*/ + +/*! + \property QState::childMode + + \brief the child mode of this state + + The default value of this property is QState::ExclusiveStates. +*/ + +/*! + \enum QState::ChildMode + + This enum specifies how a state's child states are treated. + + \value ExclusiveStates The child states are mutually exclusive and an + initial state must be set by calling QState::setInitialState(). + + \value ParallelStates The child states are parallel. When the parent state + is entered, all its child states are entered in parallel. +*/ + +QStatePrivate::QStatePrivate() + : errorState(0), initialState(0), childMode(QState::ExclusiveStates) +{ +} + +QStatePrivate::~QStatePrivate() +{ +} + +void QStatePrivate::emitFinished() +{ + Q_Q(QState); + emit q->finished(); +} + +void QStatePrivate::emitPolished() +{ + Q_Q(QState); + emit q->polished(); +} + +/*! + Constructs a new state with the given \a parent state. +*/ +QState::QState(QState *parent) + : QAbstractState(*new QStatePrivate, parent) +{ +} + +/*! + Constructs a new state with the given \a childMode and the given \a parent + state. +*/ +QState::QState(ChildMode childMode, QState *parent) + : QAbstractState(*new QStatePrivate, parent) +{ + Q_D(QState); + d->childMode = childMode; +} + +/*! + \internal +*/ +QState::QState(QStatePrivate &dd, QState *parent) + : QAbstractState(dd, parent) +{ +} + +/*! + Destroys this state. +*/ +QState::~QState() +{ +} + +QList<QAbstractState*> QStatePrivate::childStates() const +{ + QList<QAbstractState*> result; + QList<QObject*>::const_iterator it; + for (it = children.constBegin(); it != children.constEnd(); ++it) { + QAbstractState *s = qobject_cast<QAbstractState*>(*it); + if (!s || qobject_cast<QHistoryState*>(s)) + continue; + result.append(s); + } + return result; +} + +QList<QHistoryState*> QStatePrivate::historyStates() const +{ + QList<QHistoryState*> result; + QList<QObject*>::const_iterator it; + for (it = children.constBegin(); it != children.constEnd(); ++it) { + QHistoryState *h = qobject_cast<QHistoryState*>(*it); + if (h) + result.append(h); + } + return result; +} + +QList<QAbstractTransition*> QStatePrivate::transitions() const +{ + QList<QAbstractTransition*> result; + QList<QObject*>::const_iterator it; + for (it = children.constBegin(); it != children.constEnd(); ++it) { + QAbstractTransition *t = qobject_cast<QAbstractTransition*>(*it); + if (t) + result.append(t); + } + return result; +} + +/*! + Instructs this state to set the property with the given \a name of the given + \a object to the given \a value when the state is entered. + + \sa polished() +*/ +void QState::assignProperty(QObject *object, const char *name, + const QVariant &value) +{ + Q_D(QState); + if (!object) { + qWarning("QState::assignProperty: cannot assign property '%s' of null object", name); + return; + } + for (int i = 0; i < d->propertyAssignments.size(); ++i) { + QPropertyAssignment &assn = d->propertyAssignments[i]; + if ((assn.object == object) && (assn.propertyName == name)) { + assn.value = value; + return; + } + } + d->propertyAssignments.append(QPropertyAssignment(object, name, value)); +} + +/*! + Returns this state group's error state. + + \sa QStateMachine::errorState(), QStateMachine::setErrorState() +*/ +QAbstractState *QState::errorState() const +{ + Q_D(const QState); + return d->errorState; +} + +/*! + Sets this state's error state to be the given \a state. If the error state + is not set, or if it is set to 0, the state will inherit its parent's error + state recursively. + + \sa QStateMachine::setErrorState(), QStateMachine::errorState() +*/ +void QState::setErrorState(QAbstractState *state) +{ + Q_D(QState); + if (state != 0 && state->machine() != machine()) { + qWarning("QState::setErrorState: error state cannot belong " + "to a different state machine"); + return; + } + if (state != 0 && state->machine() != 0 && state->machine()->rootState() == state) { + qWarning("QStateMachine::setErrorState: root state cannot be error state"); + return; + } + + d->errorState = state; +} + +/*! + Adds the given \a transition. The transition has this state as the source. + This state takes ownership of the transition. If the transition is successfully + added, the function will return the \a transition pointer. Otherwise it will return null. +*/ +QAbstractTransition *QState::addTransition(QAbstractTransition *transition) +{ + Q_D(QState); + if (!transition) { + qWarning("QState::addTransition: cannot add null transition"); + return 0; + } + + // machine() will always be non-null for root state + if (machine() != 0 && machine()->rootState() == this) { + qWarning("QState::addTransition: cannot add transition from root state"); + return 0; + } + + const QList<QPointer<QAbstractState> > &targets = QAbstractTransitionPrivate::get(transition)->targetStates; + for (int i = 0; i < targets.size(); ++i) { + QAbstractState *t = targets.at(i); + if (!t) { + qWarning("QState::addTransition: cannot add transition to null state"); + return 0; + } + if ((QAbstractStatePrivate::get(t)->machine() != d->machine()) + && QAbstractStatePrivate::get(t)->machine() && d->machine()) { + qWarning("QState::addTransition: cannot add transition " + "to a state in a different state machine"); + return 0; + } + } + transition->setParent(this); + if (machine() != 0 && machine()->configuration().contains(this)) + QStateMachinePrivate::get(machine())->registerTransitions(this); + return transition; +} + +/*! + Adds a transition associated with the given \a signal of the given \a sender + object, and returns the new QSignalTransition object. The transition has + this state as the source, and the given \a target as the target state. +*/ +QSignalTransition *QState::addTransition(QObject *sender, const char *signal, + QAbstractState *target) +{ + if (!sender) { + qWarning("QState::addTransition: sender cannot be null"); + return 0; + } + if (!signal) { + qWarning("QState::addTransition: signal cannot be null"); + return 0; + } + if (!target) { + qWarning("QState::addTransition: cannot add transition to null state"); + return 0; + } + if (*signal && sender->metaObject()->indexOfSignal(signal+1) == -1) { + qWarning("QState::addTransition: no such signal %s::%s", + sender->metaObject()->className(), signal+1); + return 0; + } + QSignalTransition *trans = new QSignalTransition(sender, signal, QList<QAbstractState*>() << target); + addTransition(trans); + return trans; +} + +namespace { + +// ### Make public? +class UnconditionalTransition : public QAbstractTransition +{ +public: + UnconditionalTransition(QAbstractState *target) + : QAbstractTransition(QList<QAbstractState*>() << target) {} +protected: + void onTransition(QEvent *) {} + bool eventTest(QEvent *) { return true; } +}; + +} // namespace + +/*! + Adds an unconditional transition from this state to the given \a target + state, and returns then new transition object. +*/ +QAbstractTransition *QState::addTransition(QAbstractState *target) +{ + if (!target) { + qWarning("QState::addTransition: cannot add transition to null state"); + return 0; + } + UnconditionalTransition *trans = new UnconditionalTransition(target); + return addTransition(trans); +} + +/*! + Removes the given \a transition from this state. The state releases + ownership of the transition. + + \sa addTransition() +*/ +void QState::removeTransition(QAbstractTransition *transition) +{ + Q_D(QState); + if (!transition) { + qWarning("QState::removeTransition: cannot remove null transition"); + return; + } + if (transition->sourceState() != this) { + qWarning("QState::removeTransition: transition %p's source state (%p)" + " is different from this state (%p)", + transition, transition->sourceState(), this); + return; + } + QStateMachinePrivate *mach = QStateMachinePrivate::get(d->machine()); + if (mach) + mach->unregisterTransition(transition); + transition->setParent(0); +} + +/*! + \reimp +*/ +void QState::onEntry(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + \reimp +*/ +void QState::onExit(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + Returns this state's initial state, or 0 if the state has no initial state. +*/ +QAbstractState *QState::initialState() const +{ + Q_D(const QState); + return d->initialState; +} + +/*! + Sets this state's initial state to be the given \a state. + \a state has to be a child of this state. +*/ +void QState::setInitialState(QAbstractState *state) +{ + Q_D(QState); + if (d->childMode == QState::ParallelStates) { + qWarning("QState::setInitialState: ignoring attempt to set initial state " + "of parallel state group %p", this); + return; + } + if (state && (state->parentState() != this)) { + qWarning("QState::setInitialState: state %p is not a child of this state (%p)", + state, this); + return; + } + d->initialState = state; +} + +/*! + Returns the child mode of this state. +*/ +QState::ChildMode QState::childMode() const +{ + Q_D(const QState); + return d->childMode; +} + +/*! + Sets the child \a mode of this state. +*/ +void QState::setChildMode(ChildMode mode) +{ + Q_D(QState); + d->childMode = mode; +} + +/*! + \reimp +*/ +bool QState::event(QEvent *e) +{ + return QAbstractState::event(e); +} + +/*! + \fn QState::finished() + + This signal is emitted when a final child state of this state is entered. + + \sa QFinalState +*/ + +/*! + \fn QState::polished() + + This signal is emitted when all properties have been assigned their final value. + + \sa QState::assignProperty(), QAbstractTransition::addAnimation() +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h new file mode 100644 index 0000000..6729c69 --- /dev/null +++ b/src/corelib/statemachine/qstate.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTATE_H +#define QSTATE_H + +#include <QtCore/qabstractstate.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QAbstractTransition; +class QSignalTransition; + +class QStatePrivate; +class Q_CORE_EXPORT QState : public QAbstractState +{ + Q_OBJECT + Q_PROPERTY(QAbstractState* initialState READ initialState WRITE setInitialState) + Q_PROPERTY(QAbstractState* errorState READ errorState WRITE setErrorState) + Q_PROPERTY(ChildMode childMode READ childMode WRITE setChildMode) + Q_ENUMS(ChildMode) +public: + enum ChildMode { + ExclusiveStates, + ParallelStates + }; + + QState(QState *parent = 0); + QState(ChildMode childMode, QState *parent = 0); + ~QState(); + + QAbstractState *errorState() const; + void setErrorState(QAbstractState *state); + + QAbstractTransition *addTransition(QAbstractTransition *transition); + QSignalTransition *addTransition(QObject *sender, const char *signal, QAbstractState *target); + QAbstractTransition *addTransition(QAbstractState *target); + void removeTransition(QAbstractTransition *transition); + + QAbstractState *initialState() const; + void setInitialState(QAbstractState *state); + + ChildMode childMode() const; + void setChildMode(ChildMode mode); + + void assignProperty(QObject *object, const char *name, + const QVariant &value); + +Q_SIGNALS: + void finished(); + void polished(); + +protected: + void onEntry(QEvent *event); + void onExit(QEvent *event); + + bool event(QEvent *e); + +protected: + QState(QStatePrivate &dd, QState *parent); + +private: + Q_DISABLE_COPY(QState) + Q_DECLARE_PRIVATE(QState) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/statemachine/qstate_p.h b/src/corelib/statemachine/qstate_p.h new file mode 100644 index 0000000..93744b9 --- /dev/null +++ b/src/corelib/statemachine/qstate_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTATE_P_H +#define QSTATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qabstractstate_p.h" + +#include <QtCore/qlist.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_NAMESPACE + +struct QPropertyAssignment +{ + QPropertyAssignment() + : object(0) {} + QPropertyAssignment(QObject *o, const QByteArray &n, + const QVariant &v, bool es = true) + : object(o), propertyName(n), value(v), explicitlySet(es) + {} + QObject *object; + QByteArray propertyName; + QVariant value; + bool explicitlySet; +}; + +class QAbstractTransition; +class QHistoryState; + +class QState; +class Q_AUTOTEST_EXPORT QStatePrivate : public QAbstractStatePrivate +{ + Q_DECLARE_PUBLIC(QState) +public: + QStatePrivate(); + ~QStatePrivate(); + + static QStatePrivate *get(QState *q) { return q ? q->d_func() : 0; } + static const QStatePrivate *get(const QState *q) { return q? q->d_func() : 0; } + + QList<QAbstractState*> childStates() const; + QList<QHistoryState*> historyStates() const; + QList<QAbstractTransition*> transitions() const; + + void emitFinished(); + void emitPolished(); + + QAbstractState *errorState; + QAbstractState *initialState; + QState::ChildMode childMode; + + QList<QPropertyAssignment> propertyAssignments; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp new file mode 100644 index 0000000..84619d7 --- /dev/null +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -0,0 +1,2209 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstatemachine.h" +#include "qstate.h" +#include "qstate_p.h" +#include "qstatemachine_p.h" +#include "qabstracttransition.h" +#include "qabstracttransition_p.h" +#include "qsignaltransition.h" +#include "qsignaltransition_p.h" +#include "qsignalevent.h" +#include "qsignaleventgenerator_p.h" +#include "qabstractstate.h" +#include "qabstractstate_p.h" +#include "qfinalstate.h" +#include "qhistorystate.h" +#include "qhistorystate_p.h" +#include "private/qobject_p.h" +#include "private/qthread_p.h" + +#ifndef QT_NO_STATEMACHINE_EVENTFILTER +#include "qeventtransition.h" +#include "qeventtransition_p.h" +#include "qwrappedevent.h" +#endif + +#ifndef QT_NO_ANIMATION +#include "qpropertyanimation.h" +#include "qanimationgroup.h" +#include <private/qvariantanimation_p.h> +#endif + +#include <QtCore/qmetaobject.h> +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QStateMachine + \reentrant + + \brief The QStateMachine class provides a hierarchical finite state machine. + + \since 4.6 + \ingroup statemachine + + QStateMachine is based on the concepts and notation of + \l{Statecharts: A visual formalism for complex + systems}{Statecharts}. QStateMachine is part of \l{The State + Machine Framework}. + + A state machine manages a set of states (classes that inherit from + QAbstractState) and transitions (descendants of + QAbstractTransition) between those states; these states and + transitions define a state graph. Once a state graph has been + built, the state machine can execute it. \l{QStateMachine}'s + execution algorithm is based on the \l{State Chart XML: State + Machine Notation for Control Abstraction}{State Chart XML (SCXML)} + algorithm. The framework's \l{The State Machine + Framework}{overview} gives several state graphs and the code to + build them. + + The rootState() is the parent of all top-level states in the + machine; it is used, for instance, when the state graph is + deleted. It is created by the machine. + + Use the addState() function to add a state to the state machine. + All top-level states are added to the root state. States are + removed with the removeState() function. Removing states while the + machine is running is discouraged. + + Before the machine can be started, the \l{initialState}{initial + state} must be set. The initial state is the state that the + machine enters when started. You can then start() the state + machine. The started() signal is emitted when the initial state is + entered. + + The machine is event driven and keeps its own event loop. Events + are posted to the machine through postEvent(). Note that this + means that it executes asynchronously, and that it will not + progress without a running event loop. You will normally not have + to post events to the machine directly as Qt's transitions, e.g., + QEventTransition and its subclasses, handle this. But for custom + transitions triggered by events, postEvent() is useful. + + The state machine processes events and takes transitions until a + top-level final state is entered; the state machine then emits the + finished() signal. You can also stop() the state machine + explicitly. The stopped() signal is emitted in this case. + + The following snippet shows a state machine that will finish when a button + is clicked: + + \code + QPushButton button; + + QStateMachine machine; + QState *s1 = new QState(); + s1->assignProperty(&button, "text", "Click me"); + + QFinalState *s2 = new QFinalState(); + s1->addTransition(&button, SIGNAL(clicked()), s2); + + machine.addState(s1); + machine.addState(s2); + machine.setInitialState(s1); + machine.start(); + \endcode + + This code example uses QState, which inherits QAbstractState. The + QState class provides a state that you can use to set properties + and invoke methods on \l{QObject}s when the state is entered or + exited. It also contains convenience functions for adding + transitions, e.g., \l{QSignalTransition}s as in this example. See + the QState class description for further details. + + If an error is encountered, the machine will enter the + \l{errorState}{error state}, which is a special state created by + the machine. The types of errors possible are described by the + \l{QStateMachine::}{Error} enum. After the error state is entered, + the type of the error can be retrieved with error(). The execution + of the state graph will not stop when the error state is entered. + So it is possible to handle the error, for instance, by connecting + to the \l{QAbstractState::}{entered()} signal of the error state. + It is also possible to set a custom error state with + setErrorState(). + + \omit This stuff will be moved elsewhere +This is + typically used in conjunction with \l{Signals and Slots}{signals}; the + signals determine the flow of the state graph, whereas the states' property + assignments and method invocations are the actions. + + The postEvent() function posts an event to the state machine. This is useful + when you are using custom events to trigger transitions. + \endomit + + \sa QAbstractState, QAbstractTransition, QState, {The State Machine Framework} +*/ + +/*! + \property QStateMachine::rootState + + \brief the root state of this state machine +*/ + +/*! + \property QStateMachine::initialState + + \brief the initial state of this state machine + + The initial state must be one of the rootState()'s child states. +*/ + +/*! + \property QStateMachine::errorState + + \brief the error state of this state machine +*/ + +/*! + \property QStateMachine::errorString + + \brief the error string of this state machine +*/ + +/*! + \property QStateMachine::globalRestorePolicy + + \brief the restore policy for states of this state machine. + + The default value of this property is + QStateMachine::DoNotRestoreProperties. +*/ + +#ifndef QT_NO_ANIMATION +/*! + \property QStateMachine::animationsEnabled + + \brief whether animations are enabled + + The default value of this property is true. + + \sa QAbstractTransition::addAnimation() +*/ +#endif + +// #define QSTATEMACHINE_DEBUG + +QStateMachinePrivate::QStateMachinePrivate() +{ + state = NotRunning; + processing = false; + processingScheduled = false; + stop = false; + error = QStateMachine::NoError; + globalRestorePolicy = QStateMachine::DoNotRestoreProperties; + rootState = 0; + initialErrorStateForRoot = 0; + signalEventGenerator = 0; +#ifndef QT_NO_ANIMATION + animationsEnabled = true; +#endif +} + +QStateMachinePrivate::~QStateMachinePrivate() +{ + qDeleteAll(internalEventQueue); + qDeleteAll(externalEventQueue); +} + +QStateMachinePrivate *QStateMachinePrivate::get(QStateMachine *q) +{ + if (q) + return q->d_func(); + return 0; +} + +static QEvent *cloneEvent(QEvent *e) +{ + switch (e->type()) { + case QEvent::None: + return new QEvent(*e); + case QEvent::Timer: + return new QTimerEvent(*static_cast<QTimerEvent*>(e)); + default: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + } + return 0; +} + +const QStateMachinePrivate::Handler qt_kernel_statemachine_handler = { + cloneEvent +}; + +const QStateMachinePrivate::Handler *QStateMachinePrivate::handler = &qt_kernel_statemachine_handler; + +Q_CORE_EXPORT const QStateMachinePrivate::Handler *qcoreStateMachineHandler() +{ + return &qt_kernel_statemachine_handler; +} + +static int indexOfDescendant(QState *s, QAbstractState *desc) +{ + QList<QAbstractState*> childStates = QStatePrivate::get(s)->childStates(); + for (int i = 0; i < childStates.size(); ++i) { + QAbstractState *c = childStates.at(i); + if ((c == desc) || QStateMachinePrivate::isDescendantOf(desc, c)) { + return i; + } + } + return -1; +} + +bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState *s2) +{ + if (s1->parent() == s2->parent()) { + return s1->children().indexOf(s1) + < s2->children().indexOf(s2); + } else if (isDescendantOf(s1, s2)) { + return false; + } else if (isDescendantOf(s2, s1)) { + return true; + } else { + QState *lca = findLCA(QList<QAbstractState*>() << s1 << s2); + Q_ASSERT(lca != 0); + return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2)); + } +} + +bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState *s2) +{ + if (s1->parent() == s2->parent()) { + return s1->children().indexOf(s1) + < s2->children().indexOf(s2); + } else if (isDescendantOf(s1, s2)) { + return true; + } else if (isDescendantOf(s2, s1)) { + return false; + } else { + QState *lca = findLCA(QList<QAbstractState*>() << s1 << s2); + Q_ASSERT(lca != 0); + return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2)); + } +} + +QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states) +{ + if (states.isEmpty()) + return 0; + QList<QState*> ancestors = properAncestors(states.at(0), 0); + for (int i = 0; i < ancestors.size(); ++i) { + QState *anc = ancestors.at(i); + bool ok = true; + for (int j = states.size() - 1; (j > 0) && ok; --j) { + const QAbstractState *s = states.at(j); + if (!isDescendantOf(s, anc)) + ok = false; + } + if (ok) + return anc; + } + return 0; +} + +bool QStateMachinePrivate::isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const +{ + QSet<QAbstractTransition*>::const_iterator it; + for (it = transitions.constBegin(); it != transitions.constEnd(); ++it) { + QAbstractTransition *t = *it; + QList<QAbstractState*> lst = t->targetStates(); + if (!lst.isEmpty()) { + lst.prepend(t->sourceState()); + QAbstractState *lca = findLCA(lst); + if (isDescendantOf(s, lca)) { +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ':' << transitions << "preempts selection of a transition from" + << s << "because" << s << "is a descendant of" << lca; +#endif + return true; + } + } + } + return false; +} + +QSet<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event) const +{ + Q_Q(const QStateMachine); + QSet<QAbstractTransition*> enabledTransitions; + QSet<QAbstractState*>::const_iterator it; + const_cast<QStateMachine*>(q)->beginSelectTransitions(event); + for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { + QAbstractState *state = *it; + if (!isAtomic(state)) + continue; + if (isPreempted(state, enabledTransitions)) + continue; + QList<QState*> lst = properAncestors(state, 0); + if (QState *grp = qobject_cast<QState*>(state)) + lst.prepend(grp); + bool found = false; + for (int j = 0; (j < lst.size()) && !found; ++j) { + QState *s = lst.at(j); + QList<QAbstractTransition*> transitions = QStatePrivate::get(s)->transitions(); + for (int k = 0; k < transitions.size(); ++k) { + QAbstractTransition *t = transitions.at(k); + if (QAbstractTransitionPrivate::get(t)->callEventTest(event)) { +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": selecting transition" << t; +#endif + enabledTransitions.insert(t); + found = true; + break; + } + } + } + } + const_cast<QStateMachine*>(q)->endSelectTransitions(event); + return enabledTransitions; +} + +void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions) +{ +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ')'; + qDebug() << q_func() << ": configuration before exiting states:" << configuration; +#endif + QList<QAbstractState*> exitedStates = exitStates(event, enabledTransitions); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": configuration after exiting states:" << configuration; +#endif + executeTransitionContent(event, enabledTransitions); + QList<QAbstractState*> enteredStates = enterStates(event, enabledTransitions); + applyProperties(enabledTransitions, exitedStates, enteredStates); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": configuration after entering states:" << configuration; + qDebug() << q_func() << ": end microstep"; +#endif +} + +QList<QAbstractState*> QStateMachinePrivate::exitStates(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions) +{ +// qDebug() << "exitStates(" << enabledTransitions << ')'; + QSet<QAbstractState*> statesToExit; +// QSet<QAbstractState*> statesToSnapshot; + for (int i = 0; i < enabledTransitions.size(); ++i) { + QAbstractTransition *t = enabledTransitions.at(i); + QList<QAbstractState*> lst = t->targetStates(); + if (lst.isEmpty()) + continue; + lst.prepend(t->sourceState()); + QAbstractState *lca = findLCA(lst); + if (lca == 0) { + setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState()); + lst = pendingErrorStates.toList(); + lst.prepend(t->sourceState()); + + lca = findLCA(lst); + Q_ASSERT(lca != 0); + } + + { + QSet<QAbstractState*>::const_iterator it; + for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { + QAbstractState *s = *it; + if (isDescendantOf(s, lca)) + statesToExit.insert(s); + } + } + } + QList<QAbstractState*> statesToExit_sorted = statesToExit.toList(); + qSort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan); + for (int i = 0; i < statesToExit_sorted.size(); ++i) { + QAbstractState *s = statesToExit_sorted.at(i); + if (QState *grp = qobject_cast<QState*>(s)) { + QList<QHistoryState*> hlst = QStatePrivate::get(grp)->historyStates(); + for (int j = 0; j < hlst.size(); ++j) { + QHistoryState *h = hlst.at(j); + QHistoryStatePrivate::get(h)->configuration.clear(); + QSet<QAbstractState*>::const_iterator it; + for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { + QAbstractState *s0 = *it; + if (QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) { + if (isAtomic(s0) && isDescendantOf(s0, s)) + QHistoryStatePrivate::get(h)->configuration.append(s0); + } else if (s0->parentState() == s) { + QHistoryStatePrivate::get(h)->configuration.append(s0); + } + } +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": recorded" << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow") + << "history for" << s << "in" << h << ':' << QHistoryStatePrivate::get(h)->configuration; +#endif + } + } + } + for (int i = 0; i < statesToExit_sorted.size(); ++i) { + QAbstractState *s = statesToExit_sorted.at(i); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": exiting" << s; +#endif + QAbstractStatePrivate::get(s)->callOnExit(event); + configuration.remove(s); + QAbstractStatePrivate::get(s)->emitExited(); + } + return statesToExit_sorted; +} + +void QStateMachinePrivate::executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions) +{ + for (int i = 0; i < enabledTransitions.size(); ++i) { + QAbstractTransition *t = enabledTransitions.at(i); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": triggering" << t; +#endif + QAbstractTransitionPrivate::get(t)->callOnTransition(event); + } +} + +QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions) +{ +#ifdef QSTATEMACHINE_DEBUG + Q_Q(QStateMachine); +#endif +// qDebug() << "enterStates(" << enabledTransitions << ')'; + QSet<QAbstractState*> statesToEnter; + QSet<QAbstractState*> statesForDefaultEntry; + + if (pendingErrorStates.isEmpty()) { + for (int i = 0; i < enabledTransitions.size(); ++i) { + QAbstractTransition *t = enabledTransitions.at(i); + QList<QAbstractState*> lst = t->targetStates(); + if (lst.isEmpty()) + continue; + lst.prepend(t->sourceState()); + QState *lca = findLCA(lst); + for (int j = 1; j < lst.size(); ++j) { + QAbstractState *s = lst.at(j); + addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry); + if (isParallel(lca)) { + QList<QAbstractState*> lcac = QStatePrivate::get(lca)->childStates(); + foreach (QAbstractState* child,lcac) { + if (!statesToEnter.contains(child)) + addStatesToEnter(child,lca,statesToEnter,statesForDefaultEntry); + } + } + } + } + } + + // Did an error occur while selecting transitions? Then we enter the error state. + if (!pendingErrorStates.isEmpty()) { + statesToEnter.clear(); + statesToEnter = pendingErrorStates; + statesForDefaultEntry = pendingErrorStatesForDefaultEntry; + pendingErrorStates.clear(); + pendingErrorStatesForDefaultEntry.clear(); + } + + QList<QAbstractState*> statesToEnter_sorted = statesToEnter.toList(); + qSort(statesToEnter_sorted.begin(), statesToEnter_sorted.end(), stateEntryLessThan); + + for (int i = 0; i < statesToEnter_sorted.size(); ++i) { + QAbstractState *s = statesToEnter_sorted.at(i); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": entering" << s; +#endif + configuration.insert(s); + registerTransitions(s); + QAbstractStatePrivate::get(s)->callOnEntry(event); + QAbstractStatePrivate::get(s)->emitEntered(); + if (statesForDefaultEntry.contains(s)) { + // ### executeContent(s.initial.transition.children()) + } + if (isFinal(s)) { + QState *parent = s->parentState(); + if (parent) { + QState *grandparent = parent->parentState(); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": emitting finished signal for" << parent; +#endif + QStatePrivate::get(parent)->emitFinished(); + if (grandparent && isParallel(grandparent)) { + bool allChildStatesFinal = true; + QList<QAbstractState*> childStates = QStatePrivate::get(grandparent)->childStates(); + for (int j = 0; j < childStates.size(); ++j) { + QAbstractState *cs = childStates.at(j); + if (!isInFinalState(cs)) { + allChildStatesFinal = false; + break; + } + } + if (allChildStatesFinal) { +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": emitting finished signal for" << grandparent; +#endif + QStatePrivate::get(grandparent)->emitFinished(); + } + } + } + } + } + { + QSet<QAbstractState*>::const_iterator it; + for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { + if (isFinal(*it) && (*it)->parentState() == rootState) { + processing = false; + stopProcessingReason = Finished; + break; + } + } + } +// qDebug() << "configuration:" << configuration.toList(); + return statesToEnter_sorted; +} + +void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root, + QSet<QAbstractState*> &statesToEnter, + QSet<QAbstractState*> &statesForDefaultEntry) +{ + if (QHistoryState *h = qobject_cast<QHistoryState*>(s)) { + QList<QAbstractState*> hconf = QHistoryStatePrivate::get(h)->configuration; + if (!hconf.isEmpty()) { + for (int k = 0; k < hconf.size(); ++k) { + QAbstractState *s0 = hconf.at(k); + addStatesToEnter(s0, root, statesToEnter, statesForDefaultEntry); + } + #ifdef QSTATEMACHINE_DEBUG + qDebug() <<q_func() << ": restoring" + << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow") + << "history from" << s << ':' << hconf; + #endif + } else { + QList<QAbstractState*> hlst; + if (QHistoryStatePrivate::get(h)->defaultState) + hlst.append(QHistoryStatePrivate::get(h)->defaultState); + + if (hlst.isEmpty()) { + setError(QStateMachine::NoDefaultStateInHistoryStateError, h); + } else { + for (int k = 0; k < hlst.size(); ++k) { + QAbstractState *s0 = hlst.at(k); + addStatesToEnter(s0, root, statesToEnter, statesForDefaultEntry); + } + #ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": initial history targets for" << s << ':' << hlst; + #endif + } + } + } else { + statesToEnter.insert(s); + if (isParallel(s)) { + QState *grp = qobject_cast<QState*>(s); + QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates(); + for (int i = 0; i < lst.size(); ++i) { + QAbstractState *child = lst.at(i); + addStatesToEnter(child, grp, statesToEnter, statesForDefaultEntry); + } + } else if (isCompound(s)) { + statesForDefaultEntry.insert(s); + QState *grp = qobject_cast<QState*>(s); + QAbstractState *initial = grp->initialState(); + if (initial != 0) { + addStatesToEnter(initial, grp, statesToEnter, statesForDefaultEntry); + } else { + setError(QStateMachine::NoInitialStateError, grp); + return; + } + } + QList<QState*> ancs = properAncestors(s, root); + for (int i = 0; i < ancs.size(); ++i) { + QState *anc = ancs.at(i); + if (!anc->parentState()) + continue; + statesToEnter.insert(anc); + if (isParallel(anc)) { + QList<QAbstractState*> lst = QStatePrivate::get(anc)->childStates(); + for (int j = 0; j < lst.size(); ++j) { + QAbstractState *child = lst.at(j); + bool hasDescendantInList = false; + QSet<QAbstractState*>::const_iterator it; + for (it = statesToEnter.constBegin(); it != statesToEnter.constEnd(); ++it) { + if (isDescendantOf(*it, child)) { + hasDescendantInList = true; + break; + } + } + if (!hasDescendantInList) + addStatesToEnter(child, anc, statesToEnter, statesForDefaultEntry); + } + } + } + } +} + +void QStateMachinePrivate::applyProperties(const QList<QAbstractTransition*> &transitionList, + const QList<QAbstractState*> &exitedStates, + const QList<QAbstractState*> &enteredStates) +{ +#ifdef QT_NO_ANIMATION + Q_UNUSED(transitionList); + Q_UNUSED(exitedStates); +#else + Q_Q(QStateMachine); +#endif + // Process the property assignments of the entered states. + QHash<QAbstractState*, QList<QPropertyAssignment> > propertyAssignmentsForState; + QHash<RestorableId, QVariant> pendingRestorables = registeredRestorables; + for (int i = 0; i < enteredStates.size(); ++i) { + QState *s = qobject_cast<QState*>(enteredStates.at(i)); + if (!s) + continue; + + QList<QPropertyAssignment> assignments = QStatePrivate::get(s)->propertyAssignments; + for (int j = 0; j < assignments.size(); ++j) { + const QPropertyAssignment &assn = assignments.at(j); + if (globalRestorePolicy == QStateMachine::RestoreProperties) { + registerRestorable(assn.object, assn.propertyName); + } + pendingRestorables.remove(RestorableId(assn.object, assn.propertyName)); + propertyAssignmentsForState[s].append(assn); + } + + // Remove pending restorables for all parent states to avoid restoring properties + // before the state that assigned them is exited. If state does not explicitly + // assign a property which is assigned by the parent, it inherits the parent's assignment. + QState *parentState = s; + while ((parentState = parentState->parentState()) != 0) { + assignments = QStatePrivate::get(parentState)->propertyAssignments; + for (int j=0; j<assignments.size(); ++j) { + const QPropertyAssignment &assn = assignments.at(j); + int c = pendingRestorables.remove(RestorableId(assn.object, assn.propertyName)); + if (c > 0) + propertyAssignmentsForState[s].append(assn); + } + } + } + if (!pendingRestorables.isEmpty()) { + QAbstractState *s; + if (!enteredStates.isEmpty()) + s = enteredStates.last(); // ### handle if parallel + else + s = 0; + propertyAssignmentsForState[s] << restorablesToPropertyList(pendingRestorables); + } + +#ifndef QT_NO_ANIMATION + // Gracefully terminate playing animations for states that are exited. + for (int i = 0; i < exitedStates.size(); ++i) { + QAbstractState *s = exitedStates.at(i); + QList<QAbstractAnimation*> animations = animationsForState.take(s); + for (int j = 0; j < animations.size(); ++j) { + QAbstractAnimation *anim = animations.at(j); + QObject::disconnect(anim, SIGNAL(finished()), q, SLOT(_q_animationFinished())); + stateForAnimation.remove(anim); + + // Stop the (top-level) animation. + // ### Stopping nested animation has weird behavior. + QAbstractAnimation *topLevelAnim = anim; + while (QAnimationGroup *group = topLevelAnim->group()) + topLevelAnim = group; + topLevelAnim->stop(); + + if (resetAnimationEndValues.contains(anim)) { + qobject_cast<QVariantAnimation*>(anim)->setEndValue(QVariant()); // ### generalize + resetAnimationEndValues.remove(anim); + } + QPropertyAssignment assn = propertyForAnimation.take(anim); + Q_ASSERT(assn.object != 0); + // If there is no property assignment that sets this property, + // set the property to its target value. + bool found = false; + QHash<QAbstractState*, QList<QPropertyAssignment> >::const_iterator it; + for (it = propertyAssignmentsForState.constBegin(); it != propertyAssignmentsForState.constEnd(); ++it) { + const QList<QPropertyAssignment> &assignments = it.value(); + for (int k = 0; k < assignments.size(); ++k) { + if ((assignments.at(k).object == assn.object) + && (assignments.at(k).propertyName == assn.propertyName)) { + found = true; + break; + } + } + } + if (!found) { + assn.object->setProperty(assn.propertyName, assn.value); + } + } + } + + // Find the animations to use for the state change. + QList<QAbstractAnimation*> selectedAnimations; + if (animationsEnabled) { + for (int i = 0; i < transitionList.size(); ++i) { + QAbstractTransition *transition = transitionList.at(i); + + selectedAnimations << transition->animations(); + selectedAnimations << defaultAnimationsForSource.values(transition->sourceState()); + + QList<QAbstractState *> targetStates = transition->targetStates(); + for (int j=0; j<targetStates.size(); ++j) + selectedAnimations << defaultAnimationsForTarget.values(targetStates.at(j)); + } + selectedAnimations << defaultAnimations; + } + + // Initialize animations from property assignments. + for (int i = 0; i < selectedAnimations.size(); ++i) { + QAbstractAnimation *anim = selectedAnimations.at(i); + QHash<QAbstractState*, QList<QPropertyAssignment> >::iterator it; + for (it = propertyAssignmentsForState.begin(); it != propertyAssignmentsForState.end(); ) { + QList<QPropertyAssignment>::iterator it2; + QAbstractState *s = it.key(); + QList<QPropertyAssignment> &assignments = it.value(); + for (it2 = assignments.begin(); it2 != assignments.end(); ) { + QPair<QList<QAbstractAnimation*>, QList<QAbstractAnimation*> > ret; + ret = initializeAnimation(anim, *it2); + QList<QAbstractAnimation*> handlers = ret.first; + if (!handlers.isEmpty()) { + for (int j = 0; j < handlers.size(); ++j) { + QAbstractAnimation *a = handlers.at(j); + propertyForAnimation.insert(a, *it2); + stateForAnimation.insert(a, s); + animationsForState[s].append(a); + // ### connect to just the top-level animation? + QObject::connect(a, SIGNAL(finished()), q, SLOT(_q_animationFinished()), Qt::UniqueConnection); + } + it2 = assignments.erase(it2); + } else { + ++it2; + } + for (int j = 0; j < ret.second.size(); ++j) + resetAnimationEndValues.insert(ret.second.at(j)); + } + if (assignments.isEmpty()) + it = propertyAssignmentsForState.erase(it); + else + ++it; + } + // We require that at least one animation is valid. + // ### generalize + QList<QVariantAnimation*> variantAnims = qFindChildren<QVariantAnimation*>(anim); + if (QVariantAnimation *va = qobject_cast<QVariantAnimation*>(anim)) + variantAnims.append(va); + + bool hasValidEndValue = false; + for (int j = 0; j < variantAnims.size(); ++j) { + if (variantAnims.at(j)->endValue().isValid()) { + hasValidEndValue = true; + break; + } + } + + if (hasValidEndValue) { + anim->start(); + } + } +#endif // !QT_NO_ANIMATION + + // Immediately set the properties that are not animated. + { + QHash<QAbstractState*, QList<QPropertyAssignment> >::const_iterator it; + for (it = propertyAssignmentsForState.constBegin(); it != propertyAssignmentsForState.constEnd(); ++it) { + const QList<QPropertyAssignment> &assignments = it.value(); + for (int i = 0; i < assignments.size(); ++i) { + const QPropertyAssignment &assn = assignments.at(i); + assn.object->setProperty(assn.propertyName, assn.value); + } + } + } + + // Emit polished signal for entered states that have no animated properties. + for (int i = 0; i < enteredStates.size(); ++i) { + QState *s = qobject_cast<QState*>(enteredStates.at(i)); + if (s +#ifndef QT_NO_ANIMATION + && !animationsForState.contains(s) +#endif + ) + QStatePrivate::get(s)->emitPolished(); + } +} + +bool QStateMachinePrivate::isFinal(const QAbstractState *s) +{ + return qobject_cast<const QFinalState*>(s) != 0; +} + +bool QStateMachinePrivate::isParallel(const QAbstractState *s) +{ + const QState *ss = qobject_cast<const QState*>(s); + return ss && (QStatePrivate::get(ss)->childMode == QState::ParallelStates); +} + +bool QStateMachinePrivate::isCompound(const QAbstractState *s) +{ + const QState *group = qobject_cast<const QState*>(s); + if (!group) + return false; + return (!isParallel(group) && !QStatePrivate::get(group)->childStates().isEmpty()) + || (qobject_cast<QStateMachine*>(group->parent()) != 0); +} + +bool QStateMachinePrivate::isAtomic(const QAbstractState *s) +{ + const QState *ss = qobject_cast<const QState*>(s); + return (ss && QStatePrivate::get(ss)->childStates().isEmpty()) + || isFinal(s); +} + + +bool QStateMachinePrivate::isDescendantOf(const QAbstractState *state, const QAbstractState *other) +{ + Q_ASSERT(state != 0); + for (QAbstractState *s = state->parentState(); s != 0; s = s->parentState()) { + if (s == other) + return true; + } + return false; +} + +QList<QState*> QStateMachinePrivate::properAncestors(const QAbstractState *state, const QState *upperBound) +{ + Q_ASSERT(state != 0); + QList<QState*> result; + for (QState *s = state->parentState(); s && s != upperBound; s = s->parentState()) { + result.append(s); + } + return result; +} + +bool QStateMachinePrivate::isInFinalState(QAbstractState* s) const +{ + if (isCompound(s)) { + QState *grp = qobject_cast<QState*>(s); + QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates(); + for (int i = 0; i < lst.size(); ++i) { + QAbstractState *cs = lst.at(i); + if (isFinal(cs) && configuration.contains(cs)) + return true; + } + return false; + } else if (isParallel(s)) { + QState *grp = qobject_cast<QState*>(s); + QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates(); + for (int i = 0; i < lst.size(); ++i) { + QAbstractState *cs = lst.at(i); + if (!isInFinalState(cs)) + return false; + } + return true; + } + else + return false; +} + +void QStateMachinePrivate::registerRestorable(QObject *object, const QByteArray &propertyName) +{ + RestorableId id(object, propertyName); + if (!registeredRestorables.contains(id)) + registeredRestorables.insert(id, object->property(propertyName)); +} + +QList<QPropertyAssignment> QStateMachinePrivate::restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const +{ + QList<QPropertyAssignment> result; + QHash<RestorableId, QVariant>::const_iterator it; + for (it = restorables.constBegin(); it != restorables.constEnd(); ++it) { +// qDebug() << "restorable:" << it.key().first << it.key().second << it.value(); + result.append(QPropertyAssignment(it.key().first, it.key().second, it.value(), /*explicitlySet=*/false)); + } + return result; +} + +/*! + \internal + Returns true if the variable with the given \a id has been registered for restoration. +*/ +bool QStateMachinePrivate::hasRestorable(QObject *object, const QByteArray &propertyName) const +{ + return registeredRestorables.contains(RestorableId(object, propertyName)); +} + +QVariant QStateMachinePrivate::restorableValue(QObject *object, const QByteArray &propertyName) const +{ + return registeredRestorables.value(RestorableId(object, propertyName), QVariant()); +} + + +/*! + \internal + Unregisters the variable identified by \a id +*/ +void QStateMachinePrivate::unregisterRestorable(QObject *object, const QByteArray &propertyName) +{ +// qDebug() << "unregisterRestorable(" << object << propertyName << ')'; + RestorableId id(object, propertyName); + registeredRestorables.remove(id); +} + +QAbstractState *QStateMachinePrivate::findErrorState(QAbstractState *context) +{ + // If the user sets the root state's error state to 0, we return the initial error state + if (context == 0) + return initialErrorStateForRoot; + + // Find error state recursively in parent hierarchy if not set explicitly for context state + QAbstractState *errorState = 0; + + QState *s = qobject_cast<QState*>(context); + if (s) + errorState = s->errorState(); + + if (!errorState) + errorState = findErrorState(context->parentState()); + + return errorState; +} + +void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractState *currentContext) +{ + error = errorCode; + + switch (errorCode) { + case QStateMachine::NoInitialStateError: + Q_ASSERT(currentContext != 0); + + errorString = QStateMachine::tr("Missing initial state in compound state '%1'") + .arg(currentContext->objectName()); + + break; + case QStateMachine::NoDefaultStateInHistoryStateError: + Q_ASSERT(currentContext != 0); + + errorString = QStateMachine::tr("Missing default state in history state '%1'") + .arg(currentContext->objectName()); + break; + + case QStateMachine::NoCommonAncestorForTransitionError: + Q_ASSERT(currentContext != 0); + + errorString = QStateMachine::tr("No common ancestor for targets and source of transition from state '%1'") + .arg(currentContext->objectName()); + break; + default: + errorString = QStateMachine::tr("Unknown error"); + }; + + pendingErrorStates.clear(); + pendingErrorStatesForDefaultEntry.clear(); + + QAbstractState *currentErrorState = findErrorState(currentContext); + + // Avoid infinite loop if the error state itself has an error + if (currentContext == currentErrorState) { + Q_ASSERT(currentContext != initialErrorStateForRoot); // RootErrorState is broken + currentErrorState = initialErrorStateForRoot; + } + + Q_ASSERT(currentErrorState != 0); + Q_ASSERT(currentErrorState != rootState); + + QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext); + addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry); +} + +#ifndef QT_NO_ANIMATION + +QPair<QList<QAbstractAnimation*>, QList<QAbstractAnimation*> > +QStateMachinePrivate::initializeAnimation(QAbstractAnimation *abstractAnimation, + const QPropertyAssignment &prop) +{ + QList<QAbstractAnimation*> handledAnimations; + QList<QAbstractAnimation*> localResetEndValues; + QAnimationGroup *group = qobject_cast<QAnimationGroup*>(abstractAnimation); + if (group) { + for (int i = 0; i < group->animationCount(); ++i) { + QAbstractAnimation *animationChild = group->animationAt(i); + QPair<QList<QAbstractAnimation*>, QList<QAbstractAnimation*> > ret; + ret = initializeAnimation(animationChild, prop); + handledAnimations << ret.first; + localResetEndValues << ret.second; + } + } else { + QPropertyAnimation *animation = qobject_cast<QPropertyAnimation *>(abstractAnimation); + if (animation != 0 + && prop.object == animation->targetObject() + && prop.propertyName == animation->propertyName()) { + + // Only change end value if it is undefined + if (!animation->endValue().isValid()) { + animation->setEndValue(prop.value); + localResetEndValues.append(animation); + } + handledAnimations.append(animation); + } + } + return qMakePair(handledAnimations, localResetEndValues); +} + +void QStateMachinePrivate::_q_animationFinished() +{ + Q_Q(QStateMachine); + QAbstractAnimation *anim = qobject_cast<QAbstractAnimation*>(q->sender()); + Q_ASSERT(anim != 0); + QObject::disconnect(anim, SIGNAL(finished()), q, SLOT(_q_animationFinished())); + if (resetAnimationEndValues.contains(anim)) { + qobject_cast<QVariantAnimation*>(anim)->setEndValue(QVariant()); // ### generalize + resetAnimationEndValues.remove(anim); + } + + // Set the final property value. + QPropertyAssignment assn = propertyForAnimation.take(anim); + Q_ASSERT(assn.object != 0); + assn.object->setProperty(assn.propertyName, assn.value); + if (!assn.explicitlySet) + unregisterRestorable(assn.object, assn.propertyName); + + QAbstractState *state = stateForAnimation.take(anim); + Q_ASSERT(state != 0); + QHash<QAbstractState*, QList<QAbstractAnimation*> >::iterator it; + it = animationsForState.find(state); + Q_ASSERT(it != animationsForState.end()); + QList<QAbstractAnimation*> &animations = it.value(); + animations.removeOne(anim); + if (animations.isEmpty()) { + animationsForState.erase(it); + QStatePrivate::get(qobject_cast<QState*>(state))->emitPolished(); + } +} + +#endif // !QT_NO_ANIMATION + +namespace { + +class StartState : public QState +{ +public: + StartState(QState *parent) + : QState(parent) {} +protected: + void onEntry(QEvent *) {} + void onExit(QEvent *) {} +}; + +class InitialTransition : public QAbstractTransition +{ +public: + InitialTransition(QAbstractState *target) + : QAbstractTransition(QList<QAbstractState*>() << target) {} +protected: + virtual bool eventTest(QEvent *) { return true; } + virtual void onTransition(QEvent *) {} +}; + +} // namespace + +void QStateMachinePrivate::_q_start() +{ + Q_Q(QStateMachine); + Q_ASSERT(state == Starting); + if (!rootState) { + state = NotRunning; + return; + } + QAbstractState *initial = rootState->initialState(); + if (initial == 0) + setError(QStateMachine::NoInitialStateError, rootState); + + configuration.clear(); + qDeleteAll(internalEventQueue); + internalEventQueue.clear(); + qDeleteAll(externalEventQueue); + externalEventQueue.clear(); + +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": starting"; +#endif + state = Running; + processingScheduled = true; // we call _q_process() below + emit q->started(); + + StartState *start = new StartState(rootState); + QAbstractTransition *initialTransition = new InitialTransition(initial); + start->addTransition(initialTransition); + QList<QAbstractTransition*> transitions; + transitions.append(initialTransition); + QEvent nullEvent(QEvent::None); + executeTransitionContent(&nullEvent, transitions); + enterStates(&nullEvent, transitions); + applyProperties(transitions, QList<QAbstractState*>() << start, + QList<QAbstractState*>() << initial); + delete start; + +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": initial configuration:" << configuration; +#endif + _q_process(); +} + +void QStateMachinePrivate::_q_process() +{ + Q_Q(QStateMachine); + Q_ASSERT(state == Running); + Q_ASSERT(!processing); + processing = true; + processingScheduled = false; +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": starting the event processing loop"; +#endif + while (processing) { + if (stop) { + stop = false; + processing = false; + stopProcessingReason = Stopped; + break; + } + QSet<QAbstractTransition*> enabledTransitions; + QEvent *e = new QEvent(QEvent::None); + enabledTransitions = selectTransitions(e); + if (enabledTransitions.isEmpty()) { + delete e; + e = 0; + } + if (enabledTransitions.isEmpty() && !internalEventQueue.isEmpty()) { + e = internalEventQueue.takeFirst(); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": dequeued internal event" << e << "of type" << e->type(); +#endif + enabledTransitions = selectTransitions(e); + if (enabledTransitions.isEmpty()) { + delete e; + e = 0; + } + } + if (enabledTransitions.isEmpty()) { + if (externalEventQueue.isEmpty()) { + if (internalEventQueue.isEmpty()) { + processing = false; + stopProcessingReason = EventQueueEmpty; + } + } else { + e = externalEventQueue.takeFirst(); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": dequeued external event" << e << "of type" << e->type(); +#endif + enabledTransitions = selectTransitions(e); + if (enabledTransitions.isEmpty()) { + delete e; + e = 0; + } + } + } + if (!enabledTransitions.isEmpty()) { + q->beginMicrostep(e); + microstep(e, enabledTransitions.toList()); + q->endMicrostep(e); + } +#ifdef QSTATEMACHINE_DEBUG + else { + qDebug() << q << ": no transitions enabled"; + } +#endif + delete e; + } +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": finished the event processing loop"; +#endif + switch (stopProcessingReason) { + case EventQueueEmpty: + break; + case Finished: + state = NotRunning; + unregisterAllTransitions(); + emit q->finished(); + break; + case Stopped: + state = NotRunning; + unregisterAllTransitions(); + emit q->stopped(); + break; + } +} + +void QStateMachinePrivate::scheduleProcess() +{ + if ((state != Running) || processing || processingScheduled) + return; + processingScheduled = true; + QMetaObject::invokeMethod(q_func(), "_q_process", Qt::QueuedConnection); +} + +void QStateMachinePrivate::registerTransitions(QAbstractState *state) +{ + QState *group = qobject_cast<QState*>(state); + if (!group) + return; + QList<QAbstractTransition*> transitions = QStatePrivate::get(group)->transitions(); + for (int i = 0; i < transitions.size(); ++i) { + QAbstractTransition *t = transitions.at(i); + if (QSignalTransition *st = qobject_cast<QSignalTransition*>(t)) { + registerSignalTransition(st); + } +#ifndef QT_NO_STATEMACHINE_EVENTFILTER + else if (QEventTransition *oet = qobject_cast<QEventTransition*>(t)) { + registerEventTransition(oet); + } +#endif + } +} + +void QStateMachinePrivate::unregisterTransition(QAbstractTransition *transition) +{ + if (QSignalTransition *st = qobject_cast<QSignalTransition*>(transition)) { + unregisterSignalTransition(st); + } +#ifndef QT_NO_STATEMACHINE_EVENTFILTER + else if (QEventTransition *oet = qobject_cast<QEventTransition*>(transition)) { + unregisterEventTransition(oet); + } +#endif +} + +void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transition) +{ + Q_Q(QStateMachine); + if (QSignalTransitionPrivate::get(transition)->signalIndex != -1) + return; // already registered + QObject *sender = QSignalTransitionPrivate::get(transition)->sender; + if (!sender) + return; + QByteArray signal = QSignalTransitionPrivate::get(transition)->signal; + if (signal.startsWith('0'+QSIGNAL_CODE)) + signal.remove(0, 1); + int signalIndex = sender->metaObject()->indexOfSignal(signal); + if (signalIndex == -1) { + qWarning("QSignalTransition: no such signal: %s::%s", + sender->metaObject()->className(), signal.constData()); + return; + } + QVector<int> &connectedSignalIndexes = connections[sender]; + if (connectedSignalIndexes.size() <= signalIndex) + connectedSignalIndexes.resize(signalIndex+1); + if (connectedSignalIndexes.at(signalIndex) == 0) { + if (!signalEventGenerator) + signalEventGenerator = new QSignalEventGenerator(q); + bool ok = QMetaObject::connect(sender, signalIndex, signalEventGenerator, + signalEventGenerator->metaObject()->methodOffset()); + if (!ok) { +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": FAILED to add signal transition from" << transition->sourceState() + << ": ( sender =" << sender << ", signal =" << (signal.mid(1)) + << ", targets =" << transition->targetStates() << ')'; +#endif + return; + } + } + ++connectedSignalIndexes[signalIndex]; + QSignalTransitionPrivate::get(transition)->signalIndex = signalIndex; +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": added signal transition from" << transition->sourceState() + << ": ( sender =" << sender << ", signal =" << (signal.mid(1)) + << ", targets =" << transition->targetStates() << ')'; +#endif +} + +void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transition) +{ + int signalIndex = QSignalTransitionPrivate::get(transition)->signalIndex; + if (signalIndex == -1) + return; // not registered + QSignalTransitionPrivate::get(transition)->signalIndex = -1; + const QObject *sender = QSignalTransitionPrivate::get(transition)->sender; + QVector<int> &connectedSignalIndexes = connections[sender]; + Q_ASSERT(connectedSignalIndexes.size() > signalIndex); + Q_ASSERT(connectedSignalIndexes.at(signalIndex) != 0); + if (--connectedSignalIndexes[signalIndex] == 0) { + Q_ASSERT(signalEventGenerator != 0); + QMetaObject::disconnect(sender, signalIndex, signalEventGenerator, + signalEventGenerator->metaObject()->methodOffset()); + int sum = 0; + for (int i = 0; i < connectedSignalIndexes.size(); ++i) + sum += connectedSignalIndexes.at(i); + if (sum == 0) + connections.remove(sender); + } +} + +void QStateMachinePrivate::unregisterAllTransitions() +{ + { + QList<QSignalTransition*> transitions = qFindChildren<QSignalTransition*>(rootState); + for (int i = 0; i < transitions.size(); ++i) + unregisterSignalTransition(transitions.at(i)); + } + { + QList<QEventTransition*> transitions = qFindChildren<QEventTransition*>(rootState); + for (int i = 0; i < transitions.size(); ++i) + unregisterEventTransition(transitions.at(i)); + } +} + +#ifndef QT_NO_STATEMACHINE_EVENTFILTER +void QStateMachinePrivate::registerEventTransition(QEventTransition *transition) +{ + Q_Q(QStateMachine); + if (QEventTransitionPrivate::get(transition)->registered) + return; + if (transition->eventType() >= QEvent::User) { + qWarning("QObject event transitions are not supported for custom types"); + return; + } + QObject *object = QEventTransitionPrivate::get(transition)->object; + if (!object) + return; + QObjectPrivate *od = QObjectPrivate::get(object); + if (!od->eventFilters.contains(q)) + object->installEventFilter(q); + ++qobjectEvents[object][transition->eventType()]; + QEventTransitionPrivate::get(transition)->registered = true; +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": added event transition from" << transition->sourceState() + << ": ( object =" << object << ", event =" << transition->eventType() + << ", targets =" << transition->targetStates() << ')'; +#endif +} + +void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transition) +{ + Q_Q(QStateMachine); + if (!QEventTransitionPrivate::get(transition)->registered) + return; + QObject *object = QEventTransitionPrivate::get(transition)->object; + QHash<QEvent::Type, int> &events = qobjectEvents[object]; + Q_ASSERT(events.value(transition->eventType()) > 0); + if (--events[transition->eventType()] == 0) { + events.remove(transition->eventType()); + int sum = 0; + QHash<QEvent::Type, int>::const_iterator it; + for (it = events.constBegin(); it != events.constEnd(); ++it) + sum += it.value(); + if (sum == 0) { + qobjectEvents.remove(object); + object->removeEventFilter(q); + } + } + QEventTransitionPrivate::get(transition)->registered = false; +} +#endif + +void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int signalIndex, + void **argv) +{ + Q_ASSERT(connections[sender].at(signalIndex) != 0); + const QMetaObject *meta = sender->metaObject(); + QMetaMethod method = meta->method(signalIndex); + QList<QByteArray> parameterTypes = method.parameterTypes(); + int argc = parameterTypes.count(); + QList<QVariant> vargs; + for (int i = 0; i < argc; ++i) { + int type = QMetaType::type(parameterTypes.at(i)); + vargs.append(QVariant(type, argv[i+1])); + } + +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": sending signal event ( sender =" << sender + << ", signal =" << sender->metaObject()->method(signalIndex).signature() << ')'; +#endif + internalEventQueue.append(new QSignalEvent(sender, signalIndex, vargs)); + scheduleProcess(); +} + +/*! + Constructs a new state machine with the given \a parent. +*/ +QStateMachine::QStateMachine(QObject *parent) + : QObject(*new QStateMachinePrivate, parent) +{ +} + +/*! + \internal +*/ +QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + +/*! + Destroys this state machine. +*/ +QStateMachine::~QStateMachine() +{ +} + +namespace { + +class RootErrorState : public QAbstractState +{ +public: + RootErrorState(QState *parent) + : QAbstractState(parent) + { + setObjectName(QString::fromLatin1("DefaultErrorState")); + } + + void onEntry(QEvent *) + { + QAbstractStatePrivate *d = QAbstractStatePrivate::get(this); + QStateMachine *machine = d->machine(); + + qWarning("Unrecoverable error detected in running state machine: %s", + qPrintable(machine->errorString())); + } + + void onExit(QEvent *) {} +}; + +class RootState : public QState +{ +public: + RootState(QState *parent) + : QState(parent) + { + } + + void onEntry(QEvent *) {} + void onExit(QEvent *) {} +}; + +} // namespace + +/*! + Returns this state machine's root state. +*/ +QState *QStateMachine::rootState() const +{ + Q_D(const QStateMachine); + if (!d->rootState) { + const_cast<QStateMachinePrivate*>(d)->rootState = new RootState(0); + const_cast<QStateMachinePrivate*>(d)->initialErrorStateForRoot = new RootErrorState(d->rootState); + d->rootState->setParent(const_cast<QStateMachine*>(this)); + d->rootState->setErrorState(d->initialErrorStateForRoot); + } + return d->rootState; +} + +/*! + Returns the error state of the state machine's root state. + + \sa QState::errorState() +*/ +QAbstractState *QStateMachine::errorState() const +{ + return rootState()->errorState(); +} + +/*! + Sets the error state of this state machine's root state to be \a state. When a running state + machine encounters an error which puts it in an undefined state, it will enter an error state + based on the context of the error that occurred. It will enter this state regardless of what + is currently in the event queue. + + If the erroneous state has an error state set, this will be entered by the machine. If no error + state has been set, the state machine will search the parent hierarchy recursively for an + error state. The error state of the root state can thus be seen as a global error state that + applies for the states for which a more specific error state has not been set. + + Before entering the error state, the state machine will set the error code returned by error() and + error message returned by errorString(). + + The default error state will print a warning to the console containing the information returned by + errorString(). By setting a new error state on either the state machine itself, or on specific + states, you can fine tune error handling in the state machine. + + If the root state's error state is set to 0, or if the error state selected by the machine itself + contains an error, the default error state will be used. + + \sa QState::setErrorState(), rootState() +*/ +void QStateMachine::setErrorState(QAbstractState *state) +{ + rootState()->setErrorState(state); +} + +/*! \enum QStateMachine::Error + + This enum type defines errors that can occur in the state machine at run time. When the state + machine encounters an unrecoverable error at run time, it will set the error code returned + by error(), the error message returned by errorString(), and enter an error state based on + the context of the error. + + \value NoError No error has occurred. + \value NoInitialStateError The machine has entered a QState with children which does not have an + initial state set. The context of this error is the state which is missing an initial + state. + \value NoDefaultStateInHistoryStateError The machine has entered a QHistoryState which does not have + a default state set. The context of this error is the QHistoryState which is missing a + default state. + \value NoCommonAncestorForTransitionError The machine has selected a transition whose source + and targets are not part of the same tree of states, and thus are not part of the same + state machine. Commonly, this could mean that one of the states has not been given + any parent or added to any machine. The context of this error is the source state of + the transition. + + \sa setErrorState() +*/ + +/*! + \enum QStateMachine::RestorePolicy + + This enum specifies the restore policy type. The restore policy + takes effect when the machine enters a state which sets one or more + properties. If the restore policy is set to RestoreProperties, + the state machine will save the original value of the property before the + new value is set. + + Later, when the machine either enters a state which does not set + a value for the given property, the property will automatically be restored + to its initial value. + + Only one initial value will be saved for any given property. If a value for a property has + already been saved by the state machine, it will not be overwritten until the property has been + successfully restored. + + \value DoNotRestoreProperties The state machine should not save the initial values of properties + and restore them later. + \value RestoreProperties The state machine should save the initial values of properties + and restore them later. + + \sa QStateMachine::globalRestorePolicy QState::assignProperty() +*/ + + +/*! + Returns the error code of the last error that occurred in the state machine. +*/ +QStateMachine::Error QStateMachine::error() const +{ + Q_D(const QStateMachine); + return d->error; +} + +/*! + Returns the error string of the last error that occurred in the state machine. +*/ +QString QStateMachine::errorString() const +{ + Q_D(const QStateMachine); + return d->errorString; +} + +/*! + Clears the error string and error code of the state machine. +*/ +void QStateMachine::clearError() +{ + Q_D(QStateMachine); + d->errorString.clear(); + d->error = NoError; +} + +/*! + Returns the restore policy of the state machine. + + \sa setGlobalRestorePolicy() +*/ +QStateMachine::RestorePolicy QStateMachine::globalRestorePolicy() const +{ + Q_D(const QStateMachine); + return d->globalRestorePolicy; +} + +/*! + Sets the restore policy of the state machine to \a restorePolicy. The default + restore policy is QAbstractState::DoNotRestoreProperties. + + \sa globalRestorePolicy() +*/ +void QStateMachine::setGlobalRestorePolicy(QStateMachine::RestorePolicy restorePolicy) +{ + Q_D(QStateMachine); + d->globalRestorePolicy = restorePolicy; +} + +/*! + Returns this state machine's initial state, or 0 if no initial state has + been set. +*/ +QAbstractState *QStateMachine::initialState() const +{ + Q_D(const QStateMachine); + if (!d->rootState) + return 0; + return d->rootState->initialState(); +} + +/*! + Sets this state machine's initial \a state. +*/ +void QStateMachine::setInitialState(QAbstractState *state) +{ + Q_D(QStateMachine); + if (!d->rootState) { + if (!state) + return; + rootState()->setInitialState(state); + } + d->rootState->setInitialState(state); +} + +/*! + Adds the given \a state to this state machine. The state becomes a top-level + state (i.e. a child of the rootState()). + + If the state is already in a different machine, it will first be removed + from its old machine, and then added to this machine. + + \sa removeState(), rootState(), setInitialState() +*/ +void QStateMachine::addState(QAbstractState *state) +{ + if (!state) { + qWarning("QStateMachine::addState: cannot add null state"); + return; + } + if (QAbstractStatePrivate::get(state)->machine() == this) { + qWarning("QStateMachine::addState: state has already been added to this machine"); + return; + } + state->setParent(rootState()); +} + +/*! + Removes the given \a state from this state machine. The state machine + releases ownership of the state. + + \sa addState() +*/ +void QStateMachine::removeState(QAbstractState *state) +{ + if (!state) { + qWarning("QStateMachine::removeState: cannot remove null state"); + return; + } + if (QAbstractStatePrivate::get(state)->machine() != this) { + qWarning("QStateMachine::removeState: state %p's machine (%p)" + " is different from this machine (%p)", + state, QAbstractStatePrivate::get(state)->machine(), this); + return; + } + state->setParent(0); +} + +/*! + Returns whether this state machine is running. + + start(), stop() +*/ +bool QStateMachine::isRunning() const +{ + Q_D(const QStateMachine); + return (d->state == QStateMachinePrivate::Running); +} + +/*! + Starts this state machine. The machine will reset its configuration and + transition to the initial state. When a final top-level state (QFinalState) + is entered, the machine will emit the finished() signal. + + \sa started(), finished(), stop(), initialState() +*/ +void QStateMachine::start() +{ + Q_D(QStateMachine); + + if (rootState()->initialState() == 0) { + qWarning("QStateMachine::start: No initial state set for machine. Refusing to start."); + return; + } + + switch (d->state) { + case QStateMachinePrivate::NotRunning: + d->state = QStateMachinePrivate::Starting; + QMetaObject::invokeMethod(this, "_q_start", Qt::QueuedConnection); + break; + case QStateMachinePrivate::Starting: + break; + case QStateMachinePrivate::Running: + qWarning("QStateMachine::start(): already running"); + break; + } +} + +/*! + Stops this state machine. The state machine will stop processing events and + then emit the stopped() signal. + + \sa stopped(), start() +*/ +void QStateMachine::stop() +{ + Q_D(QStateMachine); + switch (d->state) { + case QStateMachinePrivate::NotRunning: + break; + case QStateMachinePrivate::Starting: + // the machine will exit as soon as it enters the event processing loop + d->stop = true; + break; + case QStateMachinePrivate::Running: + d->stop = true; + d->scheduleProcess(); + break; + } +} + +/*! + Posts the given \a event for processing by this state machine, with a delay + of \a delay milliseconds. + + This function returns immediately. The event is added to the state machine's + event queue. Events are processed in the order posted. The state machine + takes ownership of the event and deletes it once it has been processed. + + You can only post events when the state machine is running. +*/ +void QStateMachine::postEvent(QEvent *event, int delay) +{ + Q_D(QStateMachine); + if (d->state != QStateMachinePrivate::Running) { + qWarning("QStateMachine::postEvent: cannot post event when the state machine is not running"); + return; + } +#ifdef QSTATEMACHINE_DEBUG + qDebug() << this << ": posting external event" << event << "with delay" << delay; +#endif + if (delay) { + int tid = startTimer(delay); + d->delayedEvents[tid] = event; + } else { + d->externalEventQueue.append(event); + d->scheduleProcess(); + } +} + +/*! + \internal + + Posts the given internal \a event for processing by this state machine. +*/ +void QStateMachine::postInternalEvent(QEvent *event) +{ + Q_D(QStateMachine); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << this << ": posting internal event" << event; +#endif + d->internalEventQueue.append(event); + d->scheduleProcess(); +} + +/*! + \internal + + Returns the maximal consistent set of states (including parallel and final + states) that this state machine is currently in. If a state \c s is in the + configuration, it is always the case that the parent of \c s is also in + c. Note, however, that the rootState() is not an explicit member of the + configuration. +*/ +QSet<QAbstractState*> QStateMachine::configuration() const +{ + Q_D(const QStateMachine); + return d->configuration; +} + +/*! + \fn QStateMachine::started() + + This signal is emitted when the state machine has entered its initial state + (QStateMachine::initialState). + + \sa QStateMachine::finished(), QStateMachine::start() +*/ + +/*! + \fn QStateMachine::finished() + + This signal is emitted when the state machine has reached a top-level final + state (QFinalState). + + \sa QStateMachine::started() +*/ + +/*! + \fn QStateMachine::stopped() + + This signal is emitted when the state machine has stopped. + + \sa QStateMachine::stop(), QStateMachine::finished() +*/ + +/*! + \reimp +*/ +bool QStateMachine::event(QEvent *e) +{ + Q_D(QStateMachine); + if (e->type() == QEvent::Timer) { + QTimerEvent *te = static_cast<QTimerEvent*>(e); + int tid = te->timerId(); + if (d->delayedEvents.contains(tid)) { + killTimer(tid); + QEvent *ee = d->delayedEvents.take(tid); + d->externalEventQueue.append(ee); + d->scheduleProcess(); + return true; + } + } else if (e->type() == QEvent::ChildAdded) { + QChildEvent *ce = static_cast<QChildEvent*>(e); + if (QAbstractState *state = qobject_cast<QAbstractState*>(ce->child())) { + if (state != rootState()) { + state->setParent(rootState()); + return true; + } + } + } + return QObject::event(e); +} + +#ifndef QT_NO_STATEMACHINE_EVENTFILTER +/*! + \reimp +*/ +bool QStateMachine::eventFilter(QObject *watched, QEvent *event) +{ + Q_D(QStateMachine); + Q_ASSERT(d->qobjectEvents.contains(watched)); + if (d->qobjectEvents[watched].contains(event->type())) + postEvent(new QWrappedEvent(watched, d->handler->cloneEvent(event))); + return false; +} +#endif + +/*! + \internal + + This function is called when the state machine is about to select + transitions based on the given \a event. + + The default implementation does nothing. +*/ +void QStateMachine::beginSelectTransitions(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + \internal + + This function is called when the state machine has finished selecting + transitions based on the given \a event. + + The default implementation does nothing. +*/ +void QStateMachine::endSelectTransitions(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + \internal + + This function is called when the state machine is about to do a microstep. + + The default implementation does nothing. +*/ +void QStateMachine::beginMicrostep(QEvent *event) +{ + Q_UNUSED(event); +} + +/*! + \internal + + This function is called when the state machine has finished doing a + microstep. + + The default implementation does nothing. +*/ +void QStateMachine::endMicrostep(QEvent *event) +{ + Q_UNUSED(event); +} + +#ifndef QT_NO_ANIMATION + +/*! + Returns whether animations are enabled for this state machine. +*/ +bool QStateMachine::animationsEnabled() const +{ + Q_D(const QStateMachine); + return d->animationsEnabled; +} + +/*! + Sets whether animations are \a enabled for this state machine. +*/ +void QStateMachine::setAnimationsEnabled(bool enabled) +{ + Q_D(QStateMachine); + d->animationsEnabled = enabled; +} + +/*! + Adds a default \a animation to be considered for any transition. +*/ +void QStateMachine::addDefaultAnimation(QAbstractAnimation *animation) +{ + Q_D(QStateMachine); + d->defaultAnimations.append(animation); +} + +/*! + Returns the list of default animations that will be considered for any transition. +*/ +QList<QAbstractAnimation*> QStateMachine::defaultAnimations() const +{ + Q_D(const QStateMachine); + return d->defaultAnimations; +} + +/*! + Removes \a animation from the list of default animations. +*/ +void QStateMachine::removeDefaultAnimation(QAbstractAnimation *animation) +{ + Q_D(QStateMachine); + d->defaultAnimations.removeAll(animation); +} + +#endif // QT_NO_ANIMATION + + +static const uint qt_meta_data_QSignalEventGenerator[] = { + + // content: + 2, // revision + 0, // classname + 0, 0, // classinfo + 1, 12, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + + // slots: signature, parameters, type, tag, flags + 23, 22, 22, 22, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_QSignalEventGenerator[] = { + "QSignalEventGenerator\0\0execute()\0" +}; + +const QMetaObject QSignalEventGenerator::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_QSignalEventGenerator, + qt_meta_data_QSignalEventGenerator, 0 } +}; + +const QMetaObject *QSignalEventGenerator::metaObject() const +{ + return &staticMetaObject; +} + +void *QSignalEventGenerator::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_QSignalEventGenerator)) + return static_cast<void*>(const_cast< QSignalEventGenerator*>(this)); + return QObject::qt_metacast(_clname); +} + +int QSignalEventGenerator::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: { +// ### in Qt 4.6 we can use QObject::senderSignalIndex() + QObjectPrivate *d = static_cast<QObjectPrivate *>(d_ptr); + int signalIndex = -1; + QObject *sender = this->sender(); + if (sender && d->currentSender) + signalIndex = d->currentSender->signal; + + Q_ASSERT(signalIndex != -1); + QStateMachine *machine = qobject_cast<QStateMachine*>(parent()); + QStateMachinePrivate::get(machine)->handleTransitionSignal(sender, signalIndex, _a); + break; + } + default: ; + } + _id -= 1; + } + return _id; +} + +QSignalEventGenerator::QSignalEventGenerator(QStateMachine *parent) + : QObject(parent) +{ +} + +/*! + \class QSignalEvent + + \brief The QSignalEvent class represents a Qt signal event. + + \since 4.6 + \ingroup statemachine + + A signal event is generated by a QStateMachine in response to a Qt + signal. The QSignalTransition class provides a transition associated with a + signal event. QSignalEvent is part of \l{The State Machine Framework}. + + The sender() function returns the object that generated the signal. The + signalIndex() function returns the index of the signal. The arguments() + function returns the arguments of the signal. + + \sa QSignalTransition +*/ + +/*! + \internal + + Constructs a new QSignalEvent object with the given \a sender, \a + signalIndex and \a arguments. +*/ +QSignalEvent::QSignalEvent(const QObject *sender, int signalIndex, + const QList<QVariant> &arguments) + : QEvent(QEvent::Signal), m_sender(sender), + m_signalIndex(signalIndex), m_arguments(arguments) +{ +} + +/*! + Destroys this QSignalEvent. +*/ +QSignalEvent::~QSignalEvent() +{ +} + +/*! + \fn QSignalEvent::sender() const + + Returns the object that emitted the signal. + + \sa QObject::sender() +*/ + +/*! + \fn QSignalEvent::signalIndex() const + + Returns the index of the signal. + + \sa QMetaObject::indexOfSignal(), QMetaObject::method() +*/ + +/*! + \fn QSignalEvent::arguments() const + + Returns the arguments of the signal. +*/ + + +/*! + \class QWrappedEvent + + \brief The QWrappedEvent class holds a clone of an event associated with a QObject. + + \since 4.6 + \ingroup statemachine + + A wrapped event is generated by a QStateMachine in response to a Qt + event. The QEventTransition class provides a transition associated with a + such an event. QWrappedEvent is part of \l{The State Machine Framework}. + + The object() function returns the object that generated the event. The + event() function returns a clone of the original event. + + \sa QEventTransition +*/ + +/*! + \internal + + Constructs a new QWrappedEvent object with the given \a object + and \a event. +*/ +QWrappedEvent::QWrappedEvent(QObject *object, QEvent *event) + : QEvent(QEvent::Wrapped), m_object(object), m_event(event) +{ +} + +/*! + Destroys this QWrappedEvent. +*/ +QWrappedEvent::~QWrappedEvent() +{ +} + +/*! + \fn QWrappedEvent::object() const + + Returns the object that the event is associated with. +*/ + +/*! + \fn QWrappedEvent::event() const + + Returns a clone of the original event. +*/ + +QT_END_NAMESPACE + +#include "moc_qstatemachine.cpp" diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h new file mode 100644 index 0000000..2a98a9a --- /dev/null +++ b/src/corelib/statemachine/qstatemachine.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTATEMACHINE_H +#define QSTATEMACHINE_H + +#include <QtCore/qabstractstate.h> + +#include <QtCore/qlist.h> +#include <QtCore/qobject.h> +#include <QtCore/qset.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QEvent; +class QAbstractState; +class QState; + +class QStateMachinePrivate; +class QAbstractAnimation; +class QAbstractState; +class Q_CORE_EXPORT QStateMachine : public QObject +{ + Q_OBJECT + Q_PROPERTY(QState* rootState READ rootState) + Q_PROPERTY(QAbstractState* initialState READ initialState WRITE setInitialState) + Q_PROPERTY(QAbstractState* errorState READ errorState WRITE setErrorState) + Q_PROPERTY(QString errorString READ errorString) + Q_PROPERTY(RestorePolicy globalRestorePolicy READ globalRestorePolicy WRITE setGlobalRestorePolicy) + Q_ENUMS(RestorePolicy) +#ifndef QT_NO_ANIMATION + Q_PROPERTY(bool animationsEnabled READ animationsEnabled WRITE setAnimationsEnabled) +#endif +public: + enum RestorePolicy { + DoNotRestoreProperties, + RestoreProperties + }; + + enum Error { + NoError, + NoInitialStateError, + NoDefaultStateInHistoryStateError, + NoCommonAncestorForTransitionError + }; + + QStateMachine(QObject *parent = 0); + ~QStateMachine(); + + void addState(QAbstractState *state); + void removeState(QAbstractState *state); + + QState *rootState() const; + + QAbstractState *initialState() const; + void setInitialState(QAbstractState *state); + + QAbstractState *errorState() const; + void setErrorState(QAbstractState *state); + + Error error() const; + QString errorString() const; + void clearError(); + + bool isRunning() const; + +#ifndef QT_NO_ANIMATION + bool animationsEnabled() const; + void setAnimationsEnabled(bool enabled); + + void addDefaultAnimation(QAbstractAnimation *animation); + QList<QAbstractAnimation *> defaultAnimations() const; + void removeDefaultAnimation(QAbstractAnimation *animation); +#endif // QT_NO_ANIMATION + + QStateMachine::RestorePolicy globalRestorePolicy() const; + void setGlobalRestorePolicy(QStateMachine::RestorePolicy restorePolicy); + + void postEvent(QEvent *event, int delay = 0); + + QSet<QAbstractState*> configuration() const; + +#ifndef QT_NO_STATEMACHINE_EVENTFILTER + bool eventFilter(QObject *watched, QEvent *event); +#endif + +public Q_SLOTS: + void start(); + void stop(); + +Q_SIGNALS: + void started(); + void stopped(); + void finished(); + +protected: + void postInternalEvent(QEvent *event); + + virtual void beginSelectTransitions(QEvent *event); + virtual void endSelectTransitions(QEvent *event); + + virtual void beginMicrostep(QEvent *event); + virtual void endMicrostep(QEvent *event); + + bool event(QEvent *e); + +protected: + QStateMachine(QStateMachinePrivate &dd, QObject *parent); + +private: + Q_DISABLE_COPY(QStateMachine) + Q_DECLARE_PRIVATE(QStateMachine) + Q_PRIVATE_SLOT(d_func(), void _q_start()) + Q_PRIVATE_SLOT(d_func(), void _q_process()) +#ifndef QT_NO_ANIMATION + Q_PRIVATE_SLOT(d_func(), void _q_animationFinished()) +#endif +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h new file mode 100644 index 0000000..54953b4 --- /dev/null +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTATEMACHINE_P_H +#define QSTATEMACHINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qobject_p.h> +#include <QtCore/qcoreevent.h> +#include <QtCore/qhash.h> +#include <QtCore/qlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qset.h> +#include <QtCore/qvector.h> + +#include "qstate.h" +#include "qstate_p.h" + +QT_BEGIN_NAMESPACE + +class QEvent; +#ifndef QT_NO_STATEMACHINE_EVENTFILTER +class QEventTransition; +#endif +class QSignalEventGenerator; +class QSignalTransition; +class QAbstractState; +class QAbstractTransition; +class QState; + +#ifndef QT_NO_ANIMATION +class QAbstractAnimation; +#endif + +class QStateMachine; +class QStateMachinePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QStateMachine) +public: + enum State { + NotRunning, + Starting, + Running + }; + enum StopProcessingReason { + EventQueueEmpty, + Finished, + Stopped + }; + + QStateMachinePrivate(); + ~QStateMachinePrivate(); + + static QStateMachinePrivate *get(QStateMachine *q); + + static QState *findLCA(const QList<QAbstractState*> &states); + + static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2); + static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2); + + QAbstractState *findErrorState(QAbstractState *context); + void setError(QStateMachine::Error error, QAbstractState *currentContext); + + // private slots + void _q_start(); + void _q_process(); +#ifndef QT_NO_ANIMATION + void _q_animationFinished(); +#endif + + void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList); + bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const; + QSet<QAbstractTransition*> selectTransitions(QEvent *event) const; + QList<QAbstractState*> exitStates(QEvent *event, const QList<QAbstractTransition*> &transitionList); + void executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &transitionList); + QList<QAbstractState*> enterStates(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions); + void addStatesToEnter(QAbstractState *s, QState *root, + QSet<QAbstractState*> &statesToEnter, + QSet<QAbstractState*> &statesForDefaultEntry); + + void applyProperties(const QList<QAbstractTransition*> &transitionList, + const QList<QAbstractState*> &exitedStates, + const QList<QAbstractState*> &enteredStates); + + bool isInFinalState(QAbstractState *s) const; + static bool isFinal(const QAbstractState *s); + static bool isParallel(const QAbstractState *s); + static bool isCompound(const QAbstractState *s); + static bool isAtomic(const QAbstractState *s); + static bool isDescendantOf(const QAbstractState *s, const QAbstractState *other); + static QList<QState*> properAncestors(const QAbstractState *s, const QState *upperBound); + + void registerTransitions(QAbstractState *state); + void registerSignalTransition(QSignalTransition *transition); + void unregisterSignalTransition(QSignalTransition *transition); +#ifndef QT_NO_STATEMACHINE_EVENTFILTER + void registerEventTransition(QEventTransition *transition); + void unregisterEventTransition(QEventTransition *transition); +#endif + void unregisterTransition(QAbstractTransition *transition); + void unregisterAllTransitions(); + void handleTransitionSignal(const QObject *sender, int signalIndex, + void **args); + void scheduleProcess(); + + typedef QPair<QObject *, QByteArray> RestorableId; + QHash<RestorableId, QVariant> registeredRestorables; + void registerRestorable(QObject *object, const QByteArray &propertyName); + void unregisterRestorable(QObject *object, const QByteArray &propertyName); + bool hasRestorable(QObject *object, const QByteArray &propertyName) const; + QVariant restorableValue(QObject *object, const QByteArray &propertyName) const; + QList<QPropertyAssignment> restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const; + + State state; + bool processing; + bool processingScheduled; + bool stop; + StopProcessingReason stopProcessingReason; + QState *rootState; + QSet<QAbstractState*> configuration; + QList<QEvent*> internalEventQueue; + QList<QEvent*> externalEventQueue; + + QStateMachine::Error error; + QStateMachine::RestorePolicy globalRestorePolicy; + + QString errorString; + QSet<QAbstractState *> pendingErrorStates; + QSet<QAbstractState *> pendingErrorStatesForDefaultEntry; + QAbstractState *initialErrorStateForRoot; + +#ifndef QT_NO_ANIMATION + bool animationsEnabled; + + QPair<QList<QAbstractAnimation*>, QList<QAbstractAnimation*> > + initializeAnimation(QAbstractAnimation *abstractAnimation, + const QPropertyAssignment &prop); + + QHash<QAbstractState*, QList<QAbstractAnimation*> > animationsForState; + QHash<QAbstractAnimation*, QPropertyAssignment> propertyForAnimation; + QHash<QAbstractAnimation*, QAbstractState*> stateForAnimation; + QSet<QAbstractAnimation*> resetAnimationEndValues; + + QList<QAbstractAnimation *> defaultAnimations; + QMultiHash<QAbstractState *, QAbstractAnimation *> defaultAnimationsForSource; + QMultiHash<QAbstractState *, QAbstractAnimation *> defaultAnimationsForTarget; + +#endif // QT_NO_ANIMATION + + QSignalEventGenerator *signalEventGenerator; + + QHash<const QObject*, QVector<int> > connections; +#ifndef QT_NO_STATEMACHINE_EVENTFILTER + QHash<QObject*, QHash<QEvent::Type, int> > qobjectEvents; +#endif + QHash<int, QEvent*> delayedEvents; + + typedef QEvent* (*f_cloneEvent)(QEvent*); + struct Handler { + f_cloneEvent cloneEvent; + }; + + static Q_CORE_EXPORT const Handler *handler; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/statemachine/qwrappedevent.h b/src/corelib/statemachine/qwrappedevent.h new file mode 100644 index 0000000..b01c608 --- /dev/null +++ b/src/corelib/statemachine/qwrappedevent.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWRAPPEDEVENT_H +#define QWRAPPEDEVENT_H + +#include <QtCore/qcoreevent.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QObject; + +class Q_CORE_EXPORT QWrappedEvent : public QEvent +{ +public: + QWrappedEvent(QObject *object, QEvent *event); + ~QWrappedEvent(); + + inline QObject *object() const { return m_object; } + inline QEvent *event() const { return m_event; } + +private: + QObject *m_object; + QEvent *m_event; + +private: + Q_DISABLE_COPY(QWrappedEvent) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/statemachine/statemachine.pri b/src/corelib/statemachine/statemachine.pri new file mode 100644 index 0000000..5b19bc1 --- /dev/null +++ b/src/corelib/statemachine/statemachine.pri @@ -0,0 +1,30 @@ +HEADERS += $$PWD/qstatemachine.h \ + $$PWD/qstatemachine_p.h \ + $$PWD/qsignaleventgenerator_p.h \ + $$PWD/qabstractstate.h \ + $$PWD/qabstractstate_p.h \ + $$PWD/qstate.h \ + $$PWD/qstate_p.h \ + $$PWD/qfinalstate.h \ + $$PWD/qhistorystate.h \ + $$PWD/qhistorystate_p.h \ + $$PWD/qabstracttransition.h \ + $$PWD/qabstracttransition_p.h \ + $$PWD/qsignalevent.h \ + $$PWD/qsignaltransition.h \ + $$PWD/qsignaltransition_p.h + +SOURCES += $$PWD/qstatemachine.cpp \ + $$PWD/qabstractstate.cpp \ + $$PWD/qstate.cpp \ + $$PWD/qfinalstate.cpp \ + $$PWD/qhistorystate.cpp \ + $$PWD/qabstracttransition.cpp \ + $$PWD/qsignaltransition.cpp + +!contains(DEFINES, QT_NO_STATEMACHINE_EVENTFILTER) { +HEADERS += $$PWD/qwrappedevent.h \ + $$PWD/qeventtransition.h \ + $$PWD/qeventtransition_p.h +SOURCES += $$PWD/qeventtransition.cpp +} diff --git a/src/corelib/thread/qmutexpool.cpp b/src/corelib/thread/qmutexpool.cpp index 96a9940..0d7c890 100644 --- a/src/corelib/thread/qmutexpool.cpp +++ b/src/corelib/thread/qmutexpool.cpp @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE // qt_global_mutexpool is here for backwards compatability only, // use QMutexpool::instance() in new clode. Q_CORE_EXPORT QMutexPool *qt_global_mutexpool = 0; -Q_GLOBAL_STATIC_WITH_ARGS(QMutexPool, globalMutexPool, (true)) +Q_GLOBAL_STATIC_WITH_ARGS(QMutexPool, globalMutexPool, (QMutex::Recursive)) /*! \class QMutexPool @@ -88,17 +88,17 @@ Q_GLOBAL_STATIC_WITH_ARGS(QMutexPool, globalMutexPool, (true)) */ /*! - Constructs a QMutexPool, reserving space for \a size QMutexes. If - \a recursive is true, all QMutexes in the pool will be recursive - mutexes; otherwise they will all be non-recursive (the default). + Constructs a QMutexPool, reserving space for \a size QMutexes. All + mutexes in the pool are created with \a recursionMode. By default, + all mutexes are non-recursive. The QMutexes are created when needed, and deleted when the QMutexPool is destructed. */ -QMutexPool::QMutexPool(bool recursive, int size) - : mutexes(size), count(size), recurs(recursive) +QMutexPool::QMutexPool(QMutex::RecursionMode recursionMode, int size) + : mutexes(size), recursionMode(recursionMode) { - for (int index = 0; index < count; ++index) { + for (int index = 0; index < mutexes.count(); ++index) { mutexes[index] = 0; } } @@ -109,7 +109,7 @@ QMutexPool::QMutexPool(bool recursive, int size) */ QMutexPool::~QMutexPool() { - for (int index = 0; index < count; ++index) { + for (int index = 0; index < mutexes.count(); ++index) { delete mutexes[index]; mutexes[index] = 0; } @@ -130,11 +130,11 @@ QMutexPool *QMutexPool::instance() QMutex *QMutexPool::get(const void *address) { Q_ASSERT_X(address != 0, "QMutexPool::get()", "'address' argument cannot be zero"); - int index = int((quintptr(address) >> (sizeof(address) >> 1)) % count); + int index = int((quintptr(address) >> (sizeof(address) >> 1)) % mutexes.count()); if (!mutexes[index]) { // mutex not created, create one - QMutex *newMutex = new QMutex(recurs ? QMutex::Recursive : QMutex::NonRecursive); + QMutex *newMutex = new QMutex(recursionMode); if (!mutexes[index].testAndSetOrdered(0, newMutex)) delete newMutex; } diff --git a/src/corelib/thread/qmutexpool_p.h b/src/corelib/thread/qmutexpool_p.h index 1009ebb..30a16d4 100644 --- a/src/corelib/thread/qmutexpool_p.h +++ b/src/corelib/thread/qmutexpool_p.h @@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE class Q_CORE_EXPORT QMutexPool { public: - explicit QMutexPool(bool recursive = false, int size = 128); + explicit QMutexPool(QMutex::RecursionMode recursionMode = QMutex::NonRecursive, int size = 131); ~QMutexPool(); QMutex *get(const void *address); @@ -72,9 +72,8 @@ public: static QMutex *globalInstanceGet(const void *address); private: - QVarLengthArray<QAtomicPointer<QMutex>, 128> mutexes; - int count; - bool recurs; + QVarLengthArray<QAtomicPointer<QMutex>, 131> mutexes; + QMutex::RecursionMode recursionMode; }; extern Q_CORE_EXPORT QMutexPool *qt_global_mutexpool; diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 6aa35f3..49dd52d 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -579,7 +579,7 @@ static inline char qToLower(char c) return c; } -Q_CORE_EXPORT QByteArray::Data QByteArray::shared_null = {Q_BASIC_ATOMIC_INITIALIZER(1), +QByteArray::Data QByteArray::shared_null = {Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, shared_null.array, {0} }; QByteArray::Data QByteArray::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, shared_empty.array, {0} }; diff --git a/src/corelib/tools/qbytearraymatcher.h b/src/corelib/tools/qbytearraymatcher.h index 633e92c..970cbcc 100644 --- a/src/corelib/tools/qbytearraymatcher.h +++ b/src/corelib/tools/qbytearraymatcher.h @@ -70,7 +70,7 @@ public: inline QByteArray pattern() const { if (q_pattern.isNull()) - return QByteArray((const char*)p.p, p.l); + return QByteArray(reinterpret_cast<const char*>(p.p), p.l); return q_pattern; } diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp new file mode 100644 index 0000000..996ac18 --- /dev/null +++ b/src/corelib/tools/qcontiguouscache.cpp @@ -0,0 +1,439 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcontiguouscache.h" +#ifdef QT_QCONTIGUOUSCACHE_DEBUG +#include <QDebug> +#endif + +QT_BEGIN_NAMESPACE + +#ifdef QT_QCONTIGUOUSCACHE_DEBUG +void QContiguousCacheData::dump() const +{ + qDebug() << "capacity:" << alloc; + qDebug() << "count:" << count; + qDebug() << "start:" << start; + qDebug() << "offset:" << offset; +} +#endif + +/*! \class QContiguousCache + \brief The QContiguousCache class is a template class that provides a contiguous cache. + \ingroup tools + \ingroup shared + \reentrant + + The QContiguousCache class provides an efficient way of caching items for + display in a user interface view. Unlike QCache, it adds a restriction + that elements within the cache are contiguous. This has the advantage + of matching how user interface views most commonly request data, as + a set of rows localized around the current scrolled position. This + restriction allows the cache to consume less memory and processor + cycles than QCache. The QContiguousCache class also can provide + an upper bound on memory usage via setCapacity(). + + The simplest way of using a contiguous cache is to use the append() + and prepend(). + +\code +MyRecord record(int row) const +{ + Q_ASSERT(row >= 0 && row < count()); + + while(row > cache.lastIndex()) + cache.append(slowFetchRecord(cache.lastIndex()+1)); + while(row < cache.firstIndex()) + cache.prepend(slowFetchRecord(cache.firstIndex()-1)); + + return cache.at(row); +} +\endcode + + If the cache is full then the item at the opposite end of the cache from + where the new item is appended or prepended will be removed. + + This usage can be further optimized by using the insert() function + in the case where the requested row is a long way from the currently cached + items. If there is a gap between where the new item is inserted and the currently + cached items then the existing cached items are first removed to retain + the contiguous nature of the cache. Hence it is important to take some care then + when using insert() in order to avoid unwanted clearing of the cache. + + The range of valid indexes for the QContiguousCache class are from + 0 to INT_MAX. Calling prepend() such that the first index would become less + than 0 or append() such that the last index would become greater + than INT_MAX can result in the indexes of the cache being invalid. + When the cache indexes are invalid it is important to call + normalizeIndexes() before calling any of containsIndex(), firstIndex(), + lastIndex(), at() or the [] operator. Calling these + functions when the cache has invalid indexes will result in undefined + behavior. The indexes can be checked by using areIndexesValid() + + In most cases the indexes will not exceed 0 to INT_MAX, and + normalizeIndexes() will not need to be used. + + See the \l{Contiguous Cache Example}{Contiguous Cache} example. +*/ + +/*! \fn QContiguousCache::QContiguousCache(int capacity) + + Constructs a cache with the given \a capacity. + + \sa setCapacity() +*/ + +/*! \fn QContiguousCache::QContiguousCache(const QContiguousCache<T> &other) + + Constructs a copy of \a other. + + This operation takes \l{constant time}, because QContiguousCache is + \l{implicitly shared}. This makes returning a QContiguousCache from a + function very fast. If a shared instance is modified, it will be + copied (copy-on-write), and that takes \l{linear time}. + + \sa operator=() +*/ + +/*! \fn QContiguousCache::~QContiguousCache() + + Destroys the cache. +*/ + +/*! \fn void QContiguousCache::detach() + + \internal +*/ + +/*! \fn bool QContiguousCache::isDetached() const + + \internal +*/ + +/*! \fn void QContiguousCache::setSharable(bool sharable) + + \internal +*/ + +/*! \fn QContiguousCache<T> &QContiguousCache::operator=(const QContiguousCache<T> &other) + + Assigns \a other to this cache and returns a reference to this cache. +*/ + +/*! \fn bool QContiguousCache::operator==(const QContiguousCache<T> &other) const + + Returns true if \a other is equal to this cache; otherwise returns false. + + Two caches are considered equal if they contain the same values at the same + indexes. This function requires the value type to implement the \c operator==(). + + \sa operator!=() +*/ + +/*! \fn bool QContiguousCache::operator!=(const QContiguousCache<T> &other) const + + Returns true if \a other is not equal to this cache; otherwise + returns false. + + Two caches are considered equal if they contain the same values at the same + indexes. This function requires the value type to implement the \c operator==(). + + \sa operator==() +*/ + +/*! \fn int QContiguousCache::capacity() const + + Returns the number of items the cache can store before it is full. + When a cache contains a number of items equal to its capacity, adding new + items will cause items farthest from the added item to be removed. + + \sa setCapacity(), size() +*/ + +/*! \fn int QContiguousCache::count() const + + \overload + + Same as size(). +*/ + +/*! \fn int QContiguousCache::size() const + + Returns the number of items contained within the cache. + + \sa capacity() +*/ + +/*! \fn bool QContiguousCache::isEmpty() const + + Returns true if no items are stored within the cache. + + \sa size(), capacity() +*/ + +/*! \fn bool QContiguousCache::isFull() const + + Returns true if the number of items stored within the cache is equal + to the capacity of the cache. + + \sa size(), capacity() +*/ + +/*! \fn int QContiguousCache::available() const + + Returns the number of items that can be added to the cache before it becomes full. + + \sa size(), capacity(), isFull() +*/ + +/*! \fn void QContiguousCache::clear() + + Removes all items from the cache. The capacity is unchanged. +*/ + +/*! \fn void QContiguousCache::setCapacity(int size) + + Sets the capacity of the cache to the given \a size. A cache can hold a + number of items equal to its capacity. When inserting, appending or prepending + items to the cache, if the cache is already full then the item farthest from + the added item will be removed. + + If the given \a size is smaller than the current count of items in the cache + then only the last \a size items from the cache will remain. + + \sa capacity(), isFull() +*/ + +/*! \fn const T &QContiguousCache::at(int i) const + + Returns the item at index position \a i in the cache. \a i must + be a valid index position in the cache (i.e, firstIndex() <= \a i <= lastIndex()). + + The indexes in the cache refer to the number of positions the item is from the + first item appended into the cache. That is to say a cache with a capacity of + 100, that has had 150 items appended will have a valid index range of + 50 to 149. This allows inserting and retrieving items into the cache based + on a theoretical infinite list + + \sa firstIndex(), lastIndex(), insert(), operator[]() +*/ + +/*! \fn T &QContiguousCache::operator[](int i) + + Returns the item at index position \a i as a modifiable reference. If + the cache does not contain an item at the given index position \a i + then it will first insert an empty item at that position. + + In most cases it is better to use either at() or insert(). + + Note that using non-const operators can cause QContiguousCache to do a deep + copy. + + \sa insert(), at() +*/ + +/*! \fn const T &QContiguousCache::operator[](int i) const + + \overload + + Same as at(\a i). +*/ + +/*! \fn void QContiguousCache::append(const T &value) + + Inserts \a value at the end of the cache. If the cache is already full + the item at the start of the cache will be removed. + + \sa prepend(), insert(), isFull() +*/ + +/*! \fn void QContiguousCache::prepend(const T &value) + + Inserts \a value at the start of the cache. If the cache is already full + the item at the end of the cache will be removed. + + \sa append(), insert(), isFull() +*/ + +/*! \fn void QContiguousCache::insert(int i, const T &value) + + Inserts the \a value at the index position \a i. If the cache already contains + an item at \a i then that value is replaced. If \a i is either one more than + lastIndex() or one less than firstIndex() it is the equivalent to an append() + or a prepend(). + + If the given index \a i is not within the current range of the cache nor adjacent + to the bounds of the cache's index range, the cache is first cleared before + inserting the item. At this point the cache will have a size of 1. It is + worthwhile taking effort to insert items in an order that starts adjacent + to the current index range for the cache. + + The range of valid indexes for the QContiguousCache class are from + 0 to INT_MAX. Inserting outside of this range has undefined behavior. + + + \sa prepend(), append(), isFull(), firstIndex(), lastIndex() +*/ + +/*! \fn bool QContiguousCache::containsIndex(int i) const + + Returns true if the cache's index range includes the given index \a i. + + \sa firstIndex(), lastIndex() +*/ + +/*! \fn int QContiguousCache::firstIndex() const + + Returns the first valid index in the cache. The index will be invalid if the + cache is empty. + + \sa capacity(), size(), lastIndex() +*/ + +/*! \fn int QContiguousCache::lastIndex() const + + Returns the last valid index in the cache. The index will be invalid if the cache is empty. + + \sa capacity(), size(), firstIndex() +*/ + + +/*! \fn T &QContiguousCache::first() + + Returns a reference to the first item in the cache. This function + assumes that the cache isn't empty. + + \sa last(), isEmpty() +*/ + +/*! \fn T &QContiguousCache::last() + + Returns a reference to the last item in the cache. This function + assumes that the cache isn't empty. + + \sa first(), isEmpty() +*/ + +/*! \fn const T& QContiguousCache::first() const + + \overload +*/ + +/*! \fn const T& QContiguousCache::last() const + + \overload +*/ + +/*! \fn void QContiguousCache::removeFirst() + + Removes the first item from the cache. This function assumes that + the cache isn't empty. + + \sa removeLast() +*/ + +/*! \fn void QContiguousCache::removeLast() + + Removes the last item from the cache. This function assumes that + the cache isn't empty. + + \sa removeFirst() +*/ + +/*! \fn T QContiguousCache::takeFirst() + + Removes the first item in the cache and returns it. This function + assumes that the cache isn't empty. + + If you don't use the return value, removeFirst() is more efficient. + + \sa takeLast(), removeFirst() +*/ + +/*! \fn T QContiguousCache::takeLast() + + Removes the last item in the cache and returns it. This function + assumes that the cache isn't empty. + + If you don't use the return value, removeLast() is more efficient. + + \sa takeFirst(), removeLast() +*/ + +/*! \fn void QContiguousCache::normalizeIndexes() + + Moves the first index and last index of the cache + such that they point to valid indexes. The function does not modify + the contents of the cache or the ordering of elements within the cache. + + It is provided so that index overflows can be corrected when using the + cache as a circular buffer. + + \code + QContiguousCache<int> cache(10); + cache.insert(INT_MAX, 1); // cache contains one value and has valid indexes, INT_MAX to INT_MAX + cache.append(2); // cache contains two values but does not have valid indexes. + cache.normalizeIndexes(); // cache has two values, 1 and 2. New first index will be in the range of 0 to capacity(). + \endcode + + \sa areIndexesValid(), append(), prepend() +*/ + +/*! \fn bool QContiguousCache::areIndexesValid() const + + Returns whether the indexes for items stored in the cache are valid. + Indexes can become invalid if items are appended after the index position + INT_MAX or prepended before the index position 0. This is only expected + to occur in very long lived circular buffer style usage of the + contiguous cache. Indexes can be made valid again by calling + normalizeIndexs(). + + \sa normalizeIndexes(), append(), prepend() +*/ + +/*! \fn void QContiguousCache::dump() const + + \internal + + Sends information about the cache's internal structure to qDebug() +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h new file mode 100644 index 0000000..2437f63 --- /dev/null +++ b/src/corelib/tools/qcontiguouscache.h @@ -0,0 +1,430 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCONTIGUOUSCACHE_H +#define QCONTIGUOUSCACHE_H + +#include <QtCore/qatomic.h> +#include <limits.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#undef QT_QCONTIGUOUSCACHE_DEBUG +QT_MODULE(Core) + + +struct Q_CORE_EXPORT QContiguousCacheData +{ + QBasicAtomicInt ref; + int alloc; + int count; + int start; + int offset; + uint sharable : 1; + +#ifdef QT_QCONTIGUOUSCACHE_DEBUG + void dump() const; +#endif +}; + +template <typename T> +struct QContiguousCacheTypedData +{ + QBasicAtomicInt ref; + int alloc; + int count; + int start; + int offset; + uint sharable : 1; + + T array[1]; +}; + +template<typename T> +class QContiguousCache { + typedef QContiguousCacheTypedData<T> Data; + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; }; +public: + explicit QContiguousCache(int capacity = 0); + QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); } + + inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) free(d); } + + inline void detach() { if (d->ref != 1) detach_helper(); } + inline bool isDetached() const { return d->ref == 1; } + inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; } + + QContiguousCache<T> &operator=(const QContiguousCache<T> &other); + bool operator==(const QContiguousCache<T> &other) const; + inline bool operator!=(const QContiguousCache<T> &other) const { return !(*this == other); } + + inline int capacity() const {return d->alloc; } + inline int count() const { return d->count; } + inline int size() const { return d->count; } + + inline bool isEmpty() const { return d->count == 0; } + inline bool isFull() const { return d->count == d->alloc; } + inline int available() const { return d->alloc - d->count; } + + void clear(); + void setCapacity(int size); + + const T &at(int pos) const; + T &operator[](int i); + const T &operator[](int i) const; + + void append(const T &value); + void prepend(const T &value); + void insert(int pos, const T &value); + + inline bool containsIndex(int pos) const { return pos >= d->offset && pos - d->offset < d->count; } + inline int firstIndex() const { return d->offset; } + inline int lastIndex() const { return d->offset + d->count - 1; } + + inline const T &first() const { Q_ASSERT(!isEmpty()); return d->array[d->start]; } + inline const T &last() const { Q_ASSERT(!isEmpty()); return d->array[(d->start + d->count -1) % d->alloc]; } + inline T &first() { Q_ASSERT(!isEmpty()); detach(); return d->array[d->start]; } + inline T &last() { Q_ASSERT(!isEmpty()); detach(); return d->array[(d->start + d->count -1) % d->alloc]; } + + void removeFirst(); + T takeFirst(); + void removeLast(); + T takeLast(); + + inline bool areIndexesValid() const + { return d->offset >= 0 && d->offset < INT_MAX - d->count && (d->offset % d->alloc) == d->start; } + + inline void normalizeIndexes() { d->offset = d->start; } + +#ifdef QT_QCONTIGUOUSCACHE_DEBUG + void dump() const { p->dump(); } +#endif +private: + void detach_helper(); + + QContiguousCacheData *malloc(int aalloc); + void free(Data *x); + int sizeOfTypedData() { + // this is more or less the same as sizeof(Data), except that it doesn't + // count the padding at the end + return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this); + } +}; + +template <typename T> +void QContiguousCache<T>::detach_helper() +{ + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; + + x.p = malloc(d->alloc); + x.d->ref = 1; + x.d->count = d->count; + x.d->start = d->start; + x.d->offset = d->offset; + x.d->alloc = d->alloc; + x.d->sharable = true; + + T *dest = x.d->array + x.d->start; + T *src = d->array + d->start; + int count = x.d->count; + while (count--) { + if (QTypeInfo<T>::isComplex) { + new (dest) T(*src); + } else { + *dest = *src; + } + dest++; + if (dest == x.d->array + x.d->alloc) + dest = x.d->array; + src++; + if (src == d->array + d->alloc) + src = d->array; + } + + if (!d->ref.deref()) + free(d); + d = x.d; +} + +template <typename T> +void QContiguousCache<T>::setCapacity(int asize) +{ + if (asize == d->alloc) + return; + detach(); + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; + x.p = malloc(asize); + x.d->alloc = asize; + x.d->count = qMin(d->count, asize); + x.d->offset = d->offset + d->count - x.d->count; + x.d->start = x.d->offset % x.d->alloc; + T *dest = x.d->array + (x.d->start + x.d->count-1) % x.d->alloc; + T *src = d->array + (d->start + d->count-1) % d->alloc; + int count = x.d->count; + while (count--) { + if (QTypeInfo<T>::isComplex) { + new (dest) T(*src); + } else { + *dest = *src; + } + if (dest == x.d->array) + dest = x.d->array + x.d->alloc; + dest--; + if (src == d->array) + src = d->array + d->alloc; + src--; + } + /* free old */ + free(d); + d = x.d; +} + +template <typename T> +void QContiguousCache<T>::clear() +{ + if (d->ref == 1) { + if (QTypeInfo<T>::isComplex) { + int count = d->count; + T * i = d->array + d->start; + T * e = d->array + d->alloc; + while (count--) { + i->~T(); + i++; + if (i == e) + i = d->array; + } + } + d->count = d->start = d->offset = 0; + } else { + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; + x.p = malloc(d->alloc); + x.d->ref = 1; + x.d->alloc = d->alloc; + x.d->count = x.d->start = x.d->offset = 0; + x.d->sharable = true; + if (!d->ref.deref()) free(d); + d = x.d; + } +} + +template <typename T> +inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc) +{ + return static_cast<QContiguousCacheData *>(qMalloc(sizeOfTypedData() + (aalloc - 1) * sizeof(T))); +} + +template <typename T> +QContiguousCache<T>::QContiguousCache(int capacity) +{ + p = malloc(capacity); + d->ref = 1; + d->alloc = capacity; + d->count = d->start = d->offset = 0; + d->sharable = true; +} + +template <typename T> +QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &other) +{ + other.d->ref.ref(); + if (!d->ref.deref()) + free(d); + d = other.d; + if (!d->sharable) + detach_helper(); + return *this; +} + +template <typename T> +bool QContiguousCache<T>::operator==(const QContiguousCache<T> &other) const +{ + if (other.d == d) + return true; + if (other.d->start != d->start + || other.d->count != d->count + || other.d->offset != d->offset + || other.d->alloc != d->alloc) + return false; + for (int i = firstIndex(); i <= lastIndex(); ++i) + if (!(at(i) == other.at(i))) + return false; + return true; +} + +template <typename T> +void QContiguousCache<T>::free(Data *x) +{ + if (QTypeInfo<T>::isComplex) { + int count = d->count; + T * i = d->array + d->start; + T * e = d->array + d->alloc; + while (count--) { + i->~T(); + i++; + if (i == e) + i = d->array; + } + } + qFree(x); +} +template <typename T> +void QContiguousCache<T>::append(const T &value) +{ + detach(); + if (QTypeInfo<T>::isComplex) { + if (d->count == d->alloc) + (d->array + (d->start+d->count) % d->alloc)->~T(); + new (d->array + (d->start+d->count) % d->alloc) T(value); + } else { + d->array[(d->start+d->count) % d->alloc] = value; + } + + if (d->count == d->alloc) { + d->start++; + d->start %= d->alloc; + d->offset++; + } else { + d->count++; + } +} + +template<typename T> +void QContiguousCache<T>::prepend(const T &value) +{ + detach(); + if (d->start) + d->start--; + else + d->start = d->alloc-1; + d->offset--; + + if (d->count != d->alloc) + d->count++; + else + if (d->count == d->alloc) + (d->array + d->start)->~T(); + + if (QTypeInfo<T>::isComplex) + new (d->array + d->start) T(value); + else + d->array[d->start] = value; +} + +template<typename T> +void QContiguousCache<T>::insert(int pos, const T &value) +{ + Q_ASSERT_X(pos >= 0 && pos < INT_MAX, "QContiguousCache<T>::insert", "index out of range"); + detach(); + if (containsIndex(pos)) { + if(QTypeInfo<T>::isComplex) + new (d->array + pos % d->alloc) T(value); + else + d->array[pos % d->alloc] = value; + } else if (pos == d->offset-1) + prepend(value); + else if (pos == d->offset+d->count) + append(value); + else { + // we don't leave gaps. + clear(); + d->offset = pos; + d->start = pos % d->alloc; + d->count = 1; + if (QTypeInfo<T>::isComplex) + new (d->array + d->start) T(value); + else + d->array[d->start] = value; + } +} + +template <typename T> +inline const T &QContiguousCache<T>::at(int pos) const +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; } +template <typename T> +inline const T &QContiguousCache<T>::operator[](int pos) const +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; } + +template <typename T> +inline T &QContiguousCache<T>::operator[](int pos) +{ + detach(); + if (!containsIndex(pos)) + insert(pos, T()); + return d->array[pos % d->alloc]; +} + +template <typename T> +inline void QContiguousCache<T>::removeFirst() +{ + Q_ASSERT(d->count > 0); + detach(); + d->count--; + if (QTypeInfo<T>::isComplex) + (d->array + d->start)->~T(); + d->start = (d->start + 1) % d->alloc; + d->offset++; +} + +template <typename T> +inline void QContiguousCache<T>::removeLast() +{ + Q_ASSERT(d->count > 0); + detach(); + d->count--; + if (QTypeInfo<T>::isComplex) + (d->array + (d->start + d->count) % d->alloc)->~T(); +} + +template <typename T> +inline T QContiguousCache<T>::takeFirst() +{ T t = first(); removeFirst(); return t; } + +template <typename T> +inline T QContiguousCache<T>::takeLast() +{ T t = last(); removeLast(); return t; } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index 7232626..e438179 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -74,7 +74,7 @@ public: QCryptographicHash can be used to generate cryptographic hashes of binary or text data. - Currently MD4, MD5, and SHA1 are supported. + Currently MD4, MD5, and SHA-1 are supported. */ /*! diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 781514c..de41360 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -3833,19 +3833,19 @@ void QDateTimePrivate::getUTC(QDate &outDate, QTime &outTime) const #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_NO_DATESTRING) QDebug operator<<(QDebug dbg, const QDate &date) { - dbg.nospace() << "QDate(" << date.toString() << ")"; + dbg.nospace() << "QDate(" << date.toString() << ')'; return dbg.space(); } QDebug operator<<(QDebug dbg, const QTime &time) { - dbg.nospace() << "QTime(" << time.toString() << ")"; + dbg.nospace() << "QTime(" << time.toString() << ')'; return dbg.space(); } QDebug operator<<(QDebug dbg, const QDateTime &date) { - dbg.nospace() << "QDateTime(" << date.toString() << ")"; + dbg.nospace() << "QDateTime(" << date.toString() << ')'; return dbg.space(); } #endif @@ -4688,7 +4688,7 @@ QDateTimeParser::StateNode QDateTimeParser::parse(QString &input, int &cursorPos if (fixup && tmpstate == Intermediate && used < sn.count) { const FieldInfo fi = fieldInfo(index); if ((fi & (Numeric|FixedWidth)) == (Numeric|FixedWidth)) { - const QString newText = QString(QLatin1String("%1")).arg(num, sn.count, 10, QLatin1Char('0')); + const QString newText = QString::fromLatin1("%1").arg(num, sn.count, 10, QLatin1Char('0')); input.replace(pos, used, newText); used = sn.count; } diff --git a/src/corelib/tools/qdumper.cpp b/src/corelib/tools/qdumper.cpp deleted file mode 100644 index c3b8524..0000000 --- a/src/corelib/tools/qdumper.cpp +++ /dev/null @@ -1,1157 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtCore 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qdatetime.h> -#include <qdebug.h> -#include <qdir.h> -#include <qfileinfo.h> -#include <qhash.h> -#include <qmap.h> -#include <qmetaobject.h> -#include <qobject.h> -#include <qstring.h> -#include <qvariant.h> -#include <qvector.h> - -#if !defined(Q_OS_WINCE) && !defined(QT_NO_DUMPER) - -#include <stdlib.h> -#include <stdio.h> - -#ifdef Q_OS_WIN -# include <windows.h> -#endif - -QT_BEGIN_NAMESPACE - -namespace { - -// This is used to abort evaluation of custom data dumpers in a "coordinated" -// way. Abortion will happen anyway when we try to access a non-initialized -// non-trivial object, so there is no way to prevent this from occuring at all -// conceptionally. Gdb will catch SIGSEGV and return to the calling frame. -// This is just fine provided we only _read_ memory in the custom handlers -// below. - -volatile int qProvokeSegFaultHelper; - -static void qCheckAccess(const void *d) -{ - // provoke segfault when address is not readable - qProvokeSegFaultHelper = *(char*)d; -} - -static void qCheckPointer(const void *d) -{ - if (!d) - return; - qProvokeSegFaultHelper = *(char*)d; -} - -static void qProvokeSegFault() -{ - // provoke segfault unconditionally - qCheckAccess(0); -} - -static char qDumpInBuffer[100]; -static char qDumpBuffer[1000]; -#ifdef Q_OS_WIN -static char qDumpBuffer2[sizeof(qDumpBuffer) + 100]; -#endif - -static char toHex(int n) -{ - return n < 10 ? '0' + n : 'a' - 10 + n; -} - - -struct QDumper -{ - explicit QDumper(); - ~QDumper(); - void flush(); - QDumper &operator<<(long c); - QDumper &operator<<(int i); - QDumper &operator<<(unsigned long c); - QDumper &operator<<(unsigned int i); - QDumper &operator<<(const void *p); - void put(char c); - void addCommaIfNeeded(); - void putEncoded(unsigned c); - QDumper &operator<<(const char *str); - QDumper &operator<<(const QString &str); - void disarm(); - - void beginHash(); // start of data hash output - void endHash(); // start of data hash output - - // the dumper arguments - int protocolVersion; // dumper protocol version - int token; // some token to show on success - const char *outertype; // object type - const char *iname; // object name used for display - const char *exp; // object expression - const char *innertype; // 'inner type' for class templates - const void *data; // pointer to raw data - bool dumpChildren; // do we want to see children? - - // handling of nested templates - void setupTemplateParameters(); - enum { maxTemplateParameters = 10 }; - const char *templateParameters[maxTemplateParameters + 1]; - int templateParametersCount; - - // internal state - bool success; // are we finished? - size_t pos; -}; - - -QDumper::QDumper() -{ - success = false; - pos = 0; -} - -QDumper::~QDumper() -{ - flush(); - put(0); // our end marker -#ifdef Q_OS_WIN - sprintf(qDumpBuffer2, "@@CDD/%d/done\n", token); - OutputDebugStringA(qDumpBuffer2); -#else - fprintf(stderr, "%d/done\n", token); -#endif - qDumpInBuffer[0] = 0; -} - -void QDumper::flush() -{ - qDumpBuffer[pos++] = 0; -#ifdef Q_OS_WIN - sprintf(qDumpBuffer2, "@@CDD#%d#%d,%s\n", token, int(pos - 1), qDumpBuffer); - OutputDebugStringA(qDumpBuffer2); -#else - fprintf(stderr, "%d#%d,%s\n", token, int(pos - 1), qDumpBuffer); -#endif - pos = 0; -} - -void QDumper::setupTemplateParameters() -{ - char *s = const_cast<char *>(innertype); - - templateParametersCount = 1; - templateParameters[0] = s; - for (int i = 1; i != maxTemplateParameters + 1; ++i) - templateParameters[i] = 0; - - while (*s) { - while (*s && *s != '@') - ++s; - if (*s) { - *s = '\0'; - ++s; - templateParameters[templateParametersCount++] = s; - } - } -} - -QDumper &QDumper::operator<<(unsigned long c) -{ - static char buf[100]; - sprintf(buf, "%lu", c); - return (*this) << buf; -} - -QDumper &QDumper::operator<<(unsigned int i) -{ - static char buf[100]; - sprintf(buf, "%u", i); - return (*this) << buf; -} - -QDumper &QDumper::operator<<(long c) -{ - static char buf[100]; - sprintf(buf, "%ld", c); - return (*this) << buf; -} - -QDumper &QDumper::operator<<(int i) -{ - static char buf[100]; - sprintf(buf, "%d", i); - return (*this) << buf; -} - -QDumper &QDumper::operator<<(const void *p) -{ - static char buf[100]; - sprintf(buf, "%p", p); - // we get a '0x' prefix only on some implementations. - // if it isn't there, write it out manually. - if (buf[1] != 'x') { - put('0'); - put('x'); - } - return (*this) << buf; -} - -void QDumper::put(char c) -{ - if (pos >= sizeof(qDumpBuffer) - 100) - flush(); - qDumpBuffer[pos++] = c; -} - -void QDumper::addCommaIfNeeded() -{ - if (pos == 0) - return; - if (qDumpBuffer[pos - 1] == '}' || qDumpBuffer[pos - 1] == '"') - put(','); -} - -void QDumper::putEncoded(unsigned c) -{ - if (c >= 32 && c <= 126 && c != '"' && c != '\\') { - put(c); - } else { - put('\\'); - put('u'); - put(toHex((c >> 12) & 0xf)); - put(toHex((c >> 8) & 0xf)); - put(toHex((c >> 4) & 0xf)); - put(toHex( c & 0xf)); - } -} - -QDumper &QDumper::operator<<(const char *str) -{ - while (*str) - put(*(str++)); - return *this; -} - -QDumper &QDumper::operator<<(const QString &str) -{ - int n = str.size(); - if (n < 0) { - qProvokeSegFault(); - } else { - //(*this) << "[" << n << "]"; - if (n > 1000000) - n = 1000000; - //put(' '); - put('\\'); - put('"'); - for (int i = 0; i != n; ++i) - putEncoded(str[i].unicode()); - put('\\'); - put('"'); - if (n < str.size()) - (*this) << "<incomplete string>"; - } - return *this; -} - -void QDumper::disarm() -{ - flush(); - success = true; -} - -void QDumper::beginHash() -{ - addCommaIfNeeded(); - put('{'); -} - -void QDumper::endHash() -{ - put('}'); -} - - -// -// Some helpers to keep the dumper code short -// - -// dump property=value pair -#undef P -#define P(dumper,name,value) \ - do { \ - dumper.addCommaIfNeeded(); \ - dumper << (name) << "=\"" << value << "\""; \ - } while (0) - -// simple string property -#undef S -#define S(dumper, name, value) \ - dumper.beginHash(); \ - P(dumper, "name", name); \ - P(dumper, "value", value); \ - P(dumper, "type", "QString"); \ - P(dumper, "numchild", "0"); \ - dumper.endHash(); - -// simple integer property -#undef I -#define I(dumper, name, value) \ - dumper.beginHash(); \ - P(dumper, "name", name); \ - P(dumper, "value", value); \ - P(dumper, "type", "int"); \ - P(dumper, "numchild", "0"); \ - dumper.endHash(); - -// simple boolean property -#undef BL -#define BL(dumper, name, value) \ - dumper.beginHash(); \ - P(dumper, "name", name); \ - P(dumper, "value", (value ? "true" : "false")); \ - P(dumper, "type", "bool"); \ - P(dumper, "numchild", "0"); \ - dumper.endHash(); - -#undef TT -#define TT(type, value) \ - "<tr><td>" << type << "</td><td> : </td><td>" << value << "</td></tr>" - -static void qDumpUnknown(QDumper &d) -{ - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", "<internal error>"); - P(d, "type", d.outertype); - P(d, "numchild", "0"); - d.disarm(); -} - -static void qDumpQPropertyList(QDumper &d) -{ - const QObject *ob = (const QObject *)d.data; - const QMetaObject *mo = ob->metaObject(); - P(d, "iname", d.iname); - P(d, "addr", "<synthetic>"); - P(d, "type", "QObject"); - P(d, "numchild", mo->propertyCount()); - if (d.dumpChildren) { - d << ",children=["; - for (int i = mo->propertyCount(); --i >= 0; ) { - const QMetaProperty & prop = mo->property(i); - d.beginHash(); - P(d, "name", prop.name()); - if (QLatin1String(prop.typeName()) == QLatin1String("QString")) { - P(d, "value", prop.read(ob).toString()); - P(d, "numchild", "0"); - } else if (QLatin1String(prop.typeName()) == QLatin1String("bool")) { - P(d, "value", (prop.read(ob).toBool() ? "true" : "false")); - P(d, "numchild", "0"); - } else if (QLatin1String(prop.typeName()) == QLatin1String("int")) { - P(d, "value", prop.read(ob).toInt()); - P(d, "numchild", "0"); - } else { - P(d, "exp", "((" << mo->className() << "*)" << ob - << ")->" << prop.name() << "()"); - } - P(d, "type", prop.typeName()); - P(d, "numchild", "1"); - d.endHash(); - } - d << "]"; - } - d.disarm(); -} - -static void qDumpQObject(QDumper &d) -{ - const QObject *ob = reinterpret_cast<const QObject *>(d.data); - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", (void*)d.data); - P(d, "type", "QObject"); - P(d, "numchild", 4); - if (d.dumpChildren) { - const QMetaObject *mo = ob->metaObject(); - const QObjectList &children = ob->children(); - d << ",children=["; - S(d, "objectName", ob->objectName()); - d.beginHash(); - P(d, "name", "properties"); - // FIXME: Note that when simply using '(QObject*)' - // in the cast below, Gdb/MI _sometimes misparses - // expressions further down in the tree. - P(d, "exp", "*(class QObject*)" << d.data); - P(d, "type", "QPropertyList"); - P(d, "value", "<" << mo->propertyCount() << " items>"); - P(d, "numchild", mo->propertyCount()); - d.endHash(); - d.beginHash(); - P(d, "name", "children"); - P(d, "exp", "((class QObject*)" << d.data << ")->children()"); - P(d, "type", "QList<QObject *>"); - P(d, "value", "<" << children.size() << " items>"); - P(d, "numchild", children.size()); - d.endHash(); - d.beginHash(); - P(d, "name", "parent"); - P(d, "exp", "((class QObject*)" << d.data << ")->parent()"); - P(d, "type", "QObject *"); - P(d, "numchild", (ob->parent() ? "1" : "0")); - d.endHash(); - d << "]"; - } - d.disarm(); -} - -static void qDumpQDir(QDumper &d) -{ - const QDir &dir = *reinterpret_cast<const QDir *>(d.data); - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", dir.path()); - P(d, "type", "QDir"); - P(d, "numchild", "3"); - if (d.dumpChildren) { - d << ",children=["; - S(d, "absolutePath", dir.absolutePath()); - S(d, "canonicalPath", dir.canonicalPath()); - d << "]"; - } - d.disarm(); -} - -static void qDumpQFileInfo(QDumper &d) -{ - const QFileInfo &info = *reinterpret_cast<const QFileInfo *>(d.data); - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", info.filePath()); - P(d, "type", "QDir"); - P(d, "numchild", "3"); - if (d.dumpChildren) { - d << ",children=["; - S(d, "absolutePath", info.absolutePath()); - S(d, "absoluteFilePath", info.absoluteFilePath()); - S(d, "canonicalPath", info.canonicalPath()); - S(d, "canonicalFilePath", info.canonicalFilePath()); - S(d, "completeBaseName", info.completeBaseName()); - S(d, "completeSuffix", info.completeSuffix()); - S(d, "baseName", info.baseName()); -#ifdef Q_OS_MACX - BL(d, "isBundle", info.isBundle()); - S(d, "bundleName", info.bundleName()); -#endif - S(d, "completeSuffix", info.completeSuffix()); - S(d, "fileName", info.fileName()); - S(d, "filePath", info.filePath()); - S(d, "group", info.group()); - S(d, "owner", info.owner()); - S(d, "path", info.path()); - - I(d, "groupid", (long)info.groupId()); - I(d, "ownerid", (long)info.ownerId()); - //QFile::Permissions permissions () const - I(d, "permissions", info.permissions()); - - //QDir absoluteDir () const - //QDir dir () const - - BL(d, "caching", info.caching()); - BL(d, "exists", info.exists()); - BL(d, "isAbsolute", info.isAbsolute()); - BL(d, "isDir", info.isDir()); - BL(d, "isExecutable", info.isExecutable()); - BL(d, "isFile", info.isFile()); - BL(d, "isHidden", info.isHidden()); - BL(d, "isReadable", info.isReadable()); - BL(d, "isRelative", info.isRelative()); - BL(d, "isRoot", info.isRoot()); - BL(d, "isSymLink", info.isSymLink()); - BL(d, "isWritable", info.isWritable()); - -#ifndef QT_NO_DATESTRING - d.beginHash(); - P(d, "name", "created"); - P(d, "value", info.created().toString()); - P(d, "exp", "((QFileInfo*)" << d.data << ")->created()"); - P(d, "type", "QDateTime"); - P(d, "numchild", "1"); - d.endHash(); - - d.beginHash(); - P(d, "name", "lastModified"); - P(d, "value", info.lastModified().toString()); - P(d, "exp", "((QFileInfo*)" << d.data << ")->lastModified()"); - P(d, "type", "QDateTime"); - P(d, "numchild", "1"); - d.endHash(); - - d.beginHash(); - P(d, "name", "lastRead"); - P(d, "value", info.lastRead().toString()); - P(d, "exp", "((QFileInfo*)" << d.data << ")->lastRead()"); - P(d, "type", "QDateTime"); - P(d, "numchild", "1"); - d.endHash(); -#endif - - d << "]"; - } - d.disarm(); -} - -static void qDumpQDateTime(QDumper &d) -{ -#ifdef QT_NO_DATESTRING - qDumpUnknown(d); -#else - const QDateTime &date = *reinterpret_cast<const QDateTime *>(d.data); - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", date.toString()); - P(d, "type", "QDateTime"); - P(d, "numchild", "3"); - if (d.dumpChildren) { - d << ",children=["; - BL(d, "isNull", date.isNull()); - I(d, "toTime_t", (long)date.toTime_t()); - S(d, "toString", date.toString()); - S(d, "toString_(ISO)", date.toString(Qt::ISODate)); - S(d, "toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate)); - S(d, "toString_(Locale)", date.toString(Qt::LocaleDate)); - S(d, "toString", date.toString()); - - d.beginHash(); - P(d, "name", "toUTC"); - P(d, "exp", "((QDateTime*)" << d.data << ")->toTimeSpec(Qt::UTC)"); - P(d, "type", "QDateTime"); - P(d, "numchild", "1"); - d.endHash(); - - d.beginHash(); - P(d, "name", "toLocalTime"); - P(d, "exp", "((QDateTime*)" << d.data << ")->toTimeSpec(Qt::LocalTime)"); - P(d, "type", "QDateTime"); - P(d, "numchild", "1"); - d.endHash(); - - d << "]"; - } - d.disarm(); -#endif // ifdef QT_NO_DATESTRING -} - -static void qDumpQString(QDumper &d) -{ - const QString &str = *reinterpret_cast<const QString *>(d.data); - - // Try to provoke segfaults early to prevent the frontend - // from asking for unavailable child details - if (!str.isEmpty()) { - volatile ushort dummy = 0; - dummy += str.at(0).unicode(); - dummy += str.at(str.size() - 1).unicode(); - } - - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", str); - P(d, "type", "QString"); - P(d, "numchild", "0"); - d.disarm(); -} - -static void qDumpQStringList(QDumper &d) -{ - const QStringList &list = *reinterpret_cast<const QStringList *>(d.data); - int n = list.size(); - if (n < 0) - qProvokeSegFault(); - if (n > 0) { - qCheckAccess(&list.front()); - qCheckAccess(&list.back()); - } - - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", "<" << n << " items>"); - P(d, "valuedisabled", "true"); - P(d, "numchild", n); - if (d.dumpChildren) { - if (n > 100) - n = 100; - d << ",children=["; - for (int i = 0; i != n; ++i) { - S(d, "[" << i << "]", list[i]); - } - if (n < list.size()) { - d.beginHash(); - P(d, "value", "<incomplete>"); - P(d, "type", " "); - P(d, "numchild", "0"); - d.endHash(); - } - d << "]"; - } - d.disarm(); -} - -static void qDumpQVariantHelper(const void *data, QString *value, - QString *exp, int *numchild) -{ - const QVariant &v = *reinterpret_cast<const QVariant *>(data); - switch (v.type()) { - case QVariant::Invalid: - *value = QLatin1String("<invalid>"); - *numchild = 0; - break; - case QVariant::String: - *value = QLatin1Char('"') + v.toString() + QLatin1Char('"'); - *numchild = 0; - break; - case QVariant::StringList: - *exp = QString(QLatin1String("((QVariant*)%1)->d.data.c")) - .arg((qulonglong)data); - *numchild = v.toStringList().size(); - break; - case QVariant::Int: - *value = QString::number(v.toInt()); - *numchild= 0; - break; - case QVariant::Double: - *value = QString::number(v.toDouble()); - *numchild = 0; - break; - default: - // FIXME - //*exp = QString("qVariantValue<" << v.typeName() << ">" - // << "(*(QVariant*)" << data << ")"); - break; - } -} - -static void qDumpQVariant(QDumper &d) -{ - const QVariant &v = *reinterpret_cast<const QVariant *>(d.data); - QString value; - QString exp; - int numchild = 0; - qDumpQVariantHelper(d.data, &value, &exp, &numchild); - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", "(" << v.typeName() << ") " << qPrintable(value)); - P(d, "type", "QVariant"); - P(d, "numchild", 1); - if (d.dumpChildren) { - d << ",children=["; - d.beginHash(); - P(d, "name", "value"); - if (!exp.isEmpty()) - P(d, "exp", qPrintable(exp)); - if (!value.isEmpty()) - P(d, "value", qPrintable(value)); - P(d, "type", v.typeName()); - P(d, "numchild", numchild); - d.endHash(); - d << "]"; - } - d.disarm(); -} - -static void qDumpQList(QDumper &d) -{ - // This uses the knowledge that QList<T> has only a single member - // of type union { QListData p; QListData::Data *d; }; - const QListData &ldata = *reinterpret_cast<const QListData*>(d.data); - const QListData::Data *pdata = *reinterpret_cast<const QListData::Data* const*>(d.data); - int nn = ldata.size(); - if (nn < 0) - qProvokeSegFault(); - if (nn > 0) { - qCheckAccess(ldata.d->array); - //qCheckAccess(ldata.d->array[0]); - //qCheckAccess(ldata.d->array[nn - 1]); - } - - int n = nn; - P(d, "iname", d.iname); - P(d, "value", "<" << n << " items>"); - P(d, "valuedisabled", "true"); - P(d, "numchild", n); - if (d.dumpChildren) { - if (n > 100) - n = 100; - d << ",children=["; - for (int i = 0; i != n; ++i) { - d.beginHash(); - P(d, "name", "[" << i << "]"); - // The exact condition here is: - // QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic - // but this data is not available in the compiled binary. - // So as first approximation only do the 'isLarge' check: - void *p = &(ldata.d->array[i + pdata->begin]); - unsigned long voidpsize = sizeof(void*); - P(d, "exp", "(sizeof(" << d.innertype << ")>" << voidpsize << - "?(**(" << d.innertype << "**)(" << p << "))" - ":(*(" << d.innertype << "*)(" << p << ")))"); - P(d, "type", d.innertype); - d.endHash(); - } - if (n < nn) { - d << ",{"; - P(d, "value", "<incomplete>"); - d.endHash(); - } - d << "]"; - } - d.disarm(); -} - -static void qDumpQVector(QDumper &d) -{ - // Use 'int' as representative value. No way (and no need) - // to deduce proper type here. - const QVector<int> &vec = *reinterpret_cast<const QVector<int> *>(d.data); - const int nn = vec.size(); - - // Try to provoke segfaults early to prevent the frontend - // from asking for unavailable child details - if (nn < 0) - qProvokeSegFault(); - if (nn > 0) { - qCheckAccess(&vec.front()); - qCheckAccess(&vec.back()); - } - - //int innersize = 0; - //scanf(qDumpInBuffer, "%d", &innersize); - - int n = nn; - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", "<" << n << " items>"); - P(d, "valuedisabled", "true"); - P(d, "numchild", n); - if (d.dumpChildren) { - if (n > 100) - n = 100; - d << ",children=["; - for (int i = 0; i != n; ++i) { - if (i) - d << ","; - d.beginHash(); - P(d, "name", "[" << i << "]"); - P(d, "exp", "(" << d.exp << ".d->array[" << i << "])"); - P(d, "type", d.innertype); - d.endHash(); - } - if (n < nn) { - d << ",{"; - P(d, "value", "<incomplete>"); - d.endHash(); - } - d << "]"; - } - d.disarm(); -} - -static void qDumpQHashNode(QDumper &d) -{ - struct NodeOS { void *next; uint k; uint v; } nodeOS; // int-key optimization, small value - struct NodeOL { void *next; uint k; void *v; } nodeOL; // int-key optimiatzion, large value - struct NodeNS { void *next; uint h; uint k; uint v; } nodeNS; // no optimization, small value - struct NodeNL { void *next; uint h; uint k; void *v; } nodeNL; // no optimization, large value - struct NodeL { void *next; uint h; void *k; void *v; } nodeL; // complex key - - // offsetof(...,...) not yet in Standard C++ - const ulong nodeOSk ( (char *)&nodeOS.k - (char *)&nodeOS ); - const ulong nodeOSv ( (char *)&nodeOS.v - (char *)&nodeOS ); - const ulong nodeOLk ( (char *)&nodeOL.k - (char *)&nodeOL ); - const ulong nodeOLv ( (char *)&nodeOL.v - (char *)&nodeOL ); - const ulong nodeNSk ( (char *)&nodeNS.k - (char *)&nodeNS ); - const ulong nodeNSv ( (char *)&nodeNS.v - (char *)&nodeNS ); - const ulong nodeNLk ( (char *)&nodeNL.k - (char *)&nodeNL ); - const ulong nodeNLv ( (char *)&nodeNL.v - (char *)&nodeNL ); - const ulong nodeLk ( (char *)&nodeL.k - (char *)&nodeL ); - const ulong nodeLv ( (char *)&nodeL.v - (char *)&nodeL ); - - const QHashData *h = reinterpret_cast<const QHashData *>(d.data); - const char *keyType = d.templateParameters[0]; - const char *valueType = d.templateParameters[1]; - - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", ""); - P(d, "numchild", 2); - if (d.dumpChildren) { - // there is a hash specialization in cast the key are integers or shorts - bool isOptimizedIntKey = qstrcmp(keyType, "int") == 0 -#if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN - || qstrcmp(keyType, "short") == 0 - || qstrcmp(keyType, "ushort") == 0 -#endif - || qstrcmp(keyType, "uint") == 0; - - d << ",children=["; - d.beginHash(); - P(d, "name", "key"); - P(d, "type", keyType); - unsigned long intsize = sizeof(int); - if (isOptimizedIntKey) { - P(d, "exp", "*(" << keyType << "*)" - "(((sizeof(" << valueType << ")>" << intsize << ")?" - << nodeOLk << ":" << nodeOSk << - ")+(char*)" << h << ")"); - } else { - P(d, "exp", "*(" << keyType << "*)" - "(((sizeof(" << keyType << ")>" << intsize << ")?" - << nodeLk << ":" - "((sizeof(" << valueType << ")>" << intsize << ")?" - << nodeNLk << ":" << nodeNSk << "))+(char*)" << h << ")"); - } - d.endHash(); - d.beginHash(); - P(d, "name", "value"); - P(d, "type", valueType); - if (isOptimizedIntKey) { - P(d, "exp", "*(" << valueType << "*)" - "(((sizeof(" << valueType << ")>" << intsize << ")?" - << nodeOLv << ":" << nodeOSv << ")+(char*)" << h << ")"); - } else { - P(d, "exp", "*(" << valueType << "*)" - "(((sizeof(" << keyType << ")>" << intsize << ")?" << nodeLv << ":" - "((sizeof(" << valueType << ")>" << intsize << ")?" - << nodeNLv << ":" << nodeNSv << "))+(char*)" << h << ")"); - } - d.endHash(); - d << "]"; - } - d.disarm(); -} - -static void qDumpQHash(QDumper &d) -{ - QHashData *h = *reinterpret_cast<QHashData *const*>(d.data); - const char *keyType = d.templateParameters[0]; - const char *valueType = d.templateParameters[1]; - - qCheckPointer(h->fakeNext); - qCheckPointer(h->buckets); - - int n = h->size; - - if (n < 0) - qProvokeSegFault(); - if (n > 0) { - qCheckPointer(h->fakeNext); - qCheckPointer(*h->buckets); - } - - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", "<" << n << " items>"); - P(d, "numchild", n); - if (d.dumpChildren) { - if (n > 100) - n = 100; - d << ",children=["; - - QHashData::Node *node = h->firstNode(); - QHashData::Node *end = reinterpret_cast<QHashData::Node *>(h); - int i = 0; - - while (node != end) { - d.beginHash(); - P(d, "name", "[" << i << "]"); - P(d, "type", "QHashNode<" << keyType << "," << valueType << " >"); - P(d, "exp", "*(QHashNode<" << keyType << "," << valueType << " >*)" << node); - d.endHash(); - - ++i; - node = QHashData::nextNode(node); - } - d << "]"; - } - d.disarm(); -} - -static void qDumpQMapNode(QDumper &d) -{ - const QMapData *h = reinterpret_cast<const QMapData *>(d.data); - const char *keyType = d.templateParameters[0]; - const char *valueType = d.templateParameters[1]; - - qCheckAccess(h->backward); - qCheckAccess(h->forward[0]); - - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", ""); - P(d, "numchild", 2); - if (d.dumpChildren) { - unsigned long voidpsize = sizeof(void*); - d << ",children=["; - d.beginHash(); - P(d, "name", "key"); - P(d, "type", keyType); - P(d, "exp", "*(" << keyType << "*)" - << "(" - << 2 * voidpsize - << "-sizeof('QMap<" << keyType << "," << valueType << ">::Node')" - << "+(char*)" << h - << ")"); - d.endHash(); - d.beginHash(); - P(d, "name", "value"); - P(d, "type", valueType); - P(d, "exp", "*(" << valueType << "*)" - << "(" - << "(size_t)&(('QMap<" << keyType << "," << valueType << ">::Node'*)0)->value" - << "+" << 2 * voidpsize - << "-sizeof('QMap<" << keyType << "," << valueType << ">::Node')" - << "+(char*)" << h - << ")"); - d.endHash(); - d << "]"; - } - - d.disarm(); -} - -static void qDumpQMap(QDumper &d) -{ - QMapData *h = *reinterpret_cast<QMapData *const*>(d.data); - const char *keyType = d.templateParameters[0]; - const char *valueType = d.templateParameters[1]; - - int n = h->size; - - if (n < 0) - qProvokeSegFault(); - if (n > 0) { - qCheckAccess(h->backward); - qCheckAccess(h->forward[0]); - qCheckPointer(h->backward->backward); - qCheckPointer(h->forward[0]->backward); - } - - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", "<" << n << " items>"); - P(d, "numchild", n); - if (d.dumpChildren) { - if (n > 100) - n = 100; - d << ",children=["; - - QMapData::Node *node = reinterpret_cast<QMapData::Node *>(h->forward[0]); - QMapData::Node *end = reinterpret_cast<QMapData::Node *>(h); - int i = 0; - - while (node != end) { - d.beginHash(); - P(d, "name", "[" << i << "]"); - P(d, "type", "QMap<" << keyType << "," << valueType << ">::Node"); - P(d, "exp", "*('QMap<" << keyType << "," << valueType << ">::Node'*)" << node); - d.endHash(); - - ++i; - node = node->forward[0]; - } - d << "]"; - } - - d.disarm(); -} - -static void qDumpQSet(QDumper &d) -{ - // This uses the knowledge that QHash<T> has only a single member - // of union { QHashData *d; QHashNode<Key, T> *e; }; - QHashData *hd = *(QHashData**)d.data; - QHashData::Node *node = hd->firstNode(); - - int n = hd->size; - if (n < 0) - qProvokeSegFault(); - if (n > 0) { - qCheckAccess(node); - qCheckPointer(node->next); - } - - P(d, "iname", d.iname); - P(d, "addr", d.data); - P(d, "value", "<" << n << " items>"); - P(d, "valuedisabled", "true"); - P(d, "numchild", 2 * n); - if (d.dumpChildren) { - if (n > 100) - n = 100; - d << ",children=["; - int i = 0; - for (int bucket = 0; bucket != hd->numBuckets; ++bucket) { - for (node = hd->buckets[bucket]; node->next; node = node->next) { - d.beginHash(); - P(d, "name", "[" << i << "]"); - P(d, "type", d.innertype); - P(d, "exp", "(('QHashNode<" << d.innertype - << ",QHashDummyValue>'*)" - << static_cast<const void*>(node) << ")->key" - ); - d.endHash(); - ++i; - } - } - d << "]"; - } - d.disarm(); -} - -static void handleProtocolVersion2(QDumper & d) -{ - if (!d.outertype[0]) { - qDumpUnknown(d); - return; - } - - d.setupTemplateParameters(); - // d.outertype[0] is usally 'Q', so don't use it - switch (d.outertype[1]) { - case 'D': - if (qstrcmp(d.outertype, "QDateTime") == 0) - qDumpQDateTime(d); - else if (qstrcmp(d.outertype, "QDir") == 0) - qDumpQDir(d); - break; - case 'F': - if (qstrcmp(d.outertype, "QFileInfo") == 0) - qDumpQFileInfo(d); - break; - case 'H': - if (qstrcmp(d.outertype, "QHash") == 0) - qDumpQHash(d); - else if (qstrcmp(d.outertype, "QHashNode") == 0) - qDumpQHashNode(d); - break; - case 'L': - if (qstrcmp(d.outertype, "QList") == 0) - qDumpQList(d); - break; - case 'M': - if (qstrcmp(d.outertype, "QMap") == 0) - qDumpQMap(d); - else if (qstrcmp(d.outertype, "QMap::Node") == 0) - qDumpQMapNode(d); - break; - case 'O': - if (qstrcmp(d.outertype, "QObject") == 0) - qDumpQObject(d); - break; - case 'P': - if (qstrcmp(d.outertype, "QPropertyList") == 0) - qDumpQPropertyList(d); - break; - case 'S': - if (qstrcmp(d.outertype, "QSet") == 0) - qDumpQSet(d); - else if (qstrcmp(d.outertype, "QString") == 0) - qDumpQString(d); - else if (qstrcmp(d.outertype, "QStringList") == 0) - qDumpQStringList(d); - break; - case 'V': - if (qstrcmp(d.outertype, "QVariant") == 0) - qDumpQVariant(d); - else if (qstrcmp(d.outertype, "QVector") == 0) - qDumpQVector(d); - break; - } - - if (!d.success) - qDumpUnknown(d); -} - -} // anonymous namespace - - -extern "C" Q_CORE_EXPORT void qDumpObjectData( - int protocolVersion, - int token, - const char *outertype, - const char *iname, - const char *exp, - const char *innertype, - const void *data, - bool dumpChildren) -{ - if (protocolVersion == 1) { - // used to test whether error output gets through - //fprintf(stderr, "using stderr, qDebug follows: %d\n", token); - //qDebug() << "using qDebug, stderr already used: " << token; - } - - else if (protocolVersion == 2) { - QDumper d; - d.protocolVersion = protocolVersion; - d.token = token; - d.outertype = outertype ? outertype : ""; - d.iname = iname ? iname : ""; - d.exp = exp ? exp : ""; - d.innertype = innertype ? innertype : ""; - d.data = data ? data : ""; - d.dumpChildren = dumpChildren; - handleProtocolVersion2(d); - } - - else { - qDebug() << "Unsupported protocol version" << protocolVersion; - } -} - -QT_END_NAMESPACE - -#endif // !Q_OS_WINCE && !QT_NO_QDUMPER diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp new file mode 100644 index 0000000..2b027fc --- /dev/null +++ b/src/corelib/tools/qeasingcurve.cpp @@ -0,0 +1,846 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + +| *property* | *Used for type* | +| period | QEasingCurve::{In,Out,InOut,OutIn}Elastic | +| amplitude | QEasingCurve::{In,Out,InOut,OutIn}Bounce, QEasingCurve::{In,Out,InOut,OutIn}Elastic | +| overshoot | QEasingCurve::{In,Out,InOut,OutIn}Back | + +*/ + + + + +/*! + \class QEasingCurve + \since 4.6 + \ingroup animation + \brief The QEasingCurve class provides easing curves for controlling animation. + + Easing curves describe a function that controls how the speed of the interpolation + between 0 and 1 should be. Easing curves allow transitions from + one value to another to appear more natural than a simple constant speed would allow. + The QEasingCurve class is usually used in conjunction with the QAnimation class, + but can be used on its own. + + To calculate the speed of the interpolation, the easing curve provides the function + valueForProgress(), where the \a progress argument specifies the progress of the + interpolation: 0 is the start value of the interpolation, 1 is the end value of the + interpolation. The returned value is the effective progress of the interpolation. + If the returned value is the same as the input value for all input values the easing + curve is a linear curve. This is the default behaviour. + + For example, + \code + QEasingCurve easing(QEasingCurve::InOutQuad); + + for(qreal t = 0.0; t < 1.0; t+=0.1) + qWarning() << "Effective progress" << t << " is + << easing.valueForProgress(t); + \endcode + will print the effective progress of the interpolation between 0 and 1. + + When using a QAnimation, the easing curve will be used to control the + progress of the interpolation between startValue and endValue: + \code + QAnimation animation; + animation.setStartValue(0); + animation.setEndValue(1000); + animation.setDuration(1000); + animation.setEasingCurve(QEasingCurve::InOutQuad); + \endcode + */ + +/*! + \enum QEasingCurve::Type + + The type of easing curve. + + \value Linear \inlineimage qeasingcurve-linear.png + \br + Easing equation function for a simple linear tweening, + with no easing. + \value InQuad \inlineimage qeasingcurve-inquad.png + \br + Easing equation function for a quadratic (t^2) easing + in: accelerating from zero velocity. + \value OutQuad \inlineimage qeasingcurve-outquad.png + \br + Easing equation function for a quadratic (t^2) easing + out: decelerating to zero velocity. + \value InOutQuad \inlineimage qeasingcurve-inoutquad.png + \br + Easing equation function for a quadratic (t^2) easing + in/out: acceleration until halfway, then deceleration. + \value OutInQuad \inlineimage qeasingcurve-outinquad.png + \br + Easing equation function for a quadratic (t^2) easing + out/in: deceleration until halfway, then acceleration. + \value InCubic \inlineimage qeasingcurve-incubic.png + \br + Easing equation function for a cubic (t^3) easing + in: accelerating from zero velocity. + \value OutCubic \inlineimage qeasingcurve-outcubic.png + \br + Easing equation function for a cubic (t^3) easing + out: decelerating from zero velocity. + \value InOutCubic \inlineimage qeasingcurve-inoutcubic.png + \br + Easing equation function for a cubic (t^3) easing + in/out: acceleration until halfway, then deceleration. + \value OutInCubic \inlineimage qeasingcurve-outincubic.png + \br + Easing equation function for a cubic (t^3) easing + out/in: deceleration until halfway, then acceleration. + \value InQuart \inlineimage qeasingcurve-inquart.png + \br + Easing equation function for a quartic (t^4) easing + in: accelerating from zero velocity. + \value OutQuart \inlineimage qeasingcurve-outquart.png + \br + Easing equation function for a quartic (t^4) easing + out: decelerating from zero velocity. + \value InOutQuart \inlineimage qeasingcurve-inoutquart.png + \br + Easing equation function for a quartic (t^4) easing + in/out: acceleration until halfway, then deceleration. + \value OutInQuart \inlineimage qeasingcurve-outinquart.png + \br + Easing equation function for a quartic (t^4) easing + out/in: deceleration until halfway, then acceleration. + \value InQuint \inlineimage qeasingcurve-inquint.png + \br + Easing equation function for a quintic (t^5) easing + in: accelerating from zero velocity. + \value OutQuint \inlineimage qeasingcurve-outquint.png + \br + Easing equation function for a quintic (t^5) easing + out: decelerating from zero velocity. + \value InOutQuint \inlineimage qeasingcurve-inoutquint.png + \br + Easing equation function for a quintic (t^5) easing + in/out: acceleration until halfway, then deceleration. + \value OutInQuint \inlineimage qeasingcurve-outinquint.png + \br + Easing equation function for a quintic (t^5) easing + out/in: deceleration until halfway, then acceleration. + \value InSine \inlineimage qeasingcurve-insine.png + \br + Easing equation function for a sinusoidal (sin(t)) easing + in: accelerating from zero velocity. + \value OutSine \inlineimage qeasingcurve-outsine.png + \br + Easing equation function for a sinusoidal (sin(t)) easing + out: decelerating from zero velocity. + \value InOutSine \inlineimage qeasingcurve-inoutsine.png + \br + Easing equation function for a sinusoidal (sin(t)) easing + in/out: acceleration until halfway, then deceleration. + \value OutInSine \inlineimage qeasingcurve-outinsine.png + \br + Easing equation function for a sinusoidal (sin(t)) easing + out/in: deceleration until halfway, then acceleration. + \value InExpo \inlineimage qeasingcurve-inexpo.png + \br + Easing equation function for an exponential (2^t) easing + in: accelerating from zero velocity. + \value OutExpo \inlineimage qeasingcurve-outexpo.png + \br + Easing equation function for an exponential (2^t) easing + out: decelerating from zero velocity. + \value InOutExpo \inlineimage qeasingcurve-inoutexpo.png + \br + Easing equation function for an exponential (2^t) easing + in/out: acceleration until halfway, then deceleration. + \value OutInExpo \inlineimage qeasingcurve-outinexpo.png + \br + Easing equation function for an exponential (2^t) easing + out/in: deceleration until halfway, then acceleration. + \value InCirc \inlineimage qeasingcurve-incirc.png + \br + Easing equation function for a circular (sqrt(1-t^2)) easing + in: accelerating from zero velocity. + \value OutCirc \inlineimage qeasingcurve-outcirc.png + \br + Easing equation function for a circular (sqrt(1-t^2)) easing + out: decelerating from zero velocity. + \value InOutCirc \inlineimage qeasingcurve-inoutcirc.png + \br + Easing equation function for a circular (sqrt(1-t^2)) easing + in/out: acceleration until halfway, then deceleration. + \value OutInCirc \inlineimage qeasingcurve-outincirc.png + \br + Easing equation function for a circular (sqrt(1-t^2)) easing + out/in: deceleration until halfway, then acceleration. + \value InElastic \inlineimage qeasingcurve-inelastic.png + \br + Easing equation function for an elastic + (exponentially decaying sine wave) easing in: + accelerating from zero velocity. The peak amplitude + can be set with the \e amplitude parameter, and the + period of decay by the \e period parameter. + \value OutElastic \inlineimage qeasingcurve-outelastic.png + \br + Easing equation function for an elastic + (exponentially decaying sine wave) easing out: + decelerating from zero velocity. The peak amplitude + can be set with the \e amplitude parameter, and the + period of decay by the \e period parameter. + \value InOutElastic \inlineimage qeasingcurve-inoutelastic.png + \br + Easing equation function for an elastic + (exponentially decaying sine wave) easing in/out: + acceleration until halfway, then deceleration. + \value OutInElastic \inlineimage qeasingcurve-outinelastic.png + \br + Easing equation function for an elastic + (exponentially decaying sine wave) easing out/in: + deceleration until halfway, then acceleration. + \value InBack \inlineimage qeasingcurve-inback.png + \br + Easing equation function for a back (overshooting + cubic easing: (s+1)*t^3 - s*t^2) easing in: + accelerating from zero velocity. + \value OutBack \inlineimage qeasingcurve-outback.png + \br + Easing equation function for a back (overshooting + cubic easing: (s+1)*t^3 - s*t^2) easing out: + decelerating from zero velocity. + \value InOutBack \inlineimage qeasingcurve-inoutback.png + \br + Easing equation function for a back (overshooting + cubic easing: (s+1)*t^3 - s*t^2) easing in/out: + acceleration until halfway, then deceleration. + \value OutInBack \inlineimage qeasingcurve-outinback.png + \br + Easing equation function for a back (overshooting + cubic easing: (s+1)*t^3 - s*t^2) easing out/in: + deceleration until halfway, then acceleration. + \value InBounce \inlineimage qeasingcurve-inbounce.png + \br + Easing equation function for a bounce (exponentially + decaying parabolic bounce) easing in: accelerating + from zero velocity. + \value OutBounce \inlineimage qeasingcurve-outbounce.png + \br + Easing equation function for a bounce (exponentially + decaying parabolic bounce) easing out: decelerating + from zero velocity. + \value InOutBounce \inlineimage qeasingcurve-inoutbounce.png + \br + Easing equation function for a bounce (exponentially + decaying parabolic bounce) easing in/out: + acceleration until halfway, then deceleration. + \value OutInBounce \inlineimage qeasingcurve-outinbounce.png + \br + Easing equation function for a bounce (exponentially + decaying parabolic bounce) easing out/in: + deceleration until halfway, then acceleration. + \omitvalue InCurve + \omitvalue OutCurve + \omitvalue SineCurve + \omitvalue CosineCurve + \value Custom This is returned if the user have specified a custom curve type with setCustomType(). Note that you cannot call setType() with this value, but type() can return it. + \omitvalue NCurveTypes +*/ + +/*! + \typedef QEasingCurve::EasingFunction + + This is a typedef for a pointer to a function with the following + signature: + + \snippet doc/src/snippets/code/src_corelib_tools_qeasingcurve.cpp 0 +*/ + +#include "qeasingcurve.h" + +#ifndef QT_NO_DEBUG_STREAM +#include <QtCore/qdebug.h> +#include <QtCore/QString> +#endif + +QT_BEGIN_NAMESPACE + +static bool isConfigFunction(QEasingCurve::Type type) +{ + return type >= QEasingCurve::InElastic + && type <= QEasingCurve::OutInBounce; +} + +class QEasingCurveFunction +{ +public: + enum Type { In, Out, InOut, OutIn }; + + QEasingCurveFunction(QEasingCurveFunction::Type type = In, qreal period = 0.3, qreal amplitude = 1.0, + qreal overshoot = 1.70158f) + : _t(type), _p(period), _a(amplitude), _o(overshoot) + { } + virtual ~QEasingCurveFunction() {} + virtual qreal value(qreal t); + virtual QEasingCurveFunction *copy() const; + bool operator==(const QEasingCurveFunction& other); + + Type _t; + qreal _p; + qreal _a; + qreal _o; +}; + +qreal QEasingCurveFunction::value(qreal t) +{ + return t; +} + +QEasingCurveFunction *QEasingCurveFunction::copy() const +{ + return new QEasingCurveFunction(_t, _p, _a, _o); +} + +bool QEasingCurveFunction::operator==(const QEasingCurveFunction& other) +{ + return _t == other._t && + _p == other._p && + _a == other._a && + _o == other._o; +} + +QT_BEGIN_INCLUDE_NAMESPACE +#include "../../3rdparty/easing/easing.cpp" +QT_END_INCLUDE_NAMESPACE + +class QEasingCurvePrivate +{ +public: + QEasingCurvePrivate() + : type(QEasingCurve::Linear), + config(0), + func(&easeNone) + { } + ~QEasingCurvePrivate() { delete config; } + void setType_helper(QEasingCurve::Type); + + QEasingCurve::Type type; + QEasingCurveFunction *config; + QEasingCurve::EasingFunction func; +}; + +struct ElasticEase : public QEasingCurveFunction +{ + ElasticEase(Type type) + : QEasingCurveFunction(type, qreal(0.3), qreal(1.0)) + { } + + QEasingCurveFunction *copy() const + { + ElasticEase *rv = new ElasticEase(_t); + rv->_p = _p; + rv->_a = _a; + return rv; + } + + qreal value(qreal t) + { + qreal p = (_p < 0) ? 0.3f : _p; + qreal a = (_a < 0) ? 1.0f : _a; + switch(_t) { + case In: + return easeInElastic(t, a, p); + case Out: + return easeOutElastic(t, a, p); + case InOut: + return easeInOutElastic(t, a, p); + case OutIn: + return easeOutInElastic(t, a, p); + default: + return t; + } + } +}; + +struct BounceEase : public QEasingCurveFunction +{ + BounceEase(Type type) + : QEasingCurveFunction(type, 0.3f, 1.0f) + { } + + QEasingCurveFunction *copy() const + { + BounceEase *rv = new BounceEase(_t); + rv->_a = _a; + return rv; + } + + qreal value(qreal t) + { + qreal a = (_a < 0) ? 1.0f : _a; + switch(_t) { + case In: + return easeInBounce(t, a); + case Out: + return easeOutBounce(t, a); + case InOut: + return easeInOutBounce(t, a); + case OutIn: + return easeOutInBounce(t, a); + default: + return t; + } + } +}; + +struct BackEase : public QEasingCurveFunction +{ + BackEase(Type type) + : QEasingCurveFunction(type, 0.3f, 1.0f, 1.70158f) + { } + + QEasingCurveFunction *copy() const + { + BackEase *rv = new BackEase(_t); + rv->_o = _o; + return rv; + } + + qreal value(qreal t) + { + qreal o = (_o < 0) ? 1.70158f : _o; + switch(_t) { + case In: + return easeInBack(t, o); + case Out: + return easeOutBack(t, o); + case InOut: + return easeInOutBack(t, o); + case OutIn: + return easeOutInBack(t, o); + default: + return t; + } + } +}; + +static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve) +{ + switch(curve) { + case QEasingCurve::Linear: + return &easeNone; + case QEasingCurve::InQuad: + return &easeInQuad; + case QEasingCurve::OutQuad: + return &easeOutQuad; + case QEasingCurve::InOutQuad: + return &easeInOutQuad; + case QEasingCurve::OutInQuad: + return &easeOutInQuad; + case QEasingCurve::InCubic: + return &easeInCubic; + case QEasingCurve::OutCubic: + return &easeOutCubic; + case QEasingCurve::InOutCubic: + return &easeInOutCubic; + case QEasingCurve::OutInCubic: + return &easeOutInCubic; + case QEasingCurve::InQuart: + return &easeInQuart; + case QEasingCurve::OutQuart: + return &easeOutQuart; + case QEasingCurve::InOutQuart: + return &easeInOutQuart; + case QEasingCurve::OutInQuart: + return &easeOutInQuart; + case QEasingCurve::InQuint: + return &easeInQuint; + case QEasingCurve::OutQuint: + return &easeOutQuint; + case QEasingCurve::InOutQuint: + return &easeInOutQuint; + case QEasingCurve::OutInQuint: + return &easeOutInQuint; + case QEasingCurve::InSine: + return &easeInSine; + case QEasingCurve::OutSine: + return &easeOutSine; + case QEasingCurve::InOutSine: + return &easeInOutSine; + case QEasingCurve::OutInSine: + return &easeOutInSine; + case QEasingCurve::InExpo: + return &easeInExpo; + case QEasingCurve::OutExpo: + return &easeOutExpo; + case QEasingCurve::InOutExpo: + return &easeInOutExpo; + case QEasingCurve::OutInExpo: + return &easeOutInExpo; + case QEasingCurve::InCirc: + return &easeInCirc; + case QEasingCurve::OutCirc: + return &easeOutCirc; + case QEasingCurve::InOutCirc: + return &easeInOutCirc; + case QEasingCurve::OutInCirc: + return &easeOutInCirc; + // Internal for, compatibility with QTimeLine only ?? + case QEasingCurve::InCurve: + return &easeInCurve; + case QEasingCurve::OutCurve: + return &easeOutCurve; + case QEasingCurve::SineCurve: + return &easeSineCurve; + case QEasingCurve::CosineCurve: + return &easeCosineCurve; + default: + return 0; + }; +} + +static QEasingCurveFunction *curveToFunctionObject(QEasingCurve::Type type) +{ + QEasingCurveFunction *curveFunc = 0; + switch(type) { + case QEasingCurve::InElastic: + curveFunc = new ElasticEase(ElasticEase::In); + break; + case QEasingCurve::OutElastic: + curveFunc = new ElasticEase(ElasticEase::Out); + break; + case QEasingCurve::InOutElastic: + curveFunc = new ElasticEase(ElasticEase::InOut); + break; + case QEasingCurve::OutInElastic: + curveFunc = new ElasticEase(ElasticEase::OutIn); + break; + case QEasingCurve::OutBounce: + curveFunc = new BounceEase(BounceEase::Out); + break; + case QEasingCurve::InBounce: + curveFunc = new BounceEase(BounceEase::In); + break; + case QEasingCurve::OutInBounce: + curveFunc = new BounceEase(BounceEase::OutIn); + break; + case QEasingCurve::InOutBounce: + curveFunc = new BounceEase(BounceEase::InOut); + break; + case QEasingCurve::InBack: + curveFunc = new BackEase(BackEase::In); + break; + case QEasingCurve::OutBack: + curveFunc = new BackEase(BackEase::Out); + break; + case QEasingCurve::InOutBack: + curveFunc = new BackEase(BackEase::InOut); + break; + case QEasingCurve::OutInBack: + curveFunc = new BackEase(BackEase::OutIn); + break; + default: + curveFunc = new QEasingCurveFunction(QEasingCurveFunction::In, 0.3f, 1.0f, 1.70158f); // ### + } + + return curveFunc; +} + +/*! + Constructs an easing curve of the given \a type. + */ +QEasingCurve::QEasingCurve(Type type) + : d_ptr(new QEasingCurvePrivate) +{ + setType(type); +} + +/*! + Construct a copy of \a other. + */ +QEasingCurve::QEasingCurve(const QEasingCurve &other) +: d_ptr(new QEasingCurvePrivate) +{ + // ### non-atomic, requires malloc on shallow copy + *d_ptr = *other.d_ptr; + if(other.d_ptr->config) + d_ptr->config = other.d_ptr->config->copy(); +} + +/*! + Destructor. + */ + +QEasingCurve::~QEasingCurve() +{ + delete d_ptr; +} + +/*! + Copy \a other. + */ +QEasingCurve &QEasingCurve::operator=(const QEasingCurve &other) +{ + // ### non-atomic, requires malloc on shallow copy + if (d_ptr->config) { + delete d_ptr->config; + d_ptr->config = 0; + } + + *d_ptr = *other.d_ptr; + if(other.d_ptr->config) + d_ptr->config = other.d_ptr->config->copy(); + + return *this; +} + +/*! + Compare this easing curve with \a other and returns true if they are + equal. It will also compare the properties of a curve. + */ +bool QEasingCurve::operator==(const QEasingCurve &other) const +{ + bool res = d_ptr->func == other.d_ptr->func + && d_ptr->type == other.d_ptr->type; + if (res && d_ptr->config && other.d_ptr->config) { + // catch the config content + res = d_ptr->config->operator==(*(other.d_ptr->config)); + } + return res; +} + +/*! + \fn bool QEasingCurve::operator!=(const QEasingCurve &other) const + Compare this easing curve with \a other and returns true if they are not equal. + It will also compare the properties of a curve. + + \sa operator==() +*/ + +/*! + Returns the amplitude. This is not applicable for all curve types. + It is only applicable for bounce and elastic curves (curves of type() + QEasingCurve::InBounce, QEasingCurve::OutBounce, QEasingCurve::InOutBounce, + QEasingCurve::OutInBounce, QEasingCurve::InElastic, QEasingCurve::OutElastic, + QEasingCurve::InOutElastic or QEasingCurve::OutInElastic). + */ +qreal QEasingCurve::amplitude() const +{ + return d_ptr->config ? d_ptr->config->_a : 1.0; +} + +/*! + Sets the amplitude to \a amplitude. + + This will set the amplitude of the bounce or the amplitude of the + elastic "spring" effect. The higher the number, the higher the amplitude. + \sa amplitude() +*/ +void QEasingCurve::setAmplitude(qreal amplitude) +{ + if (!d_ptr->config) + d_ptr->config = curveToFunctionObject(d_ptr->type); + d_ptr->config->_a = amplitude; +} + +/*! + Returns the period. This is not applicable for all curve types. + It is only applicable if type() is QEasingCurve::InElastic, QEasingCurve::OutElastic, + QEasingCurve::InOutElastic or QEasingCurve::OutInElastic. + */ +qreal QEasingCurve::period() const +{ + return d_ptr->config ? d_ptr->config->_p : 0.3; +} + +/*! + Sets the period to \a period. + Setting a small period value will give a high frequency of the curve. A + large period will give it a small frequency. + + \sa period() +*/ +void QEasingCurve::setPeriod(qreal period) +{ + if (!d_ptr->config) + d_ptr->config = curveToFunctionObject(d_ptr->type); + d_ptr->config->_p = period; +} + +/*! + Returns the overshoot. This is not applicable for all curve types. + It is only applicable if type() is QEasingCurve::InBack, QEasingCurve::OutBack, + QEasingCurve::InOutBack or QEasingCurve::OutInBack. + */ +qreal QEasingCurve::overshoot() const +{ + return d_ptr->config ? d_ptr->config->_o : 1.70158f; +} + +/*! + Sets the overshoot to \a overshoot. + + 0 produces no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent. + + \sa overshoot() +*/ +void QEasingCurve::setOvershoot(qreal overshoot) +{ + if (!d_ptr->config) + d_ptr->config = curveToFunctionObject(d_ptr->type); + d_ptr->config->_o = overshoot; +} + +/*! + Returns the type of the easing curve. +*/ +QEasingCurve::Type QEasingCurve::type() const +{ + return d_ptr->type; +} + +void QEasingCurvePrivate::setType_helper(QEasingCurve::Type newType) +{ + qreal amp = -1.0; + qreal period = -1.0; + qreal overshoot = -1.0; + + if (config) { + amp = config->_a; + period = config->_p; + overshoot = config->_o; + delete config; + config = 0; + } + + if (isConfigFunction(newType) || (amp != -1.0) || (period != -1.0) || (overshoot != -1.0)) { + config = curveToFunctionObject(newType); + if (amp != -1.0) + config->_a = amp; + if (period != -1.0) + config->_p = period; + if (overshoot != -1.0) + config->_o = overshoot; + func = 0; + } else if (newType != QEasingCurve::Custom) { + func = curveToFunc(newType); + } + Q_ASSERT((func == 0) == (config != 0)); + type = newType; +} + +/*! + Sets the type of the easing curve to \a type. +*/ +void QEasingCurve::setType(Type type) +{ + if (d_ptr->type == type) + return; + if (type < Linear || type >= NCurveTypes - 1) { + qWarning("QEasingCurve: Invalid curve type %d", type); + return; + } + + d_ptr->setType_helper(type); +} + +/*! + Sets a custom easing curve that is defined by the user in the function \a func. + The signature of the function is qreal myEasingFunction(qreal progress), + where \e progress and the return value is considered to be normalized between 0 and 1. + (In some cases the return value can be outside that range) + After calling this function type() will return QEasingCurve::Custom. + \a func cannot be zero. + + \sa customType() + \sa valueForProgress() +*/ +void QEasingCurve::setCustomType(EasingFunction func) +{ + if (!func) { + qWarning("Function pointer must not be null"); + return; + } + d_ptr->func = func; + d_ptr->setType_helper(Custom); +} + +/*! + Returns the function pointer to the custom easing curve. + If type() does not return QEasingCurve::Custom, this function + will return 0. +*/ +QEasingCurve::EasingFunction QEasingCurve::customType() const +{ + return d_ptr->type == Custom ? d_ptr->func : 0; +} + +/*! + Return the effective progress for the easing curve at \a progress. + While \a progress must be between 0 and 1, the returned effective progress + can be outside those bounds. For instance, QEasingCurve::InBack will + return negative values in the beginning of the function. + */ +qreal QEasingCurve::valueForProgress(qreal progress) const +{ + progress = qBound<qreal>(0, progress, 1); + if (d_ptr->func) + return d_ptr->func(progress); + else if (d_ptr->config) + return d_ptr->config->value(progress); + else + return progress; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QEasingCurve &item) +{ + debug << "type:" << item.d_ptr->type + << "func:" << item.d_ptr->func; + if (item.d_ptr->config) { + debug << QString::fromAscii("period:%1").arg(item.d_ptr->config->_p, 0, 'f', 20) + << QString::fromAscii("amp:%1").arg(item.d_ptr->config->_a, 0, 'f', 20) + << QString::fromAscii("overshoot:%1").arg(item.d_ptr->config->_o, 0, 'f', 20); + } + return debug; +} +#endif + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h new file mode 100644 index 0000000..a240bc0 --- /dev/null +++ b/src/corelib/tools/qeasingcurve.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEASINGCURVE_H +#define QEASINGCURVE_H + +#include <QtCore/qglobal.h> +#include <QtCore/qobjectdefs.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QEasingCurvePrivate; +class Q_CORE_EXPORT QEasingCurve +{ + Q_GADGET + Q_ENUMS(Type) +public: + enum Type { + Linear, + InQuad, OutQuad, InOutQuad, OutInQuad, + InCubic, OutCubic, InOutCubic, OutInCubic, + InQuart, OutQuart, InOutQuart, OutInQuart, + InQuint, OutQuint, InOutQuint, OutInQuint, + InSine, OutSine, InOutSine, OutInSine, + InExpo, OutExpo, InOutExpo, OutInExpo, + InCirc, OutCirc, InOutCirc, OutInCirc, + InElastic, OutElastic, InOutElastic, OutInElastic, + InBack, OutBack, InOutBack, OutInBack, + InBounce, OutBounce, InOutBounce, OutInBounce, + InCurve, OutCurve, SineCurve, CosineCurve, + Custom, NCurveTypes + }; + + QEasingCurve(Type type = Linear); + QEasingCurve(const QEasingCurve &other); + ~QEasingCurve(); + + QEasingCurve &operator=(const QEasingCurve &other); + bool operator==(const QEasingCurve &other) const; + inline bool operator!=(const QEasingCurve &other) const + { return !(this->operator==(other)); } + + qreal amplitude() const; + void setAmplitude(qreal amplitude); + + qreal period() const; + void setPeriod(qreal period); + + qreal overshoot() const; + void setOvershoot(qreal overshoot); + + Type type() const; + void setType(Type type); + typedef qreal (*EasingFunction)(qreal progress); + void setCustomType(EasingFunction func); + EasingFunction customType() const; + + qreal valueForProgress(qreal progress) const; +private: + QEasingCurvePrivate *d_ptr; + friend Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item); +}; + +#ifndef QT_NO_DEBUG_STREAM +Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item); +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 21d98b5..2313e0e 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -379,6 +379,107 @@ void QHashData::checkSanity() #endif /*! + \fn uint qHash(const QPair<T1, T2> &key) + \since 4.3 + \relates QHash + + Returns the hash value for the \a key. + + Types \c T1 and \c T2 must be supported by qHash(). +*/ + +/*! \fn uint qHash(char key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(uchar key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(signed char key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(ushort key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(short key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(uint key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(int key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(ulong key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(long key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(quint64 key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(qint64 key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(QChar key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(const QByteArray &key) + \fn uint qHash(const QBitArray &key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(const QString &key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(const T *key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \class QHash \brief The QHash class is a template class that provides a hash-table-based dictionary. @@ -401,7 +502,8 @@ void QHashData::checkSanity() key. With QHash, the items are arbitrarily ordered. \i The key type of a QMap must provide operator<(). The key type of a QHash must provide operator==() and a global - \l{qHash()}{qHash}(Key) function. + hash function called qHash() (see the related non-member + functions). \endlist Here's an example QHash with QString keys and \c int values: @@ -732,7 +834,6 @@ void QHashData::checkSanity() */ /*! \fn const T QHash::value(const Key &key, const T &defaultValue) const - \overload If the hash contains no item with the given \a key, the function returns @@ -1490,121 +1591,6 @@ void QHashData::checkSanity() \sa operator+=(), operator-() */ -/*! \fn uint qHash(char key) - \relates QHash - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(uchar key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(signed char key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(ushort key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(short key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(uint key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(int key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(ulong key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(long key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(quint64 key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(qint64 key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(QChar key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(const QByteArray &key) - \fn uint qHash(const QBitArray &key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(const QString &key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(const T *key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! - \fn uint qHash(const QPair<T1, T2> &key) - \relates QHash - \since 4.3 - - Returns the hash value for the \a key. - - Types \c T1 and \c T2 must be supported by qHash(). -*/ - /*! \fn QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash) \relates QHash diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index a18b531..632c422 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -97,10 +97,7 @@ Q_CORE_EXPORT uint qHash(const QBitArray &key); #endif template <class T> inline uint qHash(const T *key) { - if (sizeof(const T *) > sizeof(uint)) - return qHash(reinterpret_cast<quint64>(key)); - else - return uint(reinterpret_cast<ulong>(key)); + return qHash(reinterpret_cast<quintptr>(key)); } #if defined(Q_CC_MSVC) #pragma warning( pop ) diff --git a/src/corelib/tools/qline.cpp b/src/corelib/tools/qline.cpp index f615dcd..88825a3 100644 --- a/src/corelib/tools/qline.cpp +++ b/src/corelib/tools/qline.cpp @@ -260,7 +260,7 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const QLine &p) { - d << "QLine(" << p.p1() << "," << p.p2() << ")"; + d << "QLine(" << p.p1() << ',' << p.p2() << ')'; return d; } #endif @@ -822,7 +822,7 @@ qreal QLineF::angle(const QLineF &l) const #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const QLineF &p) { - d << "QLineF(" << p.p1() << "," << p.p2() << ")"; + d << "QLineF(" << p.p1() << ',' << p.p2() << ')'; return d; } #endif diff --git a/src/corelib/tools/qlistdata.cpp b/src/corelib/tools/qlistdata.cpp index d40b6b6..34a5d80 100644 --- a/src/corelib/tools/qlistdata.cpp +++ b/src/corelib/tools/qlistdata.cpp @@ -1173,7 +1173,8 @@ void **QListData::erase(void **xi) /*! \typedef QList::iterator::iterator_category - \internal + A synonym for \e {std::random_access_iterator_tag} indicating + this iterator is a random access iterator. */ /*! \typedef QList::iterator::difference_type @@ -1432,7 +1433,8 @@ void **QListData::erase(void **xi) /*! \typedef QList::const_iterator::iterator_category - \internal + A synonym for \e {std::random_access_iterator_tag} indicating + this iterator is a random access iterator. */ /*! \typedef QList::const_iterator::difference_type diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 559ba81..9953155 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -120,7 +120,7 @@ static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt, Q_CORE_EXPORT char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str); Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); -Q_CORE_EXPORT qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok); +static qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok); static qulonglong qstrtoull(const char *nptr, const char **endptr, register int base, bool *ok); /****************************************************************************** @@ -321,7 +321,7 @@ static QString readEscapedFormatString(const QString &format, int *idx) { int &i = *idx; - Q_ASSERT(format.at(i).unicode() == '\''); + Q_ASSERT(format.at(i) == QLatin1Char('\'')); ++i; if (i == format.size()) return QString(); @@ -635,7 +635,7 @@ static QLocale::MeasurementSystem winSystemMeasurementSystem() QString iMeasure = QT_WA_INLINE( QString::fromUtf16(reinterpret_cast<ushort*>(output)), QString::fromLocal8Bit(reinterpret_cast<char*>(output))); - if (iMeasure == QString::fromLatin1("1")) { + if (iMeasure == QLatin1String("1")) { return QLocale::ImperialSystem; } } @@ -1136,7 +1136,7 @@ static QString macToQtFormat(const QString &sys_fmt) break; case 'S': // fractional second if (repeat < 3) - result += QLatin1String("z"); + result += QLatin1Char('z'); else result += QLatin1String("zzz"); break; @@ -1150,7 +1150,7 @@ static QString macToQtFormat(const QString &sys_fmt) if (repeat >= 2) result += QLatin1String("dd"); else - result += QLatin1String("d"); + result += QLatin1Char('d'); break; case 'a': result += QLatin1String("AP"); @@ -1589,7 +1589,7 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l) defaults to the default locale (see setDefault()). \endlist - The "C" locale is identical to \l{English}/\l{UnitedStates}. + The "C" locale is identical in behavior to \l{English}/\l{UnitedStates}. Use language() and country() to determine the actual language and country values used. @@ -1632,7 +1632,7 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l) This enumerated type is used to specify a language. - \value C The "C" locale is English/UnitedStates. + \value C The "C" locale is identical in behavior to English/UnitedStates. \value Abkhazian \value Afan \value Afar @@ -4671,7 +4671,7 @@ static qulonglong qstrtoull(const char *nptr, const char **endptr, register int * Ignores `locale' stuff. Assumes that the upper and lower case * alphabets and digits are each contiguous. */ -Q_CORE_EXPORT qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok) +static qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok) { register const char *s; register qulonglong acc; @@ -5367,6 +5367,14 @@ static Bigint *mult(Bigint *a, Bigint *b) static Bigint *p5s; +struct p5s_deleter +{ + ~p5s_deleter() + { + Bfree(p5s); + } +}; + static Bigint *pow5mult(Bigint *b, int k) { Bigint *b1, *p5, *p51; @@ -5388,6 +5396,7 @@ static Bigint *pow5mult(Bigint *b, int k) return b; if (!(p5 = p5s)) { /* first time */ + static p5s_deleter deleter; p5 = p5s = i2b(625); p5->next = 0; } diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index 0699400..07df28d 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -902,7 +902,8 @@ void QMapData::dump() /*! \typedef QMap::iterator::iterator_category - \internal + A synonym for \e {std::bidirectional_iterator_tag} indicating + this iterator is a bidirectional iterator. */ /*! \typedef QMap::iterator::pointer @@ -1123,7 +1124,8 @@ void QMapData::dump() /*! \typedef QMap::const_iterator::iterator_category - \internal + A synonym for \e {std::bidirectional_iterator_tag} indicating + this iterator is a bidirectional iterator. */ /*! \typedef QMap::const_iterator::pointer diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 5f13e5a..32c8d17 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -990,7 +990,7 @@ Q_INLINE_TEMPLATE int QMultiMap<Key, T>::remove(const Key &key, const T &value) { int n = 0; typename QMap<Key, T>::iterator i(find(key)); - typename QMap<Key, T>::const_iterator end(QMap<Key, T>::constEnd()); + typename QMap<Key, T>::iterator end(QMap<Key, T>::end()); while (i != end && !qMapLessThanKey<Key>(key, i.key())) { if (i.value() == value) { i = erase(i); diff --git a/src/corelib/tools/qpoint.cpp b/src/corelib/tools/qpoint.cpp index 5cc71d6..90b44b1 100644 --- a/src/corelib/tools/qpoint.cpp +++ b/src/corelib/tools/qpoint.cpp @@ -373,7 +373,7 @@ QDebug operator<<(QDebug dbg, const QPoint &p) { QDebug operator<<(QDebug d, const QPointF &p) { - d.nospace() << "QPointF(" << p.x() << ", " << p.y() << ")"; + d.nospace() << "QPointF(" << p.x() << ", " << p.y() << ')'; return d; } #endif diff --git a/src/corelib/tools/qrect.cpp b/src/corelib/tools/qrect.cpp index 3930a0d..5602170 100644 --- a/src/corelib/tools/qrect.cpp +++ b/src/corelib/tools/qrect.cpp @@ -901,7 +901,7 @@ void QRect::moveCenter(const QPoint &p) /*! \fn bool QRect::contains(const QPoint &point, bool proper) const - Returns true if the the given \a point is inside or on the edge of + Returns true if the given \a point is inside or on the edge of the rectangle, otherwise returns false. If \a proper is true, this function only returns true if the given \a point is \e inside the rectangle (i.e., not on the edge). diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h index 3a0901d..02cc497 100644 --- a/src/corelib/tools/qringbuffer_p.h +++ b/src/corelib/tools/qringbuffer_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE -class Q_CORE_EXPORT QRingBuffer +class QRingBuffer { public: inline QRingBuffer(int growth = 4096) : basicBlockSize(growth) { @@ -74,6 +74,52 @@ public: return buffers.isEmpty() ? 0 : (buffers.first().constData() + head); } + // access the bytes at a specified position + // the out-variable length will contain the amount of bytes readable + // from there, e.g. the amount still the same QByteArray + inline const char *readPointerAtPosition(qint64 pos, qint64 &length) const { + if (buffers.isEmpty()) { + length = 0; + return 0; + } + + if (pos >= bufferSize) { + length = 0; + return 0; + } + + // special case: it is in the first buffer + int nextDataBlockSizeValue = nextDataBlockSize(); + if (pos - head < nextDataBlockSizeValue) { + length = nextDataBlockSizeValue - pos; + return buffers.at(0).constData() + head + pos; + } + + // special case: we only had one buffer and tried to read over it + if (buffers.length() == 1) { + length = 0; + return 0; + } + + // skip the first + pos -= nextDataBlockSizeValue; + + // normal case: it is somewhere in the second to the-one-before-the-tailBuffer + for (int i = 1; i < tailBuffer; i++) { + if (pos >= buffers[i].size()) { + pos -= buffers[i].size(); + continue; + } + + length = buffers[i].length() - pos; + return buffers[i].constData() + pos; + } + + // it is in the tail buffer + length = tail - pos; + return buffers[tailBuffer].constData() + pos; + } + inline void free(int bytes) { bufferSize -= bytes; if (bufferSize < 0) diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index f1b35ee..ad2d9f2 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -238,6 +238,7 @@ namespace QtSharedPointer { template <class X> friend class ExternalRefCount; template <class X> friend class QWeakPointer; template <class X, class Y> friend QSharedPointer<X> qSharedPointerCastHelper(const QSharedPointer<Y> &src, X *); + template <class X, class Y> friend QSharedPointer<X> qSharedPointerDynamicCastHelper(const QSharedPointer<Y> &src, X *); template <class X, class Y> friend QSharedPointer<X> qSharedPointerConstCastHelper(const QSharedPointer<Y> &src, X *); template <class X, class Y> friend QSharedPointer<X> QtSharedPointer::qStrongRefFromWeakHelper(const QWeakPointer<Y> &src, X *); #endif @@ -509,6 +510,14 @@ namespace QtSharedPointer { return result; } template <class X, class T> + Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCastHelper(const QSharedPointer<T> &src, X *) + { + QSharedPointer<X> result; + register T *ptr = src.data(); + result.internalSet(src.d, dynamic_cast<X *>(ptr)); + return result; + } + template <class X, class T> Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCastHelper(const QSharedPointer<T> &src, X *) { QSharedPointer<X> result; @@ -544,9 +553,7 @@ template <class X, class T> Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCast(const QSharedPointer<T> &src) { X *x = 0; - if (QtSharedPointer::qVerifyDynamicCast(src.data(), x)) - return QtSharedPointer::qSharedPointerCastHelper(src, x); - return QSharedPointer<X>(); + return QtSharedPointer::qSharedPointerDynamicCastHelper(src, x); } template <class X, class T> Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCast(const QWeakPointer<T> &src) @@ -558,17 +565,13 @@ template <class X, class T> Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &src) { X *x = 0; - if (QtSharedPointer::qVerifyConstCast(src.data(), x)) - return QtSharedPointer::qSharedPointerConstCastHelper(src, x); - return QSharedPointer<X>(); + return QtSharedPointer::qSharedPointerConstCastHelper(src, x); } template <class X, class T> Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCast(const QWeakPointer<T> &src) { X *x = 0; - if (QtSharedPointer::qVerifyConstCast(src.data(), x)) - return QtSharedPointer::qSharedPointerCastHelper(src, x); - return QSharedPointer<X>(); + return QtSharedPointer::qSharedPointerConstCastHelper(src, x); } template <class X, class T> diff --git a/src/corelib/tools/qsize.cpp b/src/corelib/tools/qsize.cpp index 76a5484..bbf6c2a 100644 --- a/src/corelib/tools/qsize.cpp +++ b/src/corelib/tools/qsize.cpp @@ -781,7 +781,7 @@ void QSizeF::scale(const QSizeF &s, Qt::AspectRatioMode mode) \fn QDataStream &operator<<(QDataStream &stream, const QSizeF &size) \relates QSizeF - Writes the the given \a size to the given \a stream and returns a + Writes the given \a size to the given \a stream and returns a reference to the stream. \sa {Format of the QDataStream Operators} diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 375d672..c64e1d6 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -195,6 +195,68 @@ static int ucstrnicmp(const ushort *a, const ushort *b, int l) return ucstricmp(a, a + l, b, b + l); } +static bool qMemEquals(const quint16 *a, const quint16 *b, int length) +{ + // Benchmarking indicates that doing memcmp is much slower than + // executing the comparison ourselves. + // To make it even faster, we do a 32-bit comparison, comparing + // twice the amount of data as a normal word-by-word comparison. + // + // Benchmarking results on a 2.33 GHz Core2 Duo, with a 64-QChar + // block of data, with 4194304 iterations (per iteration): + // operation usec cpu ticks + // memcmp 330 710 + // 16-bit 79 167-171 + // 32-bit aligned 49 105-109 + // + // Testing also indicates that unaligned 32-bit loads are as + // performant as 32-bit aligned. + if (a == b || !length) + return true; + + register union { + const quint16 *w; + const quint32 *d; + quintptr value; + } sa, sb; + sa.w = a; + sb.w = b; + + // check alignment + if ((sa.value & 2) == (sb.value & 2)) { + // both addresses have the same alignment + if (sa.value & 2) { + // both addresses are not aligned to 4-bytes boundaries + // compare the first character + if (*sa.w != *sb.w) + return false; + --length; + ++sa.w; + ++sb.w; + + // now both addresses are 4-bytes aligned + } + + // both addresses are 4-bytes aligned + // do a fast 32-bit comparison + register const quint32 *e = sa.d + (length >> 1); + for ( ; sa.d != e; ++sa.d, ++sb.d) { + if (*sa.d != *sb.d) + return false; + } + + // do we have a tail? + return (length & 1) ? *sa.w == *sb.w : true; + } else { + // one of the addresses isn't 4-byte aligned but the other is + register const quint16 *e = sa.w + length; + for ( ; sa.w != e; ++sa.w, ++sb.w) { + if (*sa.w != *sb.w) + return false; + } + } + return true; +} /*! \internal @@ -743,7 +805,9 @@ int QString::grow(int size) /*! \since 4.2 - Returns a copy of the \a string string encoded in ucs4. + Returns a copy of the \a string, where the encoding of \a string depends on + the size of wchar. If wchar is 4 bytes, the \a string is interpreted as ucs-4, + if wchar is 2 bytes it is interpreted as ucs-2. If \a size is -1 (default), the \a string has to be 0 terminated. @@ -880,6 +944,23 @@ QString::QString(int size, QChar ch) } } +/*! + Constructs a string of the given \a size without initializing the + characters. This is only used in \c QStringBuilder::toString(). + + \internal +*/ + +QString::QString(int size, Uninitialized) +{ + d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar)); + d->ref = 1; + d->alloc = d->size = size; + d->clean = d->asciiCache = d->simpletext = d->righttoleft = d->capacity = 0; + d->data = d->array; + d->array[size] = '\0'; +} + /*! \fn QString::QString(const QLatin1String &str) Constructs a copy of the Latin-1 string \a str. @@ -1906,8 +1987,10 @@ QString &QString::replace(QChar c, const QLatin1String &after, Qt::CaseSensitivi */ bool QString::operator==(const QString &other) const { - return (size() == other.size()) && - (memcmp((char*)unicode(),(char*)other.unicode(), size()*sizeof(QChar))==0); + if (d->size != other.d->size) + return false; + + return qMemEquals(d->data, other.d->data, d->size); } /*! @@ -3134,7 +3217,7 @@ bool QString::startsWith(const QString& s, Qt::CaseSensitivity cs) const if (s.d->size > d->size) return false; if (cs == Qt::CaseSensitive) { - return memcmp((char*)d->data, (char*)s.d->data, s.d->size*sizeof(QChar)) == 0; + return qMemEquals(d->data, s.d->data, s.d->size); } else { uint last = 0; uint olast = 0; @@ -3205,7 +3288,7 @@ bool QString::endsWith(const QString& s, Qt::CaseSensitivity cs) const if (pos < 0) return false; if (cs == Qt::CaseSensitive) { - return memcmp((char*)&d->data[pos], (char*)s.d->data, s.d->size*sizeof(QChar)) == 0; + return qMemEquals(d->data + pos, s.d->data, s.d->size); } else { uint last = 0; uint olast = 0; @@ -7690,7 +7773,8 @@ QString QStringRef::toString() const { */ bool operator==(const QStringRef &s1,const QStringRef &s2) { return (s1.size() == s2.size() && - (memcmp((char*)s1.unicode(), (char*)s2.unicode(), s1.size()*sizeof(QChar))==0)); } + qMemEquals((const ushort *)s1.unicode(), (const ushort *)s2.unicode(), s1.size())); +} /*! \relates QStringRef @@ -7699,7 +7783,8 @@ bool operator==(const QStringRef &s1,const QStringRef &s2) */ bool operator==(const QString &s1,const QStringRef &s2) { return (s1.size() == s2.size() && - (memcmp((char*)s1.unicode(), (char*)s2.unicode(), s1.size()*sizeof(QChar))==0)); } + qMemEquals((const ushort *)s1.unicode(), (const ushort *)s2.unicode(), s1.size())); +} /*! \relates QStringRef diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 1493dce..7c0d6a3 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -113,7 +113,7 @@ public: int capacity() const; inline void reserve(int size); - inline void squeeze() { if (d->size < d->alloc) realloc(); d->capacity = 0;} + inline void squeeze() { if (d->size < d->alloc || d->ref != 1) realloc(); d->capacity = 0;} inline const QChar *unicode() const; inline QChar *data(); @@ -579,6 +579,9 @@ public: bool isSimpleText() const { if (!d->clean) updateProperties(); return d->simpletext; } bool isRightToLeft() const { if (!d->clean) updateProperties(); return d->righttoleft; } + struct Uninitialized {}; + QString(int size, Uninitialized); + private: #if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED) QString &operator+=(const char *s); @@ -1001,13 +1004,15 @@ inline int QByteArray::findRev(const QString &s, int from) const # endif // QT3_SUPPORT #endif // QT_NO_CAST_TO_ASCII +#ifndef QT_USE_FAST_OPERATOR_PLUS +# ifndef QT_USE_FAST_CONCATENATION inline const QString operator+(const QString &s1, const QString &s2) { QString t(s1); t += s2; return t; } inline const QString operator+(const QString &s1, QChar s2) { QString t(s1); t += s2; return t; } inline const QString operator+(QChar s1, const QString &s2) { QString t(s1); t += s2; return t; } -#ifndef QT_NO_CAST_FROM_ASCII +# ifndef QT_NO_CAST_FROM_ASCII inline QT_ASCII_CAST_WARN const QString operator+(const QString &s1, const char *s2) { QString t(s1); t += QString::fromAscii(s2); return t; } inline QT_ASCII_CAST_WARN const QString operator+(const char *s1, const QString &s2) @@ -1020,7 +1025,9 @@ inline QT_ASCII_CAST_WARN const QString operator+(const QByteArray &ba, const QS { QString t = QString::fromAscii(ba.constData(), qstrnlen(ba.constData(), ba.size())); t += s; return t; } inline QT_ASCII_CAST_WARN const QString operator+(const QString &s, const QByteArray &ba) { QString t(s); t += QString::fromAscii(ba.constData(), qstrnlen(ba.constData(), ba.size())); return t; } -#endif +# endif // QT_NO_CAST_FROM_ASCII +# endif // QT_USE_FAST_CONCATENATION +#endif // QT_USE_FAST_OPERATOR_PLUS #ifndef QT_NO_STL inline std::string QString::toStdString() const @@ -1229,6 +1236,8 @@ inline int QStringRef::localeAwareCompare(const QStringRef &s1, const QStringRef QT_END_NAMESPACE -QT_END_HEADER +#ifdef QT_USE_FAST_CONCATENATION +#include <QtCore/qstringbuilder.h> +#endif #endif // QSTRING_H diff --git a/src/corelib/tools/qstringbuilder.cpp b/src/corelib/tools/qstringbuilder.cpp new file mode 100644 index 0000000..b807a89 --- /dev/null +++ b/src/corelib/tools/qstringbuilder.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstringbuilder.h" + +/*! + \class QLatin1Literal + \reentrant + \since 4.6 + + \brief The QLatin1Literal class provides a thin wrapper around string + literals used in source code. + + \ingroup tools + \ingroup shared + \ingroup text + \mainclass + + Unlike \c QLatin1String, a \c QLatin1Literal can retrieve its size + without iterating over the literal. + + The main use of \c QLatin1Literal is in conjunction with \c QStringBuilder + to reduce the number of reallocations needed to build up a string from + smaller chunks. + + \sa QStringBuilder, QLatin1String, QString, QStringRef +*/ + +/*! \fn QLatin1Literal::QLatin1Literal(const char(&string)[]) + + Constructs a new literal from the given \a string. +*/ + +/*! \fn int QLatin1Literal::size() const + + Returns the number of characters in the literal \i{excluding} the trailing + NUL char. +*/ + +/*! \fn char *QLatin1Literal::data() const + + Returns a pointer to the first character of the string literal. + The string literal is terminated by a NUL character. +*/ + +/*! \fn QLatin1Literal::operator QString() const + + Converts the \c QLatin1Literal into a \c QString object. +*/ + + + +/*! + \class QStringBuilder + \reentrant + \since 4.6 + + \brief QStringBuilder is a template class that provides a facility to build + up QStrings from smaller chunks. + + \ingroup tools + \ingroup shared + \ingroup text + \mainclass + + When creating strings from smaller chunks, typically \c QString::operator+() + is used, resulting in \i{n - 1} reallocations when operating on \i{n} chunks. + + QStringBuilder uses expression templates to collect the individual parts, + compute the total size, allocate memory for the resulting QString object, + and copy the contents of the chunks into the result. + + The QStringBuilder class is not to be used explicitly in user code. + Instances of the class are created as return values of the operator%() + function, acting on objects of type \c QString, \c QLatin1String, + \c QLatin1Literal, \c \QStringRef, \c QChar, + \c QLatin1Char, and \c char. + + Concatenating strings with operator%() generally yields better + performance then using \c QString::operator+() on the same chunks + if there are three or more of them, and performs equally well in other + cases. + + \sa QLatin1Literal, QString +*/ + +/* !fn template <class A, class B> QStringBuilder<A, B> operator%(const A &a, const B &b) + + Returns a \c QStringBuilder object that is converted to a QString object + when assigned to a variable of QString type or passed to a function that + takes a QString parameter. + + This function is usable with arguments of type \c QString, + \c QLatin1String, \c QLatin1Literal, \c QStringRef, + \c QChar, \c QLatin1Char, and \c char. +*/ + diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h new file mode 100644 index 0000000..1e67b7d --- /dev/null +++ b/src/corelib/tools/qstringbuilder.h @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTRINGBUILDER_H +#define QSTRINGBUILDER_H + +#include <QtCore/qstring.h> + +#include <string.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +// ### Qt 5: merge with QLatin1String +class QLatin1Literal +{ +public: + template <int N> + QLatin1Literal(const char (&str)[N]) : m_size(N - 1), m_data(str) {} + + inline int size() const { return m_size; } + inline const char *data() const { return m_data; } + +private: + const int m_size; + const char *m_data; +}; + + +template <typename T> class QConcatenable {}; + +template <typename A, typename B> +class QStringBuilder +{ +public: + QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {} + + operator QString() const + { + QString s(QConcatenable< QStringBuilder<A, B> >::size(*this), + QString::Uninitialized()); + + QChar *d = s.data(); + QConcatenable< QStringBuilder<A, B> >::appendTo(*this, d); + return s; + } + QByteArray toLatin1() const { return QString(*this).toLatin1(); } + + const A &a; + const B &b; +}; + + +template <> struct QConcatenable<char> +{ + typedef char type; + static int size(const char) { return 1; } + static inline void appendTo(const char c, QChar *&out) + { + *out++ = QLatin1Char(c); + } +}; + +template <> struct QConcatenable<QLatin1Char> +{ + typedef QLatin1Char type; + static int size(const QLatin1Char) { return 1; } + static inline void appendTo(const QLatin1Char c, QChar *&out) + { + *out++ = c; + } +}; + +template <> struct QConcatenable<QChar> +{ + typedef QChar type; + static int size(const QChar) { return 1; } + static inline void appendTo(const QChar c, QChar *&out) + { + *out++ = c; + } +}; + +template <> struct QConcatenable<QLatin1String> +{ + typedef QLatin1String type; + static int size(const QLatin1String &a) { return qstrlen(a.latin1()); } + static inline void appendTo(const QLatin1String &a, QChar *&out) + { + for (const char *s = a.latin1(); *s; ) + *out++ = QLatin1Char(*s++); + } + +}; + +template <> struct QConcatenable<QLatin1Literal> +{ + typedef QLatin1Literal type; + static int size(const QLatin1Literal &a) { return a.size(); } + static inline void appendTo(const QLatin1Literal &a, QChar *&out) + { + for (const char *s = a.data(); *s; ) + *out++ = QLatin1Char(*s++); + } +}; + +template <> struct QConcatenable<QString> +{ + typedef QString type; + static int size(const QString &a) { return a.size(); } + static inline void appendTo(const QString &a, QChar *&out) + { + const int n = a.size(); + memcpy(out, (char*)a.constData(), sizeof(QChar) * n); + out += n; + } +}; + +template <> struct QConcatenable<QStringRef> +{ + typedef QStringRef type; + static int size(const QStringRef &a) { return a.size(); } + static inline void appendTo(QStringRef a, QChar *&out) + { + const int n = a.size(); + memcpy(out, (char*)a.constData(), sizeof(QChar) * n); + out += n; + } +}; + +template <typename A, typename B> +struct QConcatenable< QStringBuilder<A, B> > +{ + typedef QStringBuilder<A, B> type; + static int size(const type &p) + { + return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b); + } + static inline void appendTo(const QStringBuilder<A, B> &p, QChar *&out) + { + QConcatenable<A>::appendTo(p.a, out); + QConcatenable<B>::appendTo(p.b, out); + } +}; + +template <typename A, typename B> +QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type> +operator%(const A &a, const B &b) +{ + return QStringBuilder<A, B>(a, b); +} + +#ifdef QT_USE_FAST_OPERATOR_PLUS +template <typename A, typename B> +QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type> +operator+(const A &a, const B &b) +{ + return QStringBuilder<A, B>(a, b); +} +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSTRINGBUILDER_H diff --git a/src/corelib/tools/qstringlist.cpp b/src/corelib/tools/qstringlist.cpp index 386321f1..cf1bff8 100644 --- a/src/corelib/tools/qstringlist.cpp +++ b/src/corelib/tools/qstringlist.cpp @@ -397,7 +397,7 @@ void QtPrivate::QStringList_replaceInStrings(QStringList *that, const QRegExp &r \fn QString QStringList::join(const QString &separator) const Joins all the string list's strings into a single string with each - element separated by the the given \a separator (which can be an + element separated by the given \a separator (which can be an empty string). \sa QString::split() @@ -621,8 +621,6 @@ int QtPrivate::QStringList_lastIndexOf(const QStringList *that, QRegExp &rx, int the list, searching forward from index position \a from. Returns -1 if no item matched. - By default, this function is case sensitive. - \sa lastIndexOf(), contains(), QList::indexOf() */ diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp index 2979a09..ee4f73c 100644 --- a/src/corelib/tools/qtimeline.cpp +++ b/src/corelib/tools/qtimeline.cpp @@ -48,20 +48,6 @@ QT_BEGIN_NAMESPACE -static const qreal pi = qreal(3.14159265359); -static const qreal halfPi = pi / qreal(2.0); - - -static inline qreal qt_sinProgress(qreal value) -{ - return qSin((value * pi) - halfPi) / 2 + qreal(0.5); -} - -static inline qreal qt_smoothBeginEndMixFactor(qreal value) -{ - return qMin(qMax(1 - value * 2 + qreal(0.3), qreal(0.0)), qreal(1.0)); -} - class QTimeLinePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QTimeLine) @@ -70,7 +56,7 @@ public: : startTime(0), duration(1000), startFrame(0), endFrame(0), updateInterval(1000 / 25), totalLoopCount(1), currentLoopCount(0), currentTime(0), timerId(0), - direction(QTimeLine::Forward), curveShape(QTimeLine::EaseInOutCurve), + direction(QTimeLine::Forward), easingCurve(QEasingCurve::InOutSine), state(QTimeLine::NotRunning) { } @@ -88,7 +74,7 @@ public: QTime timer; QTimeLine::Direction direction; - QTimeLine::CurveShape curveShape; + QEasingCurve easingCurve; QTimeLine::State state; inline void setState(QTimeLine::State newState) { @@ -225,7 +211,9 @@ void QTimeLinePrivate::setCurrentTime(int msecs) valueForTime() and emitting valueChanged(). By default, valueForTime() applies an interpolation algorithm to generate these value. You can choose from a set of predefined timeline algorithms by calling - setCurveShape(). By default, QTimeLine uses the EaseInOut curve shape, + setCurveShape(). + + Note that by default, QTimeLine uses the EaseInOut curve shape, which provides a value that grows slowly, then grows steadily, and finally grows slowly. For a custom timeline, you can reimplement valueForTime(), in which case QTimeLine's curveShape property is ignored. @@ -521,12 +509,68 @@ void QTimeLine::setUpdateInterval(int interval) QTimeLine::CurveShape QTimeLine::curveShape() const { Q_D(const QTimeLine); - return d->curveShape; + switch (d->easingCurve.type()) { + default: + case QEasingCurve::InOutSine: + return EaseInOutCurve; + case QEasingCurve::InCurve: + return EaseInCurve; + case QEasingCurve::OutCurve: + return EaseOutCurve; + case QEasingCurve::Linear: + return LinearCurve; + case QEasingCurve::SineCurve: + return SineCurve; + case QEasingCurve::CosineCurve: + return CosineCurve; + } + return EaseInOutCurve; } + void QTimeLine::setCurveShape(CurveShape shape) { + switch (shape) { + default: + case EaseInOutCurve: + setEasingCurve(QEasingCurve(QEasingCurve::InOutSine)); + break; + case EaseInCurve: + setEasingCurve(QEasingCurve(QEasingCurve::InCurve)); + break; + case EaseOutCurve: + setEasingCurve(QEasingCurve(QEasingCurve::OutCurve)); + break; + case LinearCurve: + setEasingCurve(QEasingCurve(QEasingCurve::Linear)); + break; + case SineCurve: + setEasingCurve(QEasingCurve(QEasingCurve::SineCurve)); + break; + case CosineCurve: + setEasingCurve(QEasingCurve(QEasingCurve::CosineCurve)); + break; + } +} + +/*! + \property QTimeLine::easingCurve + + Specifies the easing curve that the timeline will use. + If both easing curve and curveShape are set, the last set property will + override the previous one. (If valueForTime() is reimplemented it will + override both) +*/ + +QEasingCurve QTimeLine::easingCurve() const +{ + Q_D(const QTimeLine); + return d->easingCurve; +} + +void QTimeLine::setEasingCurve(const QEasingCurve& curve) +{ Q_D(QTimeLine); - d->curveShape = shape; + d->easingCurve = curve; } /*! @@ -606,42 +650,8 @@ qreal QTimeLine::valueForTime(int msec) const Q_D(const QTimeLine); msec = qMin(qMax(msec, 0), d->duration); - // Simple linear interpolation qreal value = msec / qreal(d->duration); - - switch (d->curveShape) { - case EaseInOutCurve: - value = qt_sinProgress(value); - break; - // SmoothBegin blends Smooth and Linear Interpolation. - // Progress 0 - 0.3 : Smooth only - // Progress 0.3 - ~ 0.5 : Mix of Smooth and Linear - // Progress ~ 0.5 - 1 : Linear only - case EaseInCurve: { - const qreal sinProgress = qt_sinProgress(value); - const qreal linearProgress = value; - const qreal mix = qt_smoothBeginEndMixFactor(value); - value = sinProgress * mix + linearProgress * (1 - mix); - break; - } - case EaseOutCurve: { - const qreal sinProgress = qt_sinProgress(value); - const qreal linearProgress = value; - const qreal mix = qt_smoothBeginEndMixFactor(1 - value); - value = sinProgress * mix + linearProgress * (1 - mix); - break; - } - case SineCurve: - value = (qSin(((msec * pi * 2) / d->duration) - pi/2) + 1) / 2; - break; - case CosineCurve: - value = (qCos(((msec * pi * 2) / d->duration) - pi/2) + 1) / 2; - break; - default: - break; - } - - return value; + return d->easingCurve.valueForProgress(value); } /*! diff --git a/src/corelib/tools/qtimeline.h b/src/corelib/tools/qtimeline.h index 18c3980..48c9232 100644 --- a/src/corelib/tools/qtimeline.h +++ b/src/corelib/tools/qtimeline.h @@ -42,6 +42,7 @@ #ifndef QTIMELINE_H #define QTIMELINE_H +#include <QtCore/qeasingcurve.h> #include <QtCore/qobject.h> QT_BEGIN_HEADER @@ -60,6 +61,7 @@ class Q_CORE_EXPORT QTimeLine : public QObject Q_PROPERTY(Direction direction READ direction WRITE setDirection) Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount) Q_PROPERTY(CurveShape curveShape READ curveShape WRITE setCurveShape) + Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve) public: enum State { NotRunning, @@ -105,6 +107,9 @@ public: CurveShape curveShape() const; void setCurveShape(CurveShape shape); + QEasingCurve easingCurve() const; + void setEasingCurve(const QEasingCurve &curve); + int currentTime() const; int currentFrame() const; qreal currentValue() const; diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 3fd52ee..7bdcba0 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -82,19 +82,9 @@ struct Q_CORE_EXPORT QVectorData }; template <typename T> -struct QVectorTypedData -{ - QBasicAtomicInt ref; - int alloc; - int size; -#if defined(QT_ARCH_SPARC) && defined(Q_CC_GNU) && defined(__LP64__) && defined(QT_BOOTSTRAPPED) - // workaround for bug in gcc 3.4.2 - uint sharable; - uint capacity; -#else - uint sharable : 1; - uint capacity : 1; -#endif +struct QVectorTypedData : private QVectorData +{ // private inheritance as we must not access QVectorData member thought QVectorTypedData + // as this would break strict aliasing rules. (in the case of shared_null) T array[1]; }; @@ -104,14 +94,14 @@ template <typename T> class QVector { typedef QVectorTypedData<T> Data; - union { QVectorData *p; QVectorTypedData<T> *d; }; + union { QVectorData *d; Data *p; }; public: - inline QVector() : p(&QVectorData::shared_null) { d->ref.ref(); } + inline QVector() : d(&QVectorData::shared_null) { d->ref.ref(); } explicit QVector(int size); QVector(int size, const T &t); inline QVector(const QVector<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); } - inline ~QVector() { if (!d) return; if (!d->ref.deref()) free(d); } + inline ~QVector() { if (!d) return; if (!d->ref.deref()) free(p); } QVector<T> &operator=(const QVector<T> &v); bool operator==(const QVector<T> &v) const; inline bool operator!=(const QVector<T> &v) const { return !(*this == v); } @@ -130,9 +120,9 @@ public: inline bool isDetached() const { return d->ref == 1; } inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; } - inline T *data() { detach(); return d->array; } - inline const T *data() const { return d->array; } - inline const T *constData() const { return d->array; } + inline T *data() { detach(); return p->array; } + inline const T *data() const { return p->array; } + inline const T *constData() const { return p->array; } void clear(); const T &at(int i) const; @@ -225,12 +215,12 @@ public: typedef T* iterator; typedef const T* const_iterator; #endif - inline iterator begin() { detach(); return d->array; } - inline const_iterator begin() const { return d->array; } - inline const_iterator constBegin() const { return d->array; } - inline iterator end() { detach(); return d->array + d->size; } - inline const_iterator end() const { return d->array + d->size; } - inline const_iterator constEnd() const { return d->array + d->size; } + inline iterator begin() { detach(); return p->array; } + inline const_iterator begin() const { return p->array; } + inline const_iterator constBegin() const { return p->array; } + inline iterator end() { detach(); return p->array + d->size; } + inline const_iterator end() const { return p->array + d->size; } + inline const_iterator constEnd() const { return p->array + d->size; } iterator insert(iterator before, int n, const T &x); inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); } iterator erase(iterator begin, iterator end); @@ -315,7 +305,7 @@ void QVector<T>::detach_helper() { realloc(d->size, d->alloc); } template <typename T> void QVector<T>::reserve(int asize) -{ if (asize > d->alloc) realloc(d->size, asize); d->capacity = 1; } +{ if (asize > d->alloc || d->ref != 1) realloc(d->size, asize); d->capacity = 1; } template <typename T> void QVector<T>::resize(int asize) { realloc(asize, (asize > d->alloc || (!d->capacity && asize < d->size && asize < (d->alloc >> 1))) ? @@ -327,11 +317,11 @@ inline void QVector<T>::clear() template <typename T> inline const T &QVector<T>::at(int i) const { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range"); - return d->array[i]; } + return p->array[i]; } template <typename T> inline const T &QVector<T>::operator[](int i) const { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range"); - return d->array[i]; } + return p->array[i]; } template <typename T> inline T &QVector<T>::operator[](int i) { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range"); @@ -369,7 +359,7 @@ QVector<T> &QVector<T>::operator=(const QVector<T> &v) { v.d->ref.ref(); if (!d->ref.deref()) - free(d); + free(p); d = v.d; if (!d->sharable) detach_helper(); @@ -385,31 +375,31 @@ inline QVectorData *QVector<T>::malloc(int aalloc) template <typename T> QVector<T>::QVector(int asize) { - p = malloc(asize); + d = malloc(asize); d->ref = 1; d->alloc = d->size = asize; d->sharable = true; d->capacity = false; if (QTypeInfo<T>::isComplex) { - T* b = d->array; - T* i = d->array + d->size; + T* b = p->array; + T* i = p->array + d->size; while (i != b) new (--i) T; } else { - qMemSet(d->array, 0, asize * sizeof(T)); + qMemSet(p->array, 0, asize * sizeof(T)); } } template <typename T> QVector<T>::QVector(int asize, const T &t) { - p = malloc(asize); + d = malloc(asize); d->ref = 1; d->alloc = d->size = asize; d->sharable = true; d->capacity = false; - T* i = d->array + d->size; - while (i != d->array) + T* i = p->array + d->size; + while (i != p->array) new (--i) T(t); } @@ -418,7 +408,7 @@ void QVector<T>::free(Data *x) { if (QTypeInfo<T>::isComplex) { T* b = x->array; - T* i = b + x->size; + T* i = b + reinterpret_cast<QVectorData *>(x)->size; while (i-- != b) i->~T(); } @@ -429,13 +419,13 @@ template <typename T> void QVector<T>::realloc(int asize, int aalloc) { T *j, *i, *b; - union { QVectorData *p; Data *d; } x; + union { QVectorData *d; Data *p; } x; x.d = d; if (QTypeInfo<T>::isComplex && aalloc == d->alloc && d->ref == 1) { // pure resize - i = d->array + d->size; - j = d->array + asize; + i = p->array + d->size; + j = p->array + asize; if (i > j) { while (i-- != j) i->~T(); @@ -450,22 +440,22 @@ void QVector<T>::realloc(int asize, int aalloc) if (aalloc != d->alloc || d->ref != 1) { // (re)allocate memory if (QTypeInfo<T>::isStatic) { - x.p = malloc(aalloc); + x.d = malloc(aalloc); } else if (d->ref != 1) { - x.p = QVectorData::malloc(sizeOfTypedData(), aalloc, sizeof(T), p); + x.d = QVectorData::malloc(sizeOfTypedData(), aalloc, sizeof(T), d); } else { if (QTypeInfo<T>::isComplex) { // call the destructor on all objects that need to be // destroyed when shrinking if (asize < d->size) { - j = d->array + asize; - i = d->array + d->size; + j = p->array + asize; + i = p->array + d->size; while (i-- != j) i->~T(); - i = d->array + asize; + i = p->array + asize; } } - x.p = p = static_cast<QVectorData *>(qRealloc(p, sizeOfTypedData() + (aalloc - 1) * sizeof(T))); + x.d = d = static_cast<QVectorData *>(qRealloc(d, sizeOfTypedData() + (aalloc - 1) * sizeof(T))); } x.d->ref = 1; x.d->sharable = true; @@ -474,31 +464,31 @@ void QVector<T>::realloc(int asize, int aalloc) } if (QTypeInfo<T>::isComplex) { if (asize < d->size) { - j = d->array + asize; - i = x.d->array + asize; + j = p->array + asize; + i = x.p->array + asize; } else { // construct all new objects when growing - i = x.d->array + asize; - j = x.d->array + d->size; + i = x.p->array + asize; + j = x.p->array + d->size; while (i != j) new (--i) T; - j = d->array + d->size; + j = p->array + d->size; } if (i != j) { // copy objects from the old array into the new array - b = x.d->array; + b = x.p->array; while (i != b) new (--i) T(*--j); } } else if (asize > d->size) { // initialize newly allocated memory to 0 - qMemSet(x.d->array + d->size, 0, (asize - d->size) * sizeof(T)); + qMemSet(x.p->array + d->size, 0, (asize - d->size) * sizeof(T)); } x.d->size = asize; x.d->alloc = aalloc; if (d != x.d) { if (!d->ref.deref()) - free(d); + free(p); d = x.d; } } @@ -506,15 +496,15 @@ void QVector<T>::realloc(int asize, int aalloc) template<typename T> Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const { - if (i < 0 || i >= p->size) { + if (i < 0 || i >= d->size) { return T(); } - return d->array[i]; + return p->array[i]; } template<typename T> Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const { - return ((i < 0 || i >= p->size) ? defaultValue : d->array[i]); + return ((i < 0 || i >= d->size) ? defaultValue : p->array[i]); } template <typename T> @@ -525,14 +515,14 @@ void QVector<T>::append(const T &t) realloc(d->size, QVectorData::grow(sizeOfTypedData(), d->size + 1, sizeof(T), QTypeInfo<T>::isStatic)); if (QTypeInfo<T>::isComplex) - new (d->array + d->size) T(copy); + new (p->array + d->size) T(copy); else - d->array[d->size] = copy; + p->array[d->size] = copy; } else { if (QTypeInfo<T>::isComplex) - new (d->array + d->size) T(t); + new (p->array + d->size) T(t); else - d->array[d->size] = t; + p->array[d->size] = t; } ++d->size; } @@ -540,27 +530,27 @@ void QVector<T>::append(const T &t) template <typename T> Q_TYPENAME QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t) { - int offset = before - d->array; + int offset = before - p->array; if (n != 0) { const T copy(t); if (d->ref != 1 || d->size + n > d->alloc) realloc(d->size, QVectorData::grow(sizeOfTypedData(), d->size + n, sizeof(T), QTypeInfo<T>::isStatic)); if (QTypeInfo<T>::isStatic) { - T *b = d->array + d->size; - T *i = d->array + d->size + n; + T *b = p->array + d->size; + T *i = p->array + d->size + n; while (i != b) new (--i) T; - i = d->array + d->size; + i = p->array + d->size; T *j = i + n; - b = d->array + offset; + b = p->array + offset; while (i != b) *--j = *--i; i = b+n; while (i != b) *--i = copy; } else { - T *b = d->array + offset; + T *b = p->array + offset; T *i = b + n; memmove(i, b, (d->size - offset) * sizeof(T)); while (i != b) @@ -568,29 +558,29 @@ Q_TYPENAME QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, } d->size += n; } - return d->array + offset; + return p->array + offset; } template <typename T> Q_TYPENAME QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend) { - int f = abegin - d->array; - int l = aend - d->array; + int f = abegin - p->array; + int l = aend - p->array; int n = l - f; detach(); if (QTypeInfo<T>::isComplex) { - qCopy(d->array+l, d->array+d->size, d->array+f); - T *i = d->array+d->size; - T* b = d->array+d->size-n; + qCopy(p->array+l, p->array+d->size, p->array+f); + T *i = p->array+d->size; + T* b = p->array+d->size-n; while (i != b) { --i; i->~T(); } } else { - memmove(d->array + f, d->array + l, (d->size-l)*sizeof(T)); + memmove(p->array + f, p->array + l, (d->size-l)*sizeof(T)); } d->size -= n; - return d->array + f; + return p->array + f; } template <typename T> @@ -600,9 +590,9 @@ bool QVector<T>::operator==(const QVector<T> &v) const return false; if (d == v.d) return true; - T* b = d->array; + T* b = p->array; T* i = b + d->size; - T* j = v.d->array + d->size; + T* j = v.p->array + d->size; while (i != b) if (!(*--i == *--j)) return false; @@ -615,8 +605,8 @@ QVector<T> &QVector<T>::fill(const T &from, int asize) const T copy(from); resize(asize < 0 ? d->size : asize); if (d->size) { - T *i = d->array + d->size; - T *b = d->array; + T *i = p->array + d->size; + T *b = p->array; while (i != b) *--i = copy; } @@ -629,9 +619,9 @@ QVector<T> &QVector<T>::operator+=(const QVector &l) int newSize = d->size + l.d->size; realloc(d->size, newSize); - T *w = d->array + newSize; - T *i = l.d->array + l.d->size; - T *b = l.d->array; + T *w = p->array + newSize; + T *i = l.p->array + l.d->size; + T *b = l.p->array; while (i != b) { if (QTypeInfo<T>::isComplex) new (--w) T(*--i); @@ -648,11 +638,11 @@ int QVector<T>::indexOf(const T &t, int from) const if (from < 0) from = qMax(from + d->size, 0); if (from < d->size) { - T* n = d->array + from - 1; - T* e = d->array + d->size; + T* n = p->array + from - 1; + T* e = p->array + d->size; while (++n != e) if (*n == t) - return n - d->array; + return n - p->array; } return -1; } @@ -665,8 +655,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const else if (from >= d->size) from = d->size-1; if (from >= 0) { - T* b = d->array; - T* n = d->array + from + 1; + T* b = p->array; + T* n = p->array + from + 1; while (n != b) { if (*--n == t) return n - b; @@ -678,8 +668,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const template <typename T> bool QVector<T>::contains(const T &t) const { - T* b = d->array; - T* i = d->array + d->size; + T* b = p->array; + T* i = p->array + d->size; while (i != b) if (*--i == t) return true; @@ -690,8 +680,8 @@ template <typename T> int QVector<T>::count(const T &t) const { int c = 0; - T* b = d->array; - T* i = d->array + d->size; + T* b = p->array; + T* i = p->array + d->size; while (i != b) if (*--i == t) ++c; diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index e5bf7e4..aea0c6c 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -11,6 +11,7 @@ HEADERS += \ tools/qcryptographichash.h \ tools/qdatetime.h \ tools/qdatetime_p.h \ + tools/qeasingcurve.h \ tools/qhash.h \ tools/qline.h \ tools/qlinkedlist.h \ @@ -19,6 +20,7 @@ HEADERS += \ tools/qlocale_p.h \ tools/qlocale_data_p.h \ tools/qmap.h \ + tools/qcontiguouscache.h \ tools/qpodlist_p.h \ tools/qpoint.h \ tools/qqueue.h \ @@ -30,6 +32,7 @@ HEADERS += \ tools/qsize.h \ tools/qstack.h \ tools/qstring.h \ + tools/qstringbuilder.h \ tools/qstringlist.h \ tools/qstringmatcher.h \ tools/qtextboundaryfinder.h \ @@ -45,7 +48,7 @@ SOURCES += \ tools/qbytearraymatcher.cpp \ tools/qcryptographichash.cpp \ tools/qdatetime.cpp \ - tools/qdumper.cpp \ + tools/qeasingcurve.cpp \ tools/qhash.cpp \ tools/qline.cpp \ tools/qlinkedlist.cpp \ @@ -53,12 +56,14 @@ SOURCES += \ tools/qlocale.cpp \ tools/qpoint.cpp \ tools/qmap.cpp \ + tools/qcontiguouscache.cpp \ tools/qrect.cpp \ tools/qregexp.cpp \ tools/qshareddata.cpp \ tools/qsharedpointer.cpp \ tools/qsize.cpp \ tools/qstring.cpp \ + tools/qstringbuilder.cpp \ tools/qstringlist.cpp \ tools/qtextboundaryfinder.cpp \ tools/qtimeline.cpp \ diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index ff1a01f..5e1fec3 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -3058,7 +3058,7 @@ QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNa QString s; int n = ++namespacePrefixCount; forever { - s = QLatin1String("n") + QString::number(n++); + s = QLatin1Char('n') + QString::number(n++); int j = namespaceDeclarations.size() - 2; while (j >= 0 && namespaceDeclarations.at(j).prefix != s) --j; diff --git a/src/dbus/qdbuserror.cpp b/src/dbus/qdbuserror.cpp index 955a31c..2347a54 100644 --- a/src/dbus/qdbuserror.cpp +++ b/src/dbus/qdbuserror.cpp @@ -339,7 +339,7 @@ QString QDBusError::errorString(ErrorType error) #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug dbg, const QDBusError &msg) { - dbg.nospace() << "QDBusError(" << msg.name() << ", " << msg.message() << ")"; + dbg.nospace() << "QDBusError(" << msg.name() << ", " << msg.message() << ')'; return dbg.space(); } #endif diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 2c27381..33f44ab 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -74,7 +74,7 @@ static inline QDebug operator<<(QDebug dbg, const QThread *th) dbg.nospace() << "QThread(ptr=" << (void*)th; if (th && !th->objectName().isEmpty()) dbg.nospace() << ", name=" << th->objectName(); - dbg.nospace() << ")"; + dbg.nospace() << ')'; return dbg.space(); } @@ -90,7 +90,7 @@ static inline QDebug operator<<(QDebug dbg, const QDBusConnectionPrivate *conn) dbg.nospace() << "same thread"; else dbg.nospace() << conn->thread(); - dbg.nospace() << ")"; + dbg.nospace() << ')'; return dbg.space(); } @@ -565,7 +565,7 @@ static void huntAndEmit(DBusConnection *connection, DBusMessage *msg, QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack.children.constBegin(); QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack.children.constEnd(); for ( ; it != end; ++it) - huntAndEmit(connection, msg, needle, *it, isScriptable, isAdaptor, path + QLatin1String("/") + it->name); + huntAndEmit(connection, msg, needle, *it, isScriptable, isAdaptor, path + QLatin1Char('/') + it->name); if (needle == haystack.obj) { // is this a signal we should relay? @@ -1125,12 +1125,7 @@ void QDBusConnectionPrivate::objectDestroyed(QObject *obj) void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, int signalId, const QVariantList &args) { - int mciid = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE); - Q_ASSERT(mciid != -1); - - QMetaClassInfo mci = mo->classInfo(mciid); - Q_ASSERT(mci.value()); - const char *interface = mci.value(); + QString interface = qDBusInterfaceFromMetaObject(mo); QMetaMethod mm = mo->method(signalId); QByteArray memberName = mm.signature(); @@ -1146,12 +1141,12 @@ void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, in } QDBusReadLocker locker(RelaySignalAction, this); - QDBusMessage message = QDBusMessage::createSignal(QLatin1String("/"), QLatin1String(interface), + QDBusMessage message = QDBusMessage::createSignal(QLatin1String("/"), interface, QLatin1String(memberName)); message.setArguments(args); DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message); if (!msg) { - qWarning("QDBusConnection: Could not emit signal %s.%s", interface, memberName.constData()); + qWarning("QDBusConnection: Could not emit signal %s.%s", qPrintable(interface), memberName.constData()); return; } diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index 8eb8b1a..ce76ecc 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -601,7 +601,7 @@ QDBusMetaObject *QDBusMetaObject::createMetaObject(const QString &interface, con // mark as an error error = QDBusError(QDBusError::UnknownInterface, - QString( QLatin1String("Interface '%1' was not found") ) + QString::fromLatin1("Interface '%1' was not found") .arg(interface)); return 0; } diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp index 9753bbe..955f4a0 100644 --- a/src/dbus/qdbuspendingcall.cpp +++ b/src/dbus/qdbuspendingcall.cpp @@ -432,9 +432,14 @@ inline void QDBusPendingCallWatcherPrivate::_q_finished() QDBusPendingCallWatcher::QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent) : QObject(*new QDBusPendingCallWatcherPrivate, parent), QDBusPendingCall(call) { - if (d) { - if (!d->watcherHelper) + if (d) { // QDBusPendingCall::d + if (!d->watcherHelper) { d->watcherHelper = new QDBusPendingCallWatcherHelper; + if (isFinished()) { + // cause a signal emission anyways + QMetaObject::invokeMethod(d->watcherHelper, "finished", Qt::QueuedConnection); + } + } d->watcherHelper->add(this); } } @@ -464,6 +469,7 @@ void QDBusPendingCallWatcher::waitForFinished() d->waitForFinished(); // our signals were queued, so deliver them + QCoreApplication::sendPostedEvents(d->watcherHelper, QEvent::MetaCall); QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); } } diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp index 471b899..dd983a0 100644 --- a/src/dbus/qdbusutil.cpp +++ b/src/dbus/qdbusutil.cpp @@ -80,15 +80,15 @@ static bool variantToString(const QVariant &arg, QString &out) int argType = arg.userType(); if (argType == QVariant::StringList) { - out += QLatin1String("{"); + out += QLatin1Char('{'); QStringList list = arg.toStringList(); foreach (QString item, list) out += QLatin1Char('\"') + item + QLatin1String("\", "); if (!list.isEmpty()) out.chop(2); - out += QLatin1String("}"); + out += QLatin1Char('}'); } else if (argType == QVariant::ByteArray) { - out += QLatin1String("{"); + out += QLatin1Char('{'); QByteArray list = arg.toByteArray(); for (int i = 0; i < list.count(); ++i) { out += QString::number(list.at(i)); @@ -96,9 +96,9 @@ static bool variantToString(const QVariant &arg, QString &out) } if (!list.isEmpty()) out.chop(2); - out += QLatin1String("}"); + out += QLatin1Char('}'); } else if (argType == QVariant::List) { - out += QLatin1String("{"); + out += QLatin1Char('{'); QList<QVariant> list = arg.toList(); foreach (QVariant item, list) { if (!variantToString(item, out)) @@ -107,7 +107,7 @@ static bool variantToString(const QVariant &arg, QString &out) } if (!list.isEmpty()) out.chop(2); - out += QLatin1String("}"); + out += QLatin1Char('}'); } else if (argType == QMetaType::Char || argType == QMetaType::Short || argType == QMetaType::Int || argType == QMetaType::Long || argType == QMetaType::LongLong) { out += QString::number(arg.toLongLong()); @@ -142,7 +142,7 @@ static bool variantToString(const QVariant &arg, QString &out) return false; out += QLatin1Char(']'); } else if (arg.canConvert(QVariant::String)) { - out += QLatin1String("\"") + arg.toString() + QLatin1String("\""); + out += QLatin1Char('\"') + arg.toString() + QLatin1Char('\"'); } else { out += QLatin1Char('['); out += QLatin1String(arg.typeName()); @@ -226,7 +226,7 @@ bool argToString(const QDBusArgument &busArg, QString &out) if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType && elementType != QDBusArgument::MapEntryType) - out += QLatin1String("]"); + out += QLatin1Char(']'); return true; } diff --git a/src/gui/accessible/qaccessiblewidget.cpp b/src/gui/accessible/qaccessiblewidget.cpp index 753ac57..1c2fcef 100644 --- a/src/gui/accessible/qaccessiblewidget.cpp +++ b/src/gui/accessible/qaccessiblewidget.cpp @@ -102,24 +102,7 @@ static QString buddyString(const QWidget *widget) QString Q_GUI_EXPORT qt_accStripAmp(const QString &text) { - if (text.isEmpty()) - return text; - - const QChar *ch = text.unicode(); - int length = text.length(); - QString str; - while (length > 0) { - if (*ch == QLatin1Char('&')) { - ++ch; - --length; - if (!ch) - --ch; - } - str += *ch; - ++ch; - --length; - } - return str; + return QString(text).remove(QLatin1Char('&')); } QString Q_GUI_EXPORT qt_accHotKey(const QString &text) diff --git a/src/gui/animation/animation.pri b/src/gui/animation/animation.pri new file mode 100644 index 0000000..27763ca --- /dev/null +++ b/src/gui/animation/animation.pri @@ -0,0 +1,3 @@ +# Qt gui animation module + +SOURCES += animation/qguivariantanimation.cpp diff --git a/src/gui/animation/qguivariantanimation.cpp b/src/gui/animation/qguivariantanimation.cpp new file mode 100644 index 0000000..37ca6a1 --- /dev/null +++ b/src/gui/animation/qguivariantanimation.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_ANIMATION + +#include <QtCore/qvariantanimation.h> +#include <private/qvariantanimation_p.h> + +#include <QtGui/qcolor.h> + +QT_BEGIN_NAMESPACE + +template<> Q_INLINE_TEMPLATE QColor _q_interpolate(const QColor &f,const QColor &t, qreal progress) +{ + return QColor(_q_interpolate(f.red(), t.red(), progress), + _q_interpolate(f.green(), t.green(), progress), + _q_interpolate(f.blue(), t.blue(), progress), + _q_interpolate(f.alpha(), t.alpha(), progress)); +} + +static int qRegisterGuiGetInterpolator() +{ + qRegisterAnimationInterpolator<QColor>(_q_interpolateVariant<QColor>); + return 1; +} +Q_CONSTRUCTOR_FUNCTION(qRegisterGuiGetInterpolator) + +static int qUnregisterGuiGetInterpolator() +{ + qRegisterAnimationInterpolator<QColor>(0); + return 1; +} +Q_DESTRUCTOR_FUNCTION(qUnregisterGuiGetInterpolator) + +QT_END_NAMESPACE + +#endif //QT_NO_ANIMATION diff --git a/src/gui/dialogs/qabstractprintdialog.cpp b/src/gui/dialogs/qabstractprintdialog.cpp index 0dc16c9..5ed8852 100644 --- a/src/gui/dialogs/qabstractprintdialog.cpp +++ b/src/gui/dialogs/qabstractprintdialog.cpp @@ -400,7 +400,7 @@ void QAbstractPrintDialogPrivate::setPrinter(QPrinter *newPrinter) QAbstractPrintDialog::setEnabledOptions() and QAbstractPrintDialog::addEnabledOption() have no effect. - In Qt 4.4, it was possible to use the satic functions to show a sheet on + In Qt 4.4, it was possible to use the static functions to show a sheet on Mac OS X. This is no longer supported in Qt 4.5. If you want this functionality, use QPrintDialog::open(). diff --git a/src/gui/dialogs/qcolordialog.cpp b/src/gui/dialogs/qcolordialog.cpp index e06d14a..7e885da 100644 --- a/src/gui/dialogs/qcolordialog.cpp +++ b/src/gui/dialogs/qcolordialog.cpp @@ -1578,10 +1578,11 @@ void QColorDialog::setCurrentColor(const QColor &color) { Q_D(QColorDialog); d->setCurrentColor(color.rgb()); - d->selectColor(color.rgb()); + d->selectColor(color); d->setCurrentAlpha(color.alpha()); #ifdef Q_WS_MAC + d->setCurrentQColor(color); if (d->delegate) QColorDialogPrivate::setColor(d->delegate, color); #endif diff --git a/src/gui/dialogs/qcolordialog_mac.mm b/src/gui/dialogs/qcolordialog_mac.mm index 2556265..9862c1c 100644 --- a/src/gui/dialogs/qcolordialog_mac.mm +++ b/src/gui/dialogs/qcolordialog_mac.mm @@ -234,16 +234,22 @@ QT_USE_NAMESPACE CGFloat cyan, magenta, yellow, black, alpha; [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha]; mQtColor->setCmykF(cyan, magenta, yellow, black, alpha); + } else if (colorSpace == NSCalibratedRGBColorSpace || colorSpace == NSDeviceRGBColorSpace) { + CGFloat red, green, blue, alpha; + [color getRed:&red green:&green blue:&blue alpha:&alpha]; + mQtColor->setRgbF(red, green, blue, alpha); } else { - NSColor *tmpColor; - if (colorSpace == NSCalibratedRGBColorSpace || colorSpace == NSDeviceRGBColorSpace) { - tmpColor = color; + NSColorSpace *colorSpace = [color colorSpace]; + if ([colorSpace colorSpaceModel] == NSCMYKColorSpaceModel && [color numberOfComponents] == 5){ + CGFloat components[5]; + [color getComponents:components]; + mQtColor->setCmykF(components[0], components[1], components[2], components[3], components[4]); } else { - tmpColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; + NSColor *tmpColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; + CGFloat red, green, blue, alpha; + [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha]; + mQtColor->setRgbF(red, green, blue, alpha); } - CGFloat red, green, blue, alpha; - [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha]; - mQtColor->setRgbF(red, green, blue, alpha); } if (mPriv) @@ -414,10 +420,20 @@ void QColorDialogPrivate::setColor(void *delegate, const QColor &color) { QMacCocoaAutoReleasePool pool; QCocoaColorPanelDelegate *theDelegate = static_cast<QCocoaColorPanelDelegate *>(delegate); - NSColor *nsColor = [NSColor colorWithCalibratedRed:color.red() / 255.0 - green:color.green() / 255.0 - blue:color.blue() / 255.0 - alpha:color.alpha() / 255.0]; + NSColor *nsColor; + const QColor::Spec spec = color.spec(); + if (spec == QColor::Cmyk) { + nsColor = [NSColor colorWithDeviceCyan:color.cyanF() + magenta:color.magentaF() + yellow:color.yellowF() + black:color.blackF() + alpha:color.alphaF()]; + } else { + nsColor = [NSColor colorWithCalibratedRed:color.redF() + green:color.greenF() + blue:color.blueF() + alpha:color.alphaF()]; + } [[theDelegate colorPanel] setColor:nsColor]; } diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index 044aa43..56b89f0 100644 --- a/src/gui/dialogs/qfiledialog.cpp +++ b/src/gui/dialogs/qfiledialog.cpp @@ -776,6 +776,7 @@ void QFileDialog::selectFile(const QString &filename) } QModelIndex index = d->model->index(filename); + QString file; if (!index.isValid()) { // save as dialog where we want to input a default value QString text = filename; @@ -790,13 +791,13 @@ void QFileDialog::selectFile(const QString &filename) ) text = text.remove(0,1); } - if (!isVisible() || !d->lineEdit()->hasFocus()) - d->lineEdit()->setText(text); + file = text; } else { - d->qFileDialogUi->listView->selectionModel()->clear(); - if (!isVisible() || !d->lineEdit()->hasFocus()) - d->lineEdit()->setText(index.data().toString()); + file = index.data().toString(); } + d->qFileDialogUi->listView->selectionModel()->clear(); + if (!isVisible() || !d->lineEdit()->hasFocus()) + d->lineEdit()->setText(file); } /** @@ -837,8 +838,8 @@ QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList filesT // This check is needed since we might be at the root directory // and on Windows it already ends with slash. QString path = rootPath(); - if (!path.endsWith(QLatin1String("/"))) - path += QLatin1String("/"); + if (!path.endsWith(QLatin1Char('/'))) + path += QLatin1Char('/'); path += name; files.append(path); } @@ -2142,7 +2143,6 @@ void QFileDialogPrivate::createWidgets() #ifndef QT_NO_COMPLETER completer = new QFSCompletor(model, q); qFileDialogUi->fileNameEdit->setCompleter(completer); - completer->sourceModel = model; QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)), q, SLOT(_q_autoCompleteFileName(QString))); #endif // QT_NO_COMPLETER @@ -2650,7 +2650,7 @@ void QFileDialogPrivate::_q_deleteCurrent() void QFileDialogPrivate::_q_autoCompleteFileName(const QString &text) { - if (text.startsWith(QLatin1String("//")) || text.startsWith(QLatin1String("\\"))) { + if (text.startsWith(QLatin1String("//")) || text.startsWith(QLatin1Char('\\'))) { qFileDialogUi->listView->selectionModel()->clearSelection(); return; } @@ -2692,7 +2692,7 @@ void QFileDialogPrivate::_q_updateOkButton() QStringList files = q->selectedFiles(); QString lineEditText = lineEdit()->text(); - if (lineEditText.startsWith(QLatin1String("//")) || lineEditText.startsWith(QLatin1String("\\"))) { + if (lineEditText.startsWith(QLatin1String("//")) || lineEditText.startsWith(QLatin1Char('\\'))) { button->setEnabled(true); if (acceptMode == QFileDialog::AcceptSave) button->setText(isOpenDirectory ? QFileDialog::tr("&Open") : acceptLabel); @@ -3198,7 +3198,7 @@ QStringList QFSCompletor::splitPath(const QString &path) const doubleSlash.clear(); #endif - QRegExp re(QLatin1String("[") + QRegExp::escape(sep) + QLatin1String("]")); + QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']')); #ifdef Q_OS_WIN QStringList parts = pathCopy.split(re, QString::SkipEmptyParts); diff --git a/src/gui/dialogs/qfiledialog_p.h b/src/gui/dialogs/qfiledialog_p.h index dc24390..ab4199e 100644 --- a/src/gui/dialogs/qfiledialog_p.h +++ b/src/gui/dialogs/qfiledialog_p.h @@ -97,7 +97,7 @@ class Ui_QFileDialog; */ class QFSCompletor : public QCompleter { public: - QFSCompletor(QAbstractItemModel *model, QObject *parent = 0) : QCompleter(model, parent), proxyModel(0), sourceModel(0) + QFSCompletor(QFileSystemModel *model, QObject *parent = 0) : QCompleter(model, parent), proxyModel(0), sourceModel(model) { #ifdef Q_OS_WIN setCaseSensitivity(Qt::CaseInsensitive); diff --git a/src/gui/dialogs/qfiledialog_win.cpp b/src/gui/dialogs/qfiledialog_win.cpp index 6962674..75a1820 100644 --- a/src/gui/dialogs/qfiledialog_win.cpp +++ b/src/gui/dialogs/qfiledialog_win.cpp @@ -214,10 +214,10 @@ static OPENFILENAMEA *qt_win_make_OFNA(QWidget *parent, aInitSel = ""; } else { aInitSel = QDir::toNativeSeparators(initialSelection).toLocal8Bit(); - aInitSel.replace("<", ""); - aInitSel.replace(">", ""); - aInitSel.replace("\"", ""); - aInitSel.replace("|", ""); + aInitSel.replace('<', ""); + aInitSel.replace('>', ""); + aInitSel.replace('\"', ""); + aInitSel.replace('|', ""); } int maxLen = mode == QFileDialog::ExistingFiles ? maxMultiLen : maxNameLen; aInitSel.resize(maxLen + 1); // make room for return value @@ -286,10 +286,10 @@ static OPENFILENAME* qt_win_make_OFN(QWidget *parent, tTitle = title; QString initSel = QDir::toNativeSeparators(initialSelection); if (!initSel.isEmpty()) { - initSel.replace(QLatin1String("<"), QLatin1String("")); - initSel.replace(QLatin1String(">"), QLatin1String("")); - initSel.replace(QLatin1String("\""), QLatin1String("")); - initSel.replace(QLatin1String("|"), QLatin1String("")); + initSel.remove(QLatin1Char('<')); + initSel.remove(QLatin1Char('>')); + initSel.remove(QLatin1Char('\"')); + initSel.remove(QLatin1Char('|')); } int maxLen = mode == QFileDialog::ExistingFiles ? maxMultiLen : maxNameLen; @@ -811,7 +811,7 @@ QString qt_win_get_existing_directory(const QFileDialogArgs &args) QDir::setCurrent(currentDir); if (!result.isEmpty()) - result.replace(QLatin1String("\\"), QLatin1String("/")); + result.replace(QLatin1Char('\\'), QLatin1Char('/')); return result; } diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index 012d3a1..825f8b6 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -337,7 +337,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS { Q_Q(const QFileSystemModel); Q_UNUSED(q); - if (path.isEmpty() || path == myComputer() || path.startsWith(QLatin1String(":"))) + if (path.isEmpty() || path == myComputer() || path.startsWith(QLatin1Char(':'))) return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root); // Construct the nodes up to the new root path if they need to be built diff --git a/src/gui/dialogs/qfontdialog.cpp b/src/gui/dialogs/qfontdialog.cpp index d8a2c7c..c7484e7 100644 --- a/src/gui/dialogs/qfontdialog.cpp +++ b/src/gui/dialogs/qfontdialog.cpp @@ -337,6 +337,14 @@ void QFontDialogPrivate::init() QFontDialog::~QFontDialog() { +#ifdef Q_WS_MAC + Q_D(QFontDialog); + if (d->delegate) { + QFontDialogPrivate::closeCocoaFontPanel(d->delegate); + QFontDialogPrivate::sharedFontPanelAvailable = true; + return; + } +#endif } /*! diff --git a/src/gui/dialogs/qfontdialog_mac.mm b/src/gui/dialogs/qfontdialog_mac.mm index 50917a1..3be53db 100644 --- a/src/gui/dialogs/qfontdialog_mac.mm +++ b/src/gui/dialogs/qfontdialog_mac.mm @@ -47,6 +47,7 @@ #include <private/qapplication_p.h> #include <private/qfont_p.h> #include <private/qfontengine_p.h> +#include <private/qt_cocoa_helpers_mac_p.h> #include <private/qt_mac_p.h> #include <qdebug.h> #import <AppKit/AppKit.h> @@ -123,16 +124,16 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) QFont newFont; if (cocoaFont) { int pSize = qRound([cocoaFont pointSize]); - QString family(QCFString::toQString(reinterpret_cast<CFStringRef>([cocoaFont familyName]))); - QString typeface(QCFString::toQString(reinterpret_cast<CFStringRef>([cocoaFont fontName]))); -// qDebug() << "original family" << family << "typeface" << typeface << "psize" << pSize; + QString family(qt_mac_NSStringToQString([cocoaFont familyName])); + QString typeface(qt_mac_NSStringToQString([cocoaFont fontName])); + int hyphenPos = typeface.indexOf(QLatin1Char('-')); if (hyphenPos != -1) { typeface.remove(0, hyphenPos + 1); } else { typeface = QLatin1String("Normal"); } -// qDebug() << " massaged family" << family << "typeface" << typeface << "psize" << pSize; + newFont = QFontDatabase().font(family, typeface, pSize); newFont.setUnderline(resolveFont.underline()); newFont.setStrikeOut(resolveFont.strikeOut()); @@ -566,6 +567,7 @@ void *QFontDialogPrivate::openCocoaFontPanel(const QFont &initial, void QFontDialogPrivate::closeCocoaFontPanel(void *delegate) { + QMacCocoaAutoReleasePool pool; QCocoaFontPanelDelegate *theDelegate = static_cast<QCocoaFontPanelDelegate *>(delegate); NSWindow *ourPanel = [theDelegate actualPanel]; [ourPanel close]; @@ -597,15 +599,37 @@ QFont QFontDialogPrivate::execCocoaFontPanel(bool *ok, const QFont &initial, } } -void QFontDialogPrivate::setFont(void * delegate, const QFont &font) +void QFontDialogPrivate::setFont(void *delegate, const QFont &font) { + QMacCocoaAutoReleasePool pool; QFontEngine *fe = font.d->engineForScript(QUnicodeTables::Common); + NSFontManager *mgr = [NSFontManager sharedFontManager]; + NSFont *nsFont = 0; + #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 if (qstrcmp(fe->name(), "CoreText") == 0) { - const NSFont *nsFont = reinterpret_cast<const NSFont *>(static_cast<QCoreTextFontEngineMulti *>(fe)->ctfont); - [[NSFontManager sharedFontManager] setSelectedFont:nsFont isMultiple:NO]; - } + nsFont = reinterpret_cast<const NSFont *>(static_cast<QCoreTextFontEngineMulti *>(fe)->ctfont); + } else #endif + { + int weight = 5; + NSFontTraitMask mask = 0; + if (font.style() == QFont::StyleItalic) { + mask |= NSItalicFontMask; + } + if (font.weight() == QFont::Bold) { + weight = 9; + mask |= NSBoldFontMask; + } + + NSFontManager *mgr = [NSFontManager sharedFontManager]; + nsFont = [mgr fontWithFamily:qt_mac_QStringToNSString(font.family()) + traits:mask + weight:weight + size:font.pointSize()]; + } + + [mgr setSelectedFont:nsFont isMultiple:NO]; [static_cast<QCocoaFontPanelDelegate *>(delegate) setQtFont:font]; } diff --git a/src/gui/dialogs/qinputdialog.cpp b/src/gui/dialogs/qinputdialog.cpp index 78d99e3..8608334 100644 --- a/src/gui/dialogs/qinputdialog.cpp +++ b/src/gui/dialogs/qinputdialog.cpp @@ -307,8 +307,7 @@ void QInputDialogPrivate::ensureEnabledConnection(QAbstractSpinBox *spinBox) { if (spinBox) { QAbstractButton *okButton = buttonBox->button(QDialogButtonBox::Ok); - QObject::disconnect(spinBox, SIGNAL(textChanged(bool)), okButton, SLOT(setEnabled(bool))); - QObject::connect(spinBox, SIGNAL(textChanged(bool)), okButton, SLOT(setEnabled(bool))); + QObject::connect(spinBox, SIGNAL(textChanged(bool)), okButton, SLOT(setEnabled(bool)), Qt::UniqueConnection); } } diff --git a/src/gui/dialogs/qmessagebox.cpp b/src/gui/dialogs/qmessagebox.cpp index 3b622b7..1734e85 100644 --- a/src/gui/dialogs/qmessagebox.cpp +++ b/src/gui/dialogs/qmessagebox.cpp @@ -703,15 +703,10 @@ void QMessageBoxPrivate::_q_buttonClicked(QAbstractButton *button) Constructs a message box with no text and no buttons. \a parent is passed to the QDialog constructor. - If \a parent is 0, the message box is an \l{Qt::ApplicationModal} - {application modal} dialog box. If \a parent is a widget, the - message box is \l{Qt::WindowModal} {window modal} relative to \a - parent. - - On Mac OS X, if \a parent is not 0 and you want your message box - to appear as a Qt::Sheet of that parent, set the message box's - \l{setWindowModality()} {window modality} to Qt::WindowModal - (default). Otherwise, the message box will be a standard dialog. + On Mac OS X, if you want your message box to appear + as a Qt::Sheet of its \a parent, set the message box's + \l{setWindowModality()} {window modality} to Qt::WindowModal or use open(). + Otherwise, the message box will be a standard dialog. */ QMessageBox::QMessageBox(QWidget *parent) @@ -1315,7 +1310,7 @@ void QMessageBox::keyPressEvent(QKeyEvent *e) if (e == QKeySequence::Copy) { QString separator = QString::fromLatin1("---------------------------\n"); QString textToCopy = separator; - separator.prepend(QLatin1String("\n")); + separator.prepend(QLatin1Char('\n')); textToCopy += windowTitle() + separator; // title textToCopy += d->label->text() + separator; // text @@ -1689,10 +1684,13 @@ void QMessageBox::aboutQt(QWidget *parent, const QString &title) } #endif - QString translatedTextAboutQt; - translatedTextAboutQt = QMessageBox::tr( + QString translatedTextAboutQtCaption; + translatedTextAboutQtCaption = QMessageBox::tr( "<h3>About Qt</h3>" "<p>This program uses Qt version %1.</p>" + ).arg(QLatin1String(QT_VERSION_STR)); + QString translatedTextAboutQtText; + translatedTextAboutQtText = QMessageBox::tr( "<p>Qt is a C++ toolkit for cross-platform application " "development.</p>" "<p>Qt provides single-source portability across MS Windows, " @@ -1720,12 +1718,12 @@ void QMessageBox::aboutQt(QWidget *parent, const QString &title) "<p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p>" "<p>Qt is a Nokia product. See <a href=\"http://www.qtsoftware.com/qt/\">www.qtsoftware.com/qt</a> " "for more information.</p>" - ).arg(QLatin1String(QT_VERSION_STR)); - + ); QMessageBox *msgBox = new QMessageBox(parent); msgBox->setAttribute(Qt::WA_DeleteOnClose); msgBox->setWindowTitle(title.isEmpty() ? tr("About Qt") : title); - msgBox->setText(translatedTextAboutQt); + msgBox->setText(translatedTextAboutQtCaption); + msgBox->setInformativeText(translatedTextAboutQtText); QPixmap pm(QLatin1String(":/trolltech/qmessagebox/images/qtlogo-64.png")); if (!pm.isNull()) diff --git a/src/gui/dialogs/qmessagebox.h b/src/gui/dialogs/qmessagebox.h index 8d9b9fa..c6fb3bc 100644 --- a/src/gui/dialogs/qmessagebox.h +++ b/src/gui/dialogs/qmessagebox.h @@ -191,6 +191,8 @@ public: static StandardButton information(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton); + // ### Qt 5: Replace Ok with Yes|No in question() function. + // Also consider if Ok == Yes and Cancel == No. static StandardButton question(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton); diff --git a/src/gui/dialogs/qpagesetupdialog.cpp b/src/gui/dialogs/qpagesetupdialog.cpp index 63775d2..682071a 100644 --- a/src/gui/dialogs/qpagesetupdialog.cpp +++ b/src/gui/dialogs/qpagesetupdialog.cpp @@ -180,6 +180,12 @@ void QPageSetupDialog::open(QObject *receiver, const char *member) QDialog::open(); } +#if defined(Q_WS_MAC) || defined(Q_OS_WIN) +/*! \fn void QPageSetupDialog::setVisible(bool visible) + \reimp +*/ +#endif + QT_END_NAMESPACE #endif diff --git a/src/gui/dialogs/qpagesetupdialog_mac.mm b/src/gui/dialogs/qpagesetupdialog_mac.mm index 401d95f..24aef34 100644 --- a/src/gui/dialogs/qpagesetupdialog_mac.mm +++ b/src/gui/dialogs/qpagesetupdialog_mac.mm @@ -251,9 +251,6 @@ QPageSetupDialog::QPageSetupDialog(QWidget *parent) d->ep = static_cast<QMacPrintEngine *>(d->printer->paintEngine())->d_func(); } -/*! - \reimp -*/ void QPageSetupDialog::setVisible(bool visible) { Q_D(QPageSetupDialog); diff --git a/src/gui/dialogs/qprintdialog_unix.cpp b/src/gui/dialogs/qprintdialog_unix.cpp index 87a4e65..8456d13 100644 --- a/src/gui/dialogs/qprintdialog_unix.cpp +++ b/src/gui/dialogs/qprintdialog_unix.cpp @@ -669,7 +669,7 @@ QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p) for (int i = 0; i < cupsPrinterCount; ++i) { QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name)); if (cupsPrinters[i].instance) - printerName += QLatin1String("/") + QString::fromLocal8Bit(cupsPrinters[i].instance); + printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance); widget.printers->addItem(printerName); if (cupsPrinters[i].is_default) @@ -813,7 +813,7 @@ void QUnixPrintWidgetPrivate::_q_printerChanged(int index) optionsPane->selectPrinter(0); #endif if (lprPrinters.count() > 0) { - QString type = lprPrinters.at(index).name + QLatin1String("@") + lprPrinters.at(index).host; + QString type = lprPrinters.at(index).name + QLatin1Char('@') + lprPrinters.at(index).host; if (!lprPrinters.at(index).comment.isEmpty()) type += QLatin1String(", ") + lprPrinters.at(index).comment; widget.type->setText(type); @@ -1194,9 +1194,9 @@ QVariant QPPDOptionsModel::headerData(int section, Qt::Orientation, int role) co switch(section){ case 0: - return QVariant(QApplication::translate("QPPDOptionsModel","Name")); + return QVariant(QApplication::translate("QPPDOptionsModel", "Name")); case 1: - return QVariant(QApplication::translate("QPPDOptionsModel","Value")); + return QVariant(QApplication::translate("QPPDOptionsModel", "Value")); default: return QVariant(); } diff --git a/src/gui/dialogs/qprintpreviewdialog.cpp b/src/gui/dialogs/qprintpreviewdialog.cpp index c00bd14..a696160 100644 --- a/src/gui/dialogs/qprintpreviewdialog.cpp +++ b/src/gui/dialogs/qprintpreviewdialog.cpp @@ -54,6 +54,9 @@ #include <QtGui/qtoolbutton.h> #include <QtGui/qvalidator.h> #include <QtGui/qfiledialog.h> +#include <QtGui/qmainwindow.h> +#include <QtGui/qtoolbar.h> +#include <QtGui/qformlayout.h> #include <QtCore/QCoreApplication> #include <math.h> @@ -63,6 +66,13 @@ QT_BEGIN_NAMESPACE namespace { +class QPrintPreviewMainWindow : public QMainWindow +{ +public: + QPrintPreviewMainWindow(QWidget *parent) : QMainWindow(parent) {} + QMenu *createPopupMenu() { return 0; } +}; + class ZoomFactorValidator : public QDoubleValidator { public: @@ -197,7 +207,6 @@ public: QActionGroup *printerGroup; QAction *printAction; QAction *pageSetupAction; - QAction *closeAction; QPointer<QObject> receiverToDisconnectOnClose; QByteArray memberToDisconnectOnClose; @@ -219,27 +228,12 @@ void QPrintPreviewDialogPrivate::init(QPrinter *_printer) QObject::connect(preview, SIGNAL(previewChanged()), q, SLOT(_q_previewChanged())); setupActions(); - // Navigation - QToolButton* nextPageButton = new QToolButton; - nextPageButton->setDefaultAction(nextPageAction); - QToolButton* prevPageButton = new QToolButton; - prevPageButton->setDefaultAction(prevPageAction); - QToolButton* firstPageButton = new QToolButton; - firstPageButton->setDefaultAction(firstPageAction); - QToolButton* lastPageButton = new QToolButton; - lastPageButton->setDefaultAction(lastPageAction); - pageNumEdit = new LineEdit; pageNumEdit->setAlignment(Qt::AlignRight); - pageNumEdit->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding)); + pageNumEdit->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); pageNumLabel = new QLabel; QObject::connect(pageNumEdit, SIGNAL(editingFinished()), q, SLOT(_q_pageNumEdited())); - QToolButton* fitWidthButton = new QToolButton; - fitWidthButton->setDefaultAction(fitWidthAction); - QToolButton* fitPageButton = new QToolButton; - fitPageButton->setDefaultAction(fitPageAction); - zoomFactor = new QComboBox; zoomFactor->setEditable(true); zoomFactor->setMinimumContentsLength(7); @@ -255,77 +249,66 @@ void QPrintPreviewDialogPrivate::init(QPrinter *_printer) QObject::connect(zoomFactor, SIGNAL(currentIndexChanged(int)), q, SLOT(_q_zoomFactorChanged())); - QToolButton* zoomInButton = new QToolButton; - zoomInButton->setDefaultAction(zoomInAction); + QPrintPreviewMainWindow *mw = new QPrintPreviewMainWindow(q); + QToolBar *toolbar = new QToolBar(mw); + toolbar->addAction(fitWidthAction); + toolbar->addAction(fitPageAction); + toolbar->addSeparator(); + toolbar->addWidget(zoomFactor); + toolbar->addAction(zoomOutAction); + toolbar->addAction(zoomInAction); + toolbar->addSeparator(); + toolbar->addAction(portraitAction); + toolbar->addAction(landscapeAction); + toolbar->addSeparator(); + toolbar->addAction(firstPageAction); + toolbar->addAction(prevPageAction); + + // this is to ensure the label text and the editor text are + // aligned in all styles - the extra QVBoxLayout is a workaround + // for bug in QFormLayout + QWidget *pageEdit = new QWidget(toolbar); + QVBoxLayout *vboxLayout = new QVBoxLayout; + vboxLayout->setContentsMargins(0, 0, 0, 0); + QFormLayout *formLayout = new QFormLayout; + formLayout->setWidget(0, QFormLayout::LabelRole, pageNumEdit); + formLayout->setWidget(0, QFormLayout::FieldRole, pageNumLabel); + vboxLayout->addLayout(formLayout); + vboxLayout->setAlignment(Qt::AlignVCenter); + pageEdit->setLayout(vboxLayout); + toolbar->addWidget(pageEdit); + + toolbar->addAction(nextPageAction); + toolbar->addAction(lastPageAction); + toolbar->addSeparator(); + toolbar->addAction(singleModeAction); + toolbar->addAction(facingModeAction); + toolbar->addAction(overviewModeAction); + toolbar->addSeparator(); + toolbar->addAction(pageSetupAction); + toolbar->addAction(printAction); + + // Cannot use the actions' triggered signal here, since it doesn't autorepeat + QToolButton *zoomInButton = static_cast<QToolButton *>(toolbar->widgetForAction(zoomInAction)); + QToolButton *zoomOutButton = static_cast<QToolButton *>(toolbar->widgetForAction(zoomOutAction)); zoomInButton->setAutoRepeat(true); zoomInButton->setAutoRepeatInterval(200); zoomInButton->setAutoRepeatDelay(200); - - QToolButton* zoomOutButton = new QToolButton; - zoomOutButton->setDefaultAction(zoomOutAction); zoomOutButton->setAutoRepeat(true); zoomOutButton->setAutoRepeatInterval(200); zoomOutButton->setAutoRepeatDelay(200); - - //Cannot use the actions' triggered signal here, since it doesnt autorepeat QObject::connect(zoomInButton, SIGNAL(clicked()), q, SLOT(_q_zoomIn())); QObject::connect(zoomOutButton, SIGNAL(clicked()), q, SLOT(_q_zoomOut())); - QToolButton* portraitButton = new QToolButton; - portraitButton->setDefaultAction(portraitAction); - QToolButton* landscapeButton = new QToolButton; - landscapeButton->setDefaultAction(landscapeAction); - - QToolButton* singleModeButton = new QToolButton; - singleModeButton->setDefaultAction(singleModeAction); - QToolButton* facingModeButton = new QToolButton; - facingModeButton->setDefaultAction(facingModeAction); - QToolButton* overviewModeButton = new QToolButton; - overviewModeButton->setDefaultAction(overviewModeAction); - - QToolButton *printButton = new QToolButton; - printButton->setDefaultAction(printAction); - QToolButton *pageSetupButton = new QToolButton; - pageSetupButton->setDefaultAction(pageSetupAction); - QToolButton *closeButton = new QToolButton; - closeButton->setDefaultAction(closeAction); - - QHBoxLayout* modeLayout = new QHBoxLayout; - modeLayout->setSpacing(0); - modeLayout->addWidget(singleModeButton); - modeLayout->addWidget(facingModeButton); - modeLayout->addWidget(overviewModeButton); - - QHBoxLayout *barLayout = new QHBoxLayout; - barLayout->addWidget(fitWidthButton); - barLayout->addWidget(fitPageButton); - barLayout->addWidget(zoomFactor); - barLayout->addWidget(zoomOutButton); - barLayout->addWidget(zoomInButton); - barLayout->addWidget(portraitButton); - barLayout->addWidget(landscapeButton); - barLayout->addStretch(); - barLayout->addWidget(firstPageButton); - barLayout->addWidget(prevPageButton); - barLayout->addWidget(pageNumEdit); - barLayout->addWidget(pageNumLabel); - barLayout->addWidget(nextPageButton); - barLayout->addWidget(lastPageButton); - barLayout->addStretch(); - barLayout->addLayout(modeLayout); - barLayout->addStretch(); - barLayout->addWidget(pageSetupButton); - barLayout->addWidget(printButton); - barLayout->addWidget(closeButton); - - QWidget* buttonBar = new QWidget; - buttonBar->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum)); - barLayout->setMargin(0); - buttonBar->setLayout(barLayout); + mw->addToolBar(toolbar); + mw->setCentralWidget(preview); + // QMainWindows are always created as top levels, force it to be a + // plain widget + mw->setParent(q, Qt::Widget); QVBoxLayout *topLayout = new QVBoxLayout; - topLayout->addWidget(buttonBar); - topLayout->addWidget(preview); + topLayout->addWidget(mw); + topLayout->setMargin(0); q->setLayout(topLayout); QString caption = QCoreApplication::translate("QPrintPreviewDialog", "Print Preview"); @@ -338,7 +321,8 @@ void QPrintPreviewDialogPrivate::init(QPrinter *_printer) || printer->outputFormat() != QPrinter::NativeFormat #endif ) - pageSetupButton->setEnabled(false); + pageSetupAction->setEnabled(false); + preview->setFocus(); } static inline void qt_setupActionIcon(QAction *action, const QLatin1String &name) @@ -418,12 +402,10 @@ void QPrintPreviewDialogPrivate::setupActions() printerGroup = new QActionGroup(q); printAction = printerGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Print")); pageSetupAction = printerGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Page setup")); - closeAction = printerGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Close")); qt_setupActionIcon(printAction, QLatin1String("print")); qt_setupActionIcon(pageSetupAction, QLatin1String("page-setup")); QObject::connect(printAction, SIGNAL(triggered(bool)), q, SLOT(_q_print())); QObject::connect(pageSetupAction, SIGNAL(triggered(bool)), q, SLOT(_q_pageSetup())); - QObject::connect(closeAction, SIGNAL(triggered(bool)), q, SLOT(reject())); // Initial state: fitPageAction->setChecked(true); @@ -478,7 +460,7 @@ void QPrintPreviewDialogPrivate::updatePageNumLabel() int numPages = preview->numPages(); int maxChars = QString::number(numPages).length(); - pageNumLabel->setText(QString(QLatin1String("/ %1")).arg(numPages)); + pageNumLabel->setText(QString::fromLatin1("/ %1").arg(numPages)); int cyphersWidth = q->fontMetrics().width(QString().fill(QLatin1Char('8'), maxChars)); int maxWidth = pageNumEdit->minimumSizeHint().width() + cyphersWidth; pageNumEdit->setMinimumWidth(maxWidth); @@ -576,7 +558,7 @@ void QPrintPreviewDialogPrivate::_q_print() suffix = QLatin1String(".ps"); } QString fileName = QFileDialog::getSaveFileName(q, title, printer->outputFileName(), - QLatin1String("*") + suffix); + QLatin1Char('*') + suffix); if (!fileName.isEmpty()) { if (QFileInfo(fileName).suffix().isEmpty()) fileName.append(suffix); @@ -629,7 +611,7 @@ void QPrintPreviewDialogPrivate::_q_zoomFactorChanged() factor = qMax(qreal(1.0), qMin(qreal(1000.0), factor)); if (ok) { preview->setZoomFactor(factor/100.0); - zoomFactor->setEditText(QString(QLatin1String("%1%")).arg(factor)); + zoomFactor->setEditText(QString::fromLatin1("%1%").arg(factor)); setFitting(false); } } diff --git a/src/gui/dialogs/qsidebar.cpp b/src/gui/dialogs/qsidebar.cpp index 26108d7..000a06b 100644 --- a/src/gui/dialogs/qsidebar.cpp +++ b/src/gui/dialogs/qsidebar.cpp @@ -249,9 +249,9 @@ void QUrlModel::addUrls(const QList<QUrl> &list, int row, bool move) continue; for (int j = 0; move && j < rowCount(); ++j) { #if defined(Q_OS_WIN) - if (index(j, 0).data(UrlRole).toUrl().toLocalFile().toLower() == url.toLocalFile().toLower()) { + if (QDir::cleanPath(index(j, 0).data(UrlRole).toUrl().toLocalFile()).toLower() == QDir::cleanPath(url.toLocalFile()).toLower()) { #else - if (index(j, 0).data(UrlRole) == url) { + if (QDir::cleanPath(index(j, 0).data(UrlRole).toUrl().toLocalFile()) == QDir::cleanPath(url.toLocalFile())) { #endif removeRow(j); if (j <= row) diff --git a/src/gui/dialogs/qwizard.cpp b/src/gui/dialogs/qwizard.cpp index 6f2ab0a..b2ed983 100644 --- a/src/gui/dialogs/qwizard.cpp +++ b/src/gui/dialogs/qwizard.cpp @@ -1241,8 +1241,10 @@ void QWizardPrivate::updateMinMaxSizes(const QWizardLayoutInfo &info) #endif QSize minimumSize = mainLayout->totalMinimumSize() + QSize(0, extraHeight); QSize maximumSize; + bool skipMaxSize = false; #if defined(Q_WS_WIN) - if (QSysInfo::WindowsVersion > QSysInfo::WV_Me) // ### See Tasks 164078 and 161660 + if (QSysInfo::WindowsVersion <= QSysInfo::WV_Me) // ### See Tasks 164078 and 161660 + skipMaxSize = true; #endif maximumSize = mainLayout->totalMaximumSize(); if (info.header && headerWidget->maximumWidth() != QWIDGETSIZE_MAX) { @@ -1263,11 +1265,13 @@ void QWizardPrivate::updateMinMaxSizes(const QWizardLayoutInfo &info) } if (q->maximumWidth() == maximumWidth) { maximumWidth = maximumSize.width(); - q->setMaximumWidth(maximumWidth); + if (!skipMaxSize) + q->setMaximumWidth(maximumWidth); } if (q->maximumHeight() == maximumHeight) { maximumHeight = maximumSize.height(); - q->setMaximumHeight(maximumHeight); + if (!skipMaxSize) + q->setMaximumHeight(maximumHeight); } } @@ -1465,7 +1469,7 @@ void QWizardPrivate::handleAeroStyleChange() return; // prevent recursion inHandleAeroStyleChange = true; - vistaHelper->backButton()->disconnect(); + vistaHelper->disconnectBackButton(); q->removeEventFilter(vistaHelper); if (isVistaThemeEnabled()) { @@ -1491,7 +1495,7 @@ void QWizardPrivate::handleAeroStyleChange() q->setMouseTracking(true); // ### original value possibly different q->unsetCursor(); // ### ditto antiFlickerWidget->move(0, 0); - vistaHelper->backButton()->hide(); + vistaHelper->hideBackButton(); vistaHelper->setTitleBarIconAndCaptionVisible(true); } diff --git a/src/gui/dialogs/qwizard_win.cpp b/src/gui/dialogs/qwizard_win.cpp index 64696de..8aad4af 100644 --- a/src/gui/dialogs/qwizard_win.cpp +++ b/src/gui/dialogs/qwizard_win.cpp @@ -239,9 +239,11 @@ void QVistaBackButton::paintEvent(QPaintEvent *) QVistaHelper::QVistaHelper(QWizard *wizard) : pressed(false) , wizard(wizard) + , backButton_(0) { is_vista = resolveSymbols(); - backButton_ = new QVistaBackButton(wizard); + if (is_vista) + backButton_ = new QVistaBackButton(wizard); } QVistaHelper::~QVistaHelper() @@ -310,6 +312,7 @@ void QVistaHelper::drawTitleBar(QPainter *painter) QRect(0, 0, wizard->width(), titleBarSize() + topOffset()), painter->paintEngine()->getDC()); + Q_ASSERT(backButton_); const int btnTop = backButton_->mapToParent(QPoint()).y(); const int btnHeight = backButton_->size().height(); const int verticalCenter = (btnTop + btnHeight / 2); diff --git a/src/gui/dialogs/qwizard_win_p.h b/src/gui/dialogs/qwizard_win_p.h index cbb3b17..148be26 100644 --- a/src/gui/dialogs/qwizard_win_p.h +++ b/src/gui/dialogs/qwizard_win_p.h @@ -94,6 +94,8 @@ public: void resizeEvent(QResizeEvent *event); void paintEvent(QPaintEvent *event); QVistaBackButton *backButton() const { return backButton_; } + void disconnectBackButton() { if (backButton_) backButton_->disconnect(); } + void hideBackButton() { if (backButton_) backButton_->hide(); } void setWindowPosHack(); QColor basicWindowFrameColor(); enum VistaState { VistaAero, VistaBasic, Classic, Dirty }; diff --git a/src/gui/embedded/qkbdtty_qws.cpp b/src/gui/embedded/qkbdtty_qws.cpp index 5c0dec8..7f10e14 100644 --- a/src/gui/embedded/qkbdtty_qws.cpp +++ b/src/gui/embedded/qkbdtty_qws.cpp @@ -89,6 +89,7 @@ private: struct termios m_tty_attr; char m_last_keycode; int m_vt_qws; + int m_originalKbdMode; }; @@ -150,6 +151,9 @@ QWSTtyKbPrivate::QWSTtyKbPrivate(QWSTtyKeyboardHandler *h, const QString &device tcgetattr(m_tty_fd, &termdata); #if defined(Q_OS_LINUX) + // record the original mode so we can restore it again in the constructor + ::ioctl(m_tty_fd, KDGKBMODE, m_originalKbdMode); + // PLEASE NOTE: // The tty keycode interface can only report keycodes 0x01 .. 0x7f // KEY_MAX is however defined to 0x1ff. In practice this is sufficient @@ -206,7 +210,7 @@ QWSTtyKbPrivate::~QWSTtyKbPrivate() { if (m_tty_fd >= 0) { #if defined(Q_OS_LINUX) - ::ioctl(m_tty_fd, KDSKBMODE, K_XLATE); + ::ioctl(m_tty_fd, KDSKBMODE, m_originalKbdMode); #endif tcsetattr(m_tty_fd, TCSANOW, &m_tty_attr); } diff --git a/src/gui/embedded/qmouse_qws.cpp b/src/gui/embedded/qmouse_qws.cpp index 044a574..b5eda0c 100644 --- a/src/gui/embedded/qmouse_qws.cpp +++ b/src/gui/embedded/qmouse_qws.cpp @@ -413,8 +413,8 @@ void QWSCalibratedMouseHandler::writeCalibration() QFile file(calFile); if (file.open(QIODevice::WriteOnly)) { QTextStream t(&file); - t << a << " " << b << " " << c << " "; - t << d << " " << e << " " << f << " " << s << endl; + t << a << ' ' << b << ' ' << c << ' '; + t << d << ' ' << e << ' ' << f << ' ' << s << endl; } else #endif { diff --git a/src/gui/embedded/qscreen_qws.cpp b/src/gui/embedded/qscreen_qws.cpp index ff48403..91121e7 100644 --- a/src/gui/embedded/qscreen_qws.cpp +++ b/src/gui/embedded/qscreen_qws.cpp @@ -49,6 +49,7 @@ #include "qpixmap.h" #include "qvarlengtharray.h" #include "qwsdisplay_qws.h" +#include "qpainter.h" #include <private/qdrawhelper_p.h> #include <private/qpaintengine_raster_p.h> #include <private/qpixmap_raster_p.h> @@ -1396,7 +1397,7 @@ QImage::Format QScreenPrivate::preferredImageFormat() const altered. Note that the default implementations of these functions do nothing. - Reimplement the the mapFromDevice() and mapToDevice() functions to + Reimplement the mapFromDevice() and mapToDevice() functions to map objects from the framebuffer coordinate system to the coordinate space used by the application, and vice versa. Be aware that the default implementations simply return the given objects @@ -2710,7 +2711,7 @@ void QScreen::compose(int level, const QRegion &exposed, QRegion &blend, default: break; } - spanData.setup(qwsServer->backgroundBrush(), 256); + spanData.setup(qwsServer->backgroundBrush(), 256, QPainter::CompositionMode_SourceOver); spanData.dx = off.x(); spanData.dy = off.y(); } else if (!surface->isBuffered()) { @@ -2775,7 +2776,7 @@ void QScreen::paintBackground(const QRegion &r) rb.prepare(&img); QSpanData spanData; spanData.init(&rb, 0); - spanData.setup(bg, 256); + spanData.setup(bg, 256, QPainter::CompositionMode_Source); spanData.dx = off.x(); spanData.dy = off.y(); Q_ASSERT(spanData.blend); diff --git a/src/gui/embedded/qscreenmulti_qws.cpp b/src/gui/embedded/qscreenmulti_qws.cpp index 1914b44..a639e01 100644 --- a/src/gui/embedded/qscreenmulti_qws.cpp +++ b/src/gui/embedded/qscreenmulti_qws.cpp @@ -221,9 +221,9 @@ bool QMultiScreen::connect(const QString &displaySpec) { QString dSpec = displaySpec; if (dSpec.startsWith(QLatin1String("Multi:"), Qt::CaseInsensitive)) - dSpec = dSpec.mid(QString(QLatin1String("Multi:")).size()); + dSpec = dSpec.mid(QString::fromLatin1("Multi:").size()); - const QString displayIdSpec = QString(QLatin1String(" :%1")).arg(displayId); + const QString displayIdSpec = QString::fromLatin1(" :%1").arg(displayId); if (dSpec.endsWith(displayIdSpec)) dSpec = dSpec.left(dSpec.size() - displayIdSpec.size()); diff --git a/src/gui/embedded/qscreentransformed_qws.cpp b/src/gui/embedded/qscreentransformed_qws.cpp index 46ac1d1..01a18b3 100644 --- a/src/gui/embedded/qscreentransformed_qws.cpp +++ b/src/gui/embedded/qscreentransformed_qws.cpp @@ -206,11 +206,11 @@ bool QTransformedScreen::connect(const QString &displaySpec) { QString dspec = displaySpec.trimmed(); if (dspec.startsWith(QLatin1String("Transformed:"), Qt::CaseInsensitive)) - dspec = dspec.mid(QString(QLatin1String("Transformed:")).size()); + dspec = dspec.mid(QString::fromLatin1("Transformed:").size()); else if (!dspec.compare(QLatin1String("Transformed"), Qt::CaseInsensitive)) dspec = QString(); - const QString displayIdSpec = QString(QLatin1String(" :%1")).arg(displayId); + const QString displayIdSpec = QString::fromLatin1(" :%1").arg(displayId); if (dspec.endsWith(displayIdSpec)) dspec = dspec.left(dspec.size() - displayIdSpec.size()); @@ -223,7 +223,7 @@ bool QTransformedScreen::connect(const QString &displaySpec) if (!QScreenDriverFactory::keys().contains(driver, Qt::CaseInsensitive)) if (!dspec.isEmpty()) - dspec.prepend(QLatin1String(":")); + dspec.prepend(QLatin1Char(':')); const int id = getDisplayId(dspec); QScreen *s = qt_get_screen(id, dspec.toLatin1().constData()); @@ -400,7 +400,19 @@ void QTransformedScreen::blit(const QImage &image, const QPoint &topLeft, #endif #if defined(QT_QWS_DEPTH_16) || defined(QT_QWS_DEPTH_15) || defined(QT_QWS_DEPTH_12) case 16: +#if defined QT_QWS_ROTATE_BGR + if (pixelType() == BGRPixel && image.depth() == 16) { + SET_BLIT_FUNC(qbgr565, quint16, trans, func); + break; + } //fall-through here!!! +#endif case 15: +#if defined QT_QWS_ROTATE_BGR + if (pixelType() == BGRPixel && image.format() == QImage::Format_RGB555) { + SET_BLIT_FUNC(qbgr555, qrgb555, trans, func); + break; + } //fall-through here!!! +#endif case 12: if (image.depth() == 16) SET_BLIT_FUNC(quint16, quint16, trans, func); diff --git a/src/gui/embedded/qscreenvfb_qws.cpp b/src/gui/embedded/qscreenvfb_qws.cpp index abbe73b..ec393e3 100644 --- a/src/gui/embedded/qscreenvfb_qws.cpp +++ b/src/gui/embedded/qscreenvfb_qws.cpp @@ -310,6 +310,9 @@ bool QVFbScreen::connect(const QString &displaySpec) connected = this; + if (qgetenv("QT_QVFB_BGR").toInt()) + pixeltype = BGRPixel; + return true; } @@ -327,7 +330,7 @@ void QVFbScreen::disconnect() bool QVFbScreen::initDevice() { #ifndef QT_NO_QWS_MOUSE_QVFB - const QString mouseDev = QString(QLatin1String(QT_VFB_MOUSE_PIPE)) + const QString mouseDev = QString::fromLatin1(QT_VFB_MOUSE_PIPE) .arg(displayId); d_ptr->mouse = new QVFbMouseHandler(QLatin1String("QVFbMouse"), mouseDev); qwsServer->setDefaultMouse("None"); @@ -336,7 +339,7 @@ bool QVFbScreen::initDevice() #endif #if !defined(QT_NO_QWS_KBD_QVFB) && !defined(QT_NO_QWS_KEYBOARD) - const QString keyboardDev = QString(QLatin1String(QT_VFB_KEYBOARD_PIPE)) + const QString keyboardDev = QString::fromLatin1(QT_VFB_KEYBOARD_PIPE) .arg(displayId); d_ptr->keyboard = new QVFbKeyboardHandler(keyboardDev); qwsServer->setDefaultKeyboard("None"); diff --git a/src/gui/embedded/qsoundqss_qws.cpp b/src/gui/embedded/qsoundqss_qws.cpp index c72ea91..283bbd3 100644 --- a/src/gui/embedded/qsoundqss_qws.cpp +++ b/src/gui/embedded/qsoundqss_qws.cpp @@ -52,6 +52,7 @@ #include <qalgorithms.h> #include <qtimer.h> #include <qpointer.h> +#include <qendian.h> #include <unistd.h> #include <stdlib.h> @@ -335,7 +336,13 @@ public: virtual int readySamples(int) = 0; int getSample(int off, int bps) { - return (bps == 1) ? (data[out+off] - 128) * 128 : ((short*)data)[(out/2)+off]; + + // + // 16-bit audio data is converted to native endian so that it can be scaled + // Yes, this is ugly on a BigEndian machine + // Perhaps it shouldn't be scaled at all + // + return (bps == 1) ? (data[out+off] - 128) * 128 : qToLittleEndian(((short*)data)[(out/2)+off]); } int add(int* mixl, int* mixr, int count) @@ -547,7 +554,7 @@ public: wavedata_remaining = 0; mFinishedRead = true; } else if ( qstrncmp(chunk.id,"data",4) == 0 ) { - wavedata_remaining = chunk.size; + wavedata_remaining = qToLittleEndian( chunk.size ); //out = max = sound_buffer_size; @@ -572,10 +579,23 @@ public: //qDebug("couldn't ready chunkdata"); mFinishedRead = true; } + #define WAVE_FORMAT_PCM 1 - else if ( chunkdata.formatTag != WAVE_FORMAT_PCM ) { - //qDebug("WAV file: UNSUPPORTED FORMAT %d",chunkdata.formatTag); - mFinishedRead = true; + else + { + /* + ** Endian Fix the chuck data + */ + chunkdata.formatTag = qToLittleEndian( chunkdata.formatTag ); + chunkdata.channels = qToLittleEndian( chunkdata.channels ); + chunkdata.samplesPerSec = qToLittleEndian( chunkdata.samplesPerSec ); + chunkdata.avgBytesPerSec = qToLittleEndian( chunkdata.avgBytesPerSec ); + chunkdata.blockAlign = qToLittleEndian( chunkdata.blockAlign ); + chunkdata.wBitsPerSample = qToLittleEndian( chunkdata.wBitsPerSample ); + if ( chunkdata.formatTag != WAVE_FORMAT_PCM ) { + qWarning("WAV file: UNSUPPORTED FORMAT %d",chunkdata.formatTag); + mFinishedRead = true; + } } } else { // ignored chunk @@ -1166,9 +1186,15 @@ bool QWSSoundServerPrivate::openDevice() if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &v)) qWarning("Could not set fragments to %08x",v); #ifdef QT_QWS_SOUND_16BIT - v=AFMT_S16_LE; if (ioctl(fd, SNDCTL_DSP_SETFMT, &v)) + // + // Use native endian + // Since we have manipulated the data volume the data + // is now in native format, even though its stored + // as little endian in the WAV file + // + v=AFMT_S16_NE; if (ioctl(fd, SNDCTL_DSP_SETFMT, &v)) qWarning("Could not set format %d",v); - if (AFMT_S16_LE != v) + if (AFMT_S16_NE != v) qDebug("Want format %d got %d", AFMT_S16_LE, v); #else v=AFMT_U8; if (ioctl(fd, SNDCTL_DSP_SETFMT, &v)) diff --git a/src/gui/embedded/qtransportauth_qws.cpp b/src/gui/embedded/qtransportauth_qws.cpp index 97ba5b8..6677482 100644 --- a/src/gui/embedded/qtransportauth_qws.cpp +++ b/src/gui/embedded/qtransportauth_qws.cpp @@ -834,12 +834,12 @@ QString RequestAnalyzer::analyze( QByteArray *msgQueue ) if ( command_type == QWSCommand::QCopSend ) { QWSQCopSendCommand *sendCommand = static_cast<QWSQCopSendCommand*>(command); - request += QString( QLatin1String("/QCop/%1/%2") ).arg( sendCommand->channel ).arg( sendCommand->message ); + request += QString::fromLatin1("/QCop/%1/%2").arg( sendCommand->channel ).arg( sendCommand->message ); } if ( command_type == QWSCommand::QCopRegisterChannel ) { QWSQCopRegisterChannelCommand *registerCommand = static_cast<QWSQCopRegisterChannelCommand*>(command); - request += QString( QLatin1String("/QCop/RegisterChannel/%1") ).arg( registerCommand->channel ); + request += QString::fromLatin1("/QCop/RegisterChannel/%1").arg( registerCommand->channel ); } #endif dataSize = QWS_PROTOCOL_ITEM_SIZE( *command ); diff --git a/src/gui/embedded/qunixsocket.cpp b/src/gui/embedded/qunixsocket.cpp index 16f2cae..1600505 100644 --- a/src/gui/embedded/qunixsocket.cpp +++ b/src/gui/embedded/qunixsocket.cpp @@ -135,7 +135,7 @@ struct QUnixSocketRightsPrivate : public QSharedData #ifdef QUNIXSOCKET_DEBUG if(0 != closerv) { qDebug() << "QUnixSocketRightsPrivate: Unable to close managed" - " file descriptor (" << ::strerror(errno) << ")"; + " file descriptor (" << ::strerror(errno) << ')'; } #endif } @@ -166,7 +166,7 @@ QUnixSocketRights::QUnixSocketRights(int fd) #ifdef QUNIXSOCKET_DEBUG if(-1 == d->fd) { qDebug() << "QUnixSocketRights: Unable to duplicate fd " - << fd << " (" << ::strerror(errno) << ")"; + << fd << " (" << ::strerror(errno) << ')'; } #endif } @@ -237,7 +237,7 @@ int QUnixSocketRights::dupFd() const #ifdef QUNIXSOCKET_DEBUG if(-1 == rv) qDebug() << "QUnixSocketRights: Unable to duplicate managed file " - "descriptor (" << ::strerror(errno) << ")"; + "descriptor (" << ::strerror(errno) << ')'; #endif return rv; @@ -927,7 +927,7 @@ bool QUnixSocket::connect(const QByteArray & path) int crv; #ifdef QUNIXSOCKET_DEBUG qDebug() << "QUnixSocket: Connect requested to '" - << path << "'"; + << path << '\''; #endif abort(); // Reset any existing connection @@ -949,7 +949,7 @@ bool QUnixSocket::connect(const QByteArray & path) if(-1 == d->fd) { #ifdef QUNIXSOCKET_DEBUG qDebug() << "QUnixSocket: Unable to create socket (" - << strerror(errno) << ")"; + << strerror(errno) << ')'; #endif d->error = ResourceError; goto connect_error; @@ -962,7 +962,7 @@ bool QUnixSocket::connect(const QByteArray & path) if(-1 == crv) { #ifdef QUNIXSOCKET_DEBUG qDebug() << "QUnixSocket: Unable to configure socket (" - << ::strerror(errno) << ")"; + << ::strerror(errno) << ')'; #endif d->error = ResourceError; @@ -981,7 +981,7 @@ bool QUnixSocket::connect(const QByteArray & path) if(-1 == crv) { #ifdef QUNIXSOCKET_DEBUG qDebug() << "QUnixSocket: Unable to connect (" - << ::strerror(errno) << ")"; + << ::strerror(errno) << ')'; #endif if(ECONNREFUSED == errno) d->error = ConnectionRefused; @@ -1021,7 +1021,7 @@ connect_error: // Cleanup failed connection #ifdef QUNIXSOCKET_DEBUG if(0 != closerv) { qDebug() << "QUnixSocket: Unable to close file descriptor after " - "failed connect (" << ::strerror(errno) << ")"; + "failed connect (" << ::strerror(errno) << ')'; } #endif } @@ -1065,7 +1065,7 @@ bool QUnixSocket::setSocketDescriptor(int socketDescriptor) if(-1 == crv) { #ifdef QUNIXSOCKET_DEBUG qDebug() << "QUnixSocket: Unable to configure client provided socket (" - << ::strerror(errno) << ")"; + << ::strerror(errno) << ')'; #endif d->error = ResourceError; @@ -1136,7 +1136,7 @@ void QUnixSocket::abort() #ifdef QUNIXSOCKET_DEBUG if(0 != closerv) { qDebug() << "QUnixSocket: Unable to close socket during abort (" - << strerror(errno) << ")"; + << strerror(errno) << ')'; } #endif @@ -1686,11 +1686,11 @@ qint64 QUnixSocketPrivate::writeActivated() } #ifdef QUNIXSOCKET_DEBUG - qDebug() << "QUnixSocket: Transmitting message (length" << m.d->size() << ")"; + qDebug() << "QUnixSocket: Transmitting message (length" << m.d->size() << ')'; #endif ::ssize_t s = ::sendmsg(fd, &sendmessage, MSG_DONTWAIT | MSG_NOSIGNAL); #ifdef QUNIXSOCKET_DEBUG - qDebug() << "QUnixSocket: Transmitted message (" << s << ")"; + qDebug() << "QUnixSocket: Transmitted message (" << s << ')'; #endif if(-1 == s) { @@ -1699,13 +1699,13 @@ qint64 QUnixSocketPrivate::writeActivated() } else if(EPIPE == errno) { #ifdef QUNIXSOCKET_DEBUG qDebug() << "QUnixSocket: Remote side disconnected during transmit " - "(" << ::strerror(errno) << ")"; + "(" << ::strerror(errno) << ')'; #endif me->abort(); } else { #ifdef QUNIXSOCKET_DEBUG qDebug() << "QUnixSocket: Unable to transmit data (" - << ::strerror(errno) << ")"; + << ::strerror(errno) << ')'; #endif error = (QUnixSocket::SocketError)(QUnixSocket::WriteFailure | CausedAbort); @@ -1764,12 +1764,12 @@ void QUnixSocketPrivate::readActivated() int recvrv = ::recvmsg(fd, &message, 0); #ifdef QUNIXSOCKET_DEBUG - qDebug() << "QUnixSocket: Received message (" << recvrv << ")"; + qDebug() << "QUnixSocket: Received message (" << recvrv << ')'; #endif if(-1 == recvrv) { #ifdef QUNIXSOCKET_DEBUG qDebug() << "QUnixSocket: Unable to receive data (" - << ::strerror(errno) << ")"; + << ::strerror(errno) << ')'; #endif error = (QUnixSocket::SocketError)(QUnixSocket::ReadFailure | CausedAbort); diff --git a/src/gui/embedded/qunixsocketserver.cpp b/src/gui/embedded/qunixsocketserver.cpp index 6e9347b..489c40a 100644 --- a/src/gui/embedded/qunixsocketserver.cpp +++ b/src/gui/embedded/qunixsocketserver.cpp @@ -172,7 +172,7 @@ void QUnixSocketServer::close() #ifdef QUNIXSOCKET_DEBUG if(0 != closerv) { qDebug() << "QUnixSocketServer: Unable to close socket (" - << strerror(errno) << ")"; + << strerror(errno) << ')'; } #endif } @@ -245,7 +245,7 @@ bool QUnixSocketServer::listen(const QByteArray & path) if(-1 == d->fd) { #ifdef QUNIXSOCKETSERVER_DEBUG qDebug() << "QUnixSocketServer: Unable to create socket (" - << strerror(errno) << ")"; + << strerror(errno) << ')'; #endif close(); d->error = ResourceError; @@ -263,7 +263,7 @@ bool QUnixSocketServer::listen(const QByteArray & path) if(-1 == ::bind(d->fd, (sockaddr *)&addr, sizeof(sockaddr_un))) { #ifdef QUNIXSOCKETSERVER_DEBUG qDebug() << "QUnixSocketServer: Unable to bind socket (" - << strerror(errno) << ")"; + << strerror(errno) << ')'; #endif close(); d->error = BindError; @@ -274,7 +274,7 @@ bool QUnixSocketServer::listen(const QByteArray & path) if(-1 == ::listen(d->fd, d->maxConns)) { #ifdef QUNIXSOCKETSERVER_DEBUG qDebug() << "QUnixSocketServer: Unable to listen socket (" - << strerror(errno) << ")"; + << strerror(errno) << ')'; #endif close(); d->error = ListenError; diff --git a/src/gui/embedded/qwindowsystem_qws.cpp b/src/gui/embedded/qwindowsystem_qws.cpp index dffebf2..a15decd 100644 --- a/src/gui/embedded/qwindowsystem_qws.cpp +++ b/src/gui/embedded/qwindowsystem_qws.cpp @@ -2210,7 +2210,7 @@ void QWSServer::sendMouseEvent(const QPoint& pos, int state, int wheel) { bool block = qwsServerPrivate->screensaverblockevent(MOUSE, qwsServerPrivate->screensaverinterval, state); #ifdef EVENT_BLOCK_DEBUG - qDebug() << "sendMouseEvent" << pos.x() << pos.y() << state << (block?"block":"pass"); + qDebug() << "sendMouseEvent" << pos.x() << pos.y() << state << (block ? "block" : "pass"); #endif if (state || wheel) @@ -4044,7 +4044,7 @@ void QWSServer::setDesktopBackground(const QImage &img) */ void QWSServer::setDesktopBackground(const QColor &c) { - setDesktopBackground(QBrush(c)); + setBackground(QBrush(c)); } #endif //QT3_SUPPORT @@ -4110,7 +4110,7 @@ void QWSServer::processKeyEvent(int unicode, int keycode, Qt::KeyboardModifiers block = qwsServerPrivate->screensaverblockevent(KEY, qwsServerPrivate->screensaverinterval, isPress); #ifdef EVENT_BLOCK_DEBUG - qDebug() << "processKeyEvent" << unicode << keycode << modifiers << isPress << autoRepeat << (block?"block":"pass"); + qDebug() << "processKeyEvent" << unicode << keycode << modifiers << isPress << autoRepeat << (block ? "block" : "pass"); #endif // If we press a key and it's going to be blocked, wake up the screen diff --git a/src/gui/embedded/qwscommand_qws.cpp b/src/gui/embedded/qwscommand_qws.cpp index b0fd78b..26d3435 100644 --- a/src/gui/embedded/qwscommand_qws.cpp +++ b/src/gui/embedded/qwscommand_qws.cpp @@ -133,7 +133,7 @@ void QWSHexDump::init() void QWSHexDump::hexDump() { - *outstrm << "(" << dataSize << " bytes):\n" << prefix; + *outstrm << '(' << dataSize << " bytes):\n" << prefix; sprintf(sideviewLayout, " [%%-%us]", wrap); dataWidth = (2 * wrap) + (wrap / clustering); @@ -144,7 +144,7 @@ void QWSHexDump::hexDump() sideview[wrapIndex = i%wrap] = isprint(c) ? c : '.'; if (wrapIndex && (wrapIndex % clustering == 0)) - *outstrm << " "; + *outstrm << ' '; outstrm->setFieldWidth(2); outstrm->setPadChar('0'); @@ -172,14 +172,14 @@ void QWSHexDump::sideviewDump(int at) int currentWidth = (2 * at) + (at / clustering) - (at%clustering?0:1); int missing = qMax(dataWidth - currentWidth, 0); while (missing--) - *outstrm << " "; + *outstrm << ' '; *outstrm << " ["; outstrm->setPadChar(' '); outstrm->setFieldWidth(wrap); outstrm->setFieldAlignment( QTextStream::AlignLeft ); *outstrm << sideview; - *outstrm << "]"; + *outstrm << ']'; } } diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 5d7d81f..c1d44d3 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -130,12 +130,18 @@ \img graphicsview-parentchild.png + \section1 Transformation + QGraphicsItem supports affine transformations in addition to its base position, pos(). To change the item's transformation, you can either pass - a transformation matrix to setTransform(), or call one of the convenience - functions rotate(), scale(), translate(), or shear(). Item transformations - accumulate from parent to child, so if both a parent and child item are - rotated 90 degrees, the child's total transformation will be 180 degrees. + a transformation matrix to setTransform(), or set the different transformation + properties (transformOrigin, x/y/zRotation, x/yScale, horizontal/verticalShear). + Note that setting the transformation matrix conflicts with using the properties. + Setting the properties will overwrite the transformation set with setTransform, + and using setTransform will reset the properties. + + Item transformations accumulate from parent to child, so if both a parent and child + item are rotated 90 degrees, the child's total transformation will be 180 degrees. Similarly, if the item's parent is scaled to 2x its original size, its children will also be twice as large. An item's transformation does not affect its own local geometry; all geometry functions (e.g., contains(), @@ -146,6 +152,22 @@ and scenePos(), which returns its position in scene coordinates. To reset an item's matrix, call resetTransform(). + The order you set the transformation properties does not affect the resulting transformation + The resulting transformation is always computed in the following order + + \code + [Origin] [RotateX] [RotateY] [RotateZ] [Shear] [Scale] [-Origin] + \endcode + + So the transformation is equivalent to the following code + + \code + QTransform().translate(xOrigin, yOrigin).rotate(xRotation, Qt::XAxis).rotate(yRotation, Qt::YAxis).rotate(zRotation, Qt::ZAxis) + .shear(horizontalShear, verticalShear).scale(xScale, yScale).translate(-xOrigin, -yOrigin); + \endcode + + \section1 Painting + The paint() function is called by QGraphicsView to paint the item's contents. The item has no background or default fill of its own; whatever is behind the item will shine through all areas that are not explicitly @@ -161,6 +183,8 @@ high z-values. Stacking order applies to sibling items; parents are always drawn before their children. + \section1 Events + QGraphicsItem receives events from QGraphicsScene through the virtual function sceneEvent(). This function distributes the most common events to a set of convenience event handlers: @@ -186,6 +210,8 @@ by the virtual function sceneEventFilter(). You can remove item event filters by calling removeSceneEventFilter(). + \section1 Custom Data + Sometimes it's useful to register custom data with an item, be it a custom item, or a standard item. You can call setData() on any item to store data in it using a key-value pair (the key being an integer, and the value is a @@ -274,6 +300,15 @@ this flag, the child will be stacked behind it. This flag is useful for drop shadow effects and for decoration objects that follow the parent item's geometry without drawing on top of it. + + \value ItemUsesExtendedStyleOption The item makes use of either + QStyleOptionGraphicsItem::exposedRect or QStyleOptionGraphicsItem::matrix. + By default, the exposedRect is initialized to the item's boundingRect and + the matrix is untransformed. Enable this flag for more fine-grained values. + Note that QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag + and is always initialized to 1. + Use QStyleOptionGraphicsItem::levelOfDetailFromTransform for a more + fine-grained value. */ /*! @@ -329,16 +364,17 @@ \value ItemTransformChange The item's transformation matrix changes. This notification is only sent when the item's local transformation matrix - changes (i.e., as a result of calling setTransform(), or one of the - convenience transformation functions, such as rotate()). The value + changes (i.e., as a result of calling setTransform(). The value argument is the new matrix (i.e., a QTransform); to get the old matrix, - call transform(). Do not call setTransform() or any of the transformation - convenience functions in itemChange() as this notification is delivered; + call transform(). Do not call setTransform() or set any of the transformation + properties in itemChange() as this notification is delivered; instead, you can return the new matrix from itemChange(). + This notification is not sent if you change the transformation properties. \value ItemTransformHasChanged The item's transformation matrix has - changed. This notification is only sent after the item's local - trasformation matrix has changed. The value argument is the new matrix + changed either because setTransform is called, or one of the transformation + properties is changed. This notification is only sent after the item's local + transformation matrix has changed. The value argument is the new matrix (same as transform()), and QGraphicsItem ignores the return value for this notification (i.e., a read-only notification). @@ -914,6 +950,53 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec } } +void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, + const QRegion &exposedRegion, bool allItems) const +{ + Q_ASSERT(option); + Q_Q(const QGraphicsItem); + + // Initialize standard QStyleOption values. + const QRectF brect = q->boundingRect(); + option->state = QStyle::State_None; + option->rect = brect.toRect(); + option->levelOfDetail = 1; + option->exposedRect = brect; + if (selected) + option->state |= QStyle::State_Selected; + if (enabled) + option->state |= QStyle::State_Enabled; + if (q->hasFocus()) + option->state |= QStyle::State_HasFocus; + if (scene) { + if (scene->d_func()->hoverItems.contains(q_ptr)) + option->state |= QStyle::State_MouseOver; + if (q == scene->mouseGrabberItem()) + option->state |= QStyle::State_Sunken; + } + + if (!(flags & QGraphicsItem::ItemUsesExtendedStyleOption)) + return; + + // Initialize QStyleOptionGraphicsItem specific values (matrix, exposedRect). + + const QTransform itemToViewportTransform = q->deviceTransform(worldTransform); + option->matrix = itemToViewportTransform.toAffine(); //### discards perspective + + if (!allItems) { + // Determine the item's exposed area + option->exposedRect = QRectF(); + const QTransform reverseMap = itemToViewportTransform.inverted(); + const QVector<QRect> exposedRects(exposedRegion.rects()); + for (int i = 0; i < exposedRects.size(); ++i) { + option->exposedRect |= reverseMap.mapRect(exposedRects.at(i)); + if (option->exposedRect.contains(brect)) + break; + } + option->exposedRect &= brect; + } +} + /*! \internal @@ -922,6 +1005,7 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec void QGraphicsItemCache::purge() { QPixmapCache::remove(key); + key = QPixmapCache::Key(); QMutableMapIterator<QPaintDevice *, DeviceData> it(deviceData); while (it.hasNext()) { DeviceData &data = it.next().value(); @@ -1263,8 +1347,8 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) return; // Flags that alter the geometry of the item (or its children). - int geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations); - bool fullUpdate = (flags & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask); + const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations); + bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask); if (fullUpdate) d_ptr->fullUpdateHelper(false, true); @@ -1370,12 +1454,6 @@ void QGraphicsItem::setCacheMode(CacheMode mode, const QSize &logicalCacheSize) cache->purge(); if (mode == ItemCoordinateCache) { - if (cache->key.isEmpty()) { - // Generate new simple pixmap cache key. - QString tmp; - tmp.sprintf("qgv-%p", this); - cache->key = tmp; - } if (lastMode == mode && cache->fixedSize == logicalCacheSize) noVisualChange = true; cache->fixedSize = logicalCacheSize; @@ -1562,6 +1640,10 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo if (visible == quint32(newVisible)) return; + // Don't show child if parent is not visible + if (parent && newVisible && !parent->d_ptr->visible) + return; + // Modify the property. const QVariant newVisibleVariant(q_ptr->itemChange(QGraphicsItem::ItemVisibleChange, quint32(newVisible))); @@ -1961,7 +2043,7 @@ void QGraphicsItem::setOpacity(qreal opacity) itemChange(ItemOpacityHasChanged, newOpacity); // Update. - d_ptr->fullUpdateHelper(); + d_ptr->fullUpdateHelper(/*childrenOnly=*/false, /*maybeDirtyClipPath=*/false, /*ignoreOpacity=*/true); } /*! @@ -2508,8 +2590,13 @@ QMatrix QGraphicsItem::matrix() const /*! \since 4.3 - Returns this item's transformation matrix. If no matrix has been set, the - identity matrix is returned. + Returns this item's transformation matrix. + + Either the one set by setTransform, or the resulting transformation from + all the transfmation properties + + If no matrix or transformation property has been set, the + identity matrix is returned. \sa setTransform(), sceneTransform() */ @@ -2517,10 +2604,404 @@ QTransform QGraphicsItem::transform() const { if (!d_ptr->hasTransform) return QTransform(); + if (d_ptr->hasDecomposedTransform && d_ptr->dirtyTransform) { + QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); + QTransform x; + decomposed->generateTransform(&x); + QVariant v(x); + d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, v); + d_ptr->dirtyTransform = 0; + const_cast<QGraphicsItem *>(this)->itemChange(ItemTransformHasChanged, v); + return x; + } return qVariantValue<QTransform>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)); } /*! + \since 4.6 + + Returns the rotation around the X axis. + + The default is 0 + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, this function return the default value. + + \sa setXRotation(), {Transformations} +*/ +qreal QGraphicsItem::xRotation() const +{ + return d_ptr->decomposedTransform()->xRotation; +} + +/*! + \since 4.6 + + Sets the rotation around the X axis to \a angle degrees. + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, it will be overwritten. + + \sa xRotation(), {Transformations} +*/ +void QGraphicsItem::setXRotation(qreal angle) +{ + if (!d_ptr->dirtyTransform) { + d_ptr->fullUpdateHelper(true); + prepareGeometryChange(); + } + QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); + decomposed->xRotation = angle; + if (!d_ptr->dirtyTransform) + d_ptr->invalidateSceneTransformCache(); + d_ptr->dirtyTransform = 1; + d_ptr->hasTransform = 1; +} + +/*! + \since 4.6 + + Returns the rotation around the Y axis. + + The default is 0 + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, this function return the default value. + + \sa setYRotation(), {Transformations} +*/ +qreal QGraphicsItem::yRotation() const +{ + return d_ptr->decomposedTransform()->yRotation; +} + +/*! + \since 4.6 + + Sets the rotation around the Y axis to \a angle degrees. + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, it will be overwritten. + + \sa yRotation(), {Transformations} +*/ +void QGraphicsItem::setYRotation(qreal angle) +{ + if (!d_ptr->dirtyTransform) { + d_ptr->fullUpdateHelper(true); + prepareGeometryChange(); + } + QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); + decomposed->yRotation = angle; + if (!d_ptr->dirtyTransform) + d_ptr->invalidateSceneTransformCache(); + d_ptr->dirtyTransform = 1; + d_ptr->hasTransform = 1; +} + +/*! + \since 4.6 + + Returns the rotation around the Z axis. + + The default is 0 + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, this function return the default value. + + \sa setZRotation(), {Transformations} +*/ +qreal QGraphicsItem::zRotation() const +{ + return d_ptr->decomposedTransform()->zRotation; +} + +/*! + \since 4.6 + + Sets the rotation around the Z axis to \a angle degrees. + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, it will be overwritten. + + \sa zRotation(), {Transformations} +*/ +void QGraphicsItem::setZRotation(qreal angle) +{ + if (!d_ptr->dirtyTransform) { + d_ptr->fullUpdateHelper(true); + prepareGeometryChange(); + } + QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); + decomposed->zRotation = angle; + if (!d_ptr->dirtyTransform) + d_ptr->invalidateSceneTransformCache(); + d_ptr->dirtyTransform = 1; + d_ptr->hasTransform = 1; +} + +/*! + \since 4.6 + + This convenience function set the rotation angles around the 3 axes + to \a x, \a y and \a z. + + \sa setXRotation(), setYRotation(), setZRotation() +*/ +void QGraphicsItem::setRotation(qreal x, qreal y, qreal z) +{ + setXRotation(x); + setYRotation(y); + setZRotation(z); +} + +/*! + \since 4.6 + + Returns the scale factor on the X axis. + + The default is 1 + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, this function return the default value. + + \sa setXScale(), {Transformations} +*/ +qreal QGraphicsItem::xScale() const +{ + return d_ptr->decomposedTransform()->xScale; +} + +/*! + \since 4.6 + + Sets the scale factor on the X axis to \a factor. + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, it will be overwritten. + + \sa xScale(), {Transformations} +*/ +void QGraphicsItem::setXScale(qreal factor) +{ + if (!d_ptr->dirtyTransform) { + d_ptr->fullUpdateHelper(true); + prepareGeometryChange(); + } + QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); + decomposed->xScale = factor; + if (!d_ptr->dirtyTransform) + d_ptr->invalidateSceneTransformCache(); + d_ptr->dirtyTransform = 1; + d_ptr->hasTransform = 1; +} + +/*! + \since 4.6 + + Returns the scale factor on the Y axis. + + The default is 1 + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, this function return the default value. + + \sa setYScale(), {Transformations} +*/ +qreal QGraphicsItem::yScale() const +{ + return d_ptr->decomposedTransform()->yScale; +} + +/*! + \since 4.6 + + Sets the scale factor on the Y axis to \a factor. + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, it will be overwritten. + + \sa yScale(), {Transformations} +*/ +void QGraphicsItem::setYScale(qreal factor) +{ + if (!d_ptr->dirtyTransform) { + d_ptr->fullUpdateHelper(true); + prepareGeometryChange(); + } + QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); + decomposed->yScale = factor; + if (!d_ptr->dirtyTransform) + d_ptr->invalidateSceneTransformCache(); + d_ptr->dirtyTransform = 1; + d_ptr->hasTransform = 1; +} + +/*! + \since 4.6 + + This convenience function set the scaling factors on X and Y axis to \a sx and \a sy. + + \sa setXScale(), setYScale() +*/ +void QGraphicsItem::setScale(qreal sx, qreal sy) +{ + setXScale(sx); + setYScale(sy); +} + +/*! + \since 4.6 + + Returns the horizontal shear. + + The default is 0 + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, this function return the default value. + + \sa setHorizontalShear(), {Transformations} +*/ +qreal QGraphicsItem::horizontalShear() const +{ + return d_ptr->decomposedTransform()->horizontalShear; +} + +/*! + \since 4.6 + + Sets the horizontal shear to \a shear. + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, it will be overwritten. + + \sa horizontalShear(), {Transformations} +*/ +void QGraphicsItem::setHorizontalShear(qreal shear) +{ + if (!d_ptr->dirtyTransform) { + d_ptr->fullUpdateHelper(true); + prepareGeometryChange(); + } + QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); + decomposed->horizontalShear = shear; + if (!d_ptr->dirtyTransform) + d_ptr->invalidateSceneTransformCache(); + d_ptr->dirtyTransform = 1; + d_ptr->hasTransform = 1; +} + +/*! + \since 4.6 + + Returns the vertical shear. + + The default is 0 + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, this function return the default value. + + \sa setHorizontalShear(), {Transformations} +*/ +qreal QGraphicsItem::verticalShear() const +{ + return d_ptr->decomposedTransform()->verticalShear; +} + +/*! + \since 4.6 + + Sets the vertical shear to \a shear. + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, it will be overwritten. + + \sa verticalShear(), {Transformations} +*/ +void QGraphicsItem::setVerticalShear(qreal shear) +{ + if (!d_ptr->dirtyTransform) { + d_ptr->fullUpdateHelper(true); + prepareGeometryChange(); + } + QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); + decomposed->verticalShear = shear; + if (!d_ptr->dirtyTransform) + d_ptr->invalidateSceneTransformCache(); + d_ptr->dirtyTransform = 1; + d_ptr->hasTransform = 1; +} + +/*! + \since 4.6 + + This convenience function sets the horizontal shear to \a sh and the vertical shear to \a sv. + + \sa setHorizontalShear(), setVerticalShear() +*/ +void QGraphicsItem::setShear(qreal sh, qreal sv) +{ + setHorizontalShear(sh); + setVerticalShear(sv); +} + +/*! + \since 4.6 + + Returns the transformation origin for the transformation properties. + + The default is QPointF(0,0). + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, this function return the default value. + + \sa setTransformOrigin(), {Transformations} +*/ +QPointF QGraphicsItem::transformOrigin() const +{ + const QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); + return QPointF(decomposed->xOrigin, decomposed->yOrigin); +} + +/*! + \fn inline void setTransformOrigin(qreal x, qreal y) + + \since 4.6 + + This is an overloaded member function, provided for convenience. + Sets the transformation origin for the transformation + properties to the point(\a x, \a y). + + \sa setTransformOrigin(), {Transformations} +*/ + +/*! + \since 4.6 + + Sets the transformation origin for the transformation properties to \a origin. + This does not apply to the transformation set by setTransform. + + \warning setting this property is conflicting with calling setTransform. + If a transform has been set, it will be overwritten. + + \sa transformOrigin(), {Transformations} +*/ +void QGraphicsItem::setTransformOrigin(const QPointF &origin) +{ + if (!d_ptr->dirtyTransform) { + d_ptr->fullUpdateHelper(true); + prepareGeometryChange(); + } + QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); + decomposed->xOrigin = origin.x(); + decomposed->yOrigin = origin.y(); + if (!d_ptr->dirtyTransform) + d_ptr->invalidateSceneTransformCache(); + d_ptr->dirtyTransform = 1; + d_ptr->hasTransform = 1; +} + +/*! \obsolete Use sceneTransform() instead. @@ -2618,6 +3099,10 @@ QTransform QGraphicsItem::sceneTransform() const */ QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) const { + // Ensure we return the standard transform if we're not untransformable. + if (!d_ptr->itemIsUntransformable()) + return sceneTransform() * viewportTransform; + // Find the topmost item that ignores view transformations. const QGraphicsItem *untransformedAncestor = this; QList<const QGraphicsItem *> parents; @@ -2791,7 +3276,7 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co Use setTransform() instead. - \sa transform(), rotate(), scale(), shear(), translate(), {The Graphics View Coordinate System} + \sa transform(), {The Graphics View Coordinate System} */ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) { @@ -2816,6 +3301,8 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) prepareGeometryChange(); d_ptr->hasTransform = !newTransform.isIdentity(); d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); + d_ptr->dirtyTransformComponents = 1; + d_ptr->dirtyTransform = 0; d_ptr->invalidateSceneTransformCache(); // Send post-notification. @@ -2839,7 +3326,10 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) to map an item coordiate to a scene coordinate, or mapFromScene() to map from scene coordinates to item coordinates. - \sa transform(), rotate(), scale(), shear(), translate(), {The Graphics View Coordinate System} + \warning using this function conflicts with using the transformation properties. + If you set a transformation, getting the properties will return default values. + + \sa transform(), setRotation(), setScale(), setShear(), setTransformOrigin() {The Graphics View Coordinate System} */ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) { @@ -2864,6 +3354,8 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) prepareGeometryChange(); d_ptr->hasTransform = !newTransform.isIdentity(); d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); + d_ptr->dirtyTransformComponents = 1; + d_ptr->dirtyTransform = 0; d_ptr->invalidateSceneTransformCache(); // Send post-notification. @@ -2883,8 +3375,9 @@ void QGraphicsItem::resetMatrix() /*! \since 4.3 - Resets this item's transformation matrix to the identity matrix. This is - equivalent to calling \c setTransform(QTransform()). + Resets this item's transformation matrix to the identity matrix or + all the transformation properties to their default values. + This is equivalent to calling \c setTransform(QTransform()). \sa setTransform(), transform() */ @@ -2894,6 +3387,9 @@ void QGraphicsItem::resetTransform() } /*! + \obsolete + Use setZRotation() instead + Rotates the current item transformation \a angle degrees clockwise around its origin. To translate around an arbitrary point (x, y), you need to combine translation and rotation with setTransform(). @@ -2902,6 +3398,9 @@ void QGraphicsItem::resetTransform() \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 6 + \warning using this function conflicts with using the transformation properties. + Getting those properties after using this function will return default values. + \sa setTransform(), transform(), scale(), shear(), translate() */ void QGraphicsItem::rotate(qreal angle) @@ -2910,6 +3409,9 @@ void QGraphicsItem::rotate(qreal angle) } /*! + \obsolete + Use setScale() instead + Scales the current item transformation by (\a sx, \a sy) around its origin. To scale from an arbitrary point (x, y), you need to combine translation and scaling with setTransform(). @@ -2918,7 +3420,10 @@ void QGraphicsItem::rotate(qreal angle) \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 7 - \sa setTransform(), transform(), rotate(), shear(), translate() + \warning using this function conflicts with using the transformation properties. + Getting those properties after using this function will return default values. + + \sa setTransform(), transform() */ void QGraphicsItem::scale(qreal sx, qreal sy) { @@ -2926,9 +3431,15 @@ void QGraphicsItem::scale(qreal sx, qreal sy) } /*! + \obsolete + Use setShear instead. + Shears the current item transformation by (\a sh, \a sv). - \sa setTransform(), transform(), rotate(), scale(), translate() + \warning using this function conflicts with using the transformation properties. + Getting those properties after using this function will return default values. + + \sa setTransform(), transform() */ void QGraphicsItem::shear(qreal sh, qreal sv) { @@ -2936,13 +3447,19 @@ void QGraphicsItem::shear(qreal sh, qreal sv) } /*! + \obsolete + Use setPos() or setTransformOrigin() instead. + Translates the current item transformation by (\a dx, \a dy). If all you want is to move an item, you should call moveBy() or setPos() instead; this function changes the item's translation, which is conceptually separate from its position. - \sa setTransform(), transform(), rotate(), scale(), shear() + \warning using this function conflicts with using the transformation properties. + Getting those properties after using this function will return default values. + + \sa setTransform(), transform() */ void QGraphicsItem::translate(qreal dx, qreal dy) { @@ -3066,7 +3583,7 @@ QRectF QGraphicsItem::childrenBoundingRect() const Although the item's shape can be arbitrary, the bounding rect is always rectangular, and it is unaffected by the items' - transformation (scale(), rotate(), etc.). + transformation. If you want to change the item's bounding rectangle, you must first call prepareGeometryChange(). This notifies the scene of the imminent change, @@ -3276,10 +3793,16 @@ bool QGraphicsItem::contains(const QPointF &point) const } /*! - Returns true if this item collides with \a other; otherwise returns false. - The ways items collide is determined by \a mode. The default value for \a - mode is Qt::IntersectsItemShape; \a other collides with this item if it - either intersects, contains, or is contained by this item's shape. + + Returns true if this item collides with \a other; otherwise + returns false. + + The \a mode is applied to \a other, and the resulting shape or + bounding rectangle is then compared to this item's shape. The + default value for \a mode is Qt::IntersectsItemShape; \a other + collides with this item if it either intersects, contains, or is + contained by this item's shape (see Qt::ItemSelectionMode for + details). The default implementation is based on shape intersection, and it calls shape() on both items. Because the complexity of arbitrary shape-shape @@ -3334,6 +3857,11 @@ bool QGraphicsItem::collidesWithItem(const QGraphicsItem *other, Qt::ItemSelecti Qt::IntersectsItemShape; \a path collides with this item if it either intersects, contains, or is contained by this item's shape. + Note that this function checks whether the item's shape or + bounding rectangle (depending on \a mode) is contained within \a + path, and not whether \a path is contained within the items shape + or bounding rectangle. + \sa collidesWithItem(), contains(), shape() */ bool QGraphicsItem::collidesWithPath(const QPainterPath &path, Qt::ItemSelectionMode mode) const @@ -3374,11 +3902,12 @@ bool QGraphicsItem::collidesWithPath(const QPainterPath &path, Qt::ItemSelection /*! Returns a list of all items that collide with this item. - The way collisions are detected is determined by \a mode. The default - value for \a mode is Qt::IntersectsItemShape; All items whose shape - intersects or is contained by this item's shape are returned. + The way collisions are detected is determined by applying \a mode + to items that are compared to this item, i.e., each item's shape + or bounding rectangle is checked against this item's shape. The + default value for \a mode is Qt::IntersectsItemShape. - \sa QGraphicsScene::collidingItems(), collidesWithItem() + \sa collidesWithItem() */ QList<QGraphicsItem *> QGraphicsItem::collidingItems(Qt::ItemSelectionMode mode) const { @@ -3655,16 +4184,15 @@ void QGraphicsItem::setBoundingRegionGranularity(qreal granularity) All painting is done in local coordinates. - \sa setCacheMode(), QPen::width(), {Item Coordinates} + \sa setCacheMode(), QPen::width(), {Item Coordinates}, ItemUsesExtendedStyleOption */ /*! \internal Returns true if we can discard an update request; otherwise false. */ -bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, - bool ignoreVisibleBit, - bool ignoreDirtyBit) const +bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, bool ignoreVisibleBit, + bool ignoreDirtyBit, bool ignoreOpacity) const { // No scene, or if the scene is updating everything, means we have nothing // to do. The only exception is if the scene tracks the growing scene rect. @@ -3673,7 +4201,7 @@ bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, || !scene || (scene->d_func()->updateAll && scene->d_func()->hasSceneRect) || (!ignoreClipping && (childrenClippedToShape() && isClippedAway())) - || (childrenCombineOpacity() && isFullyTransparent()); + || (!ignoreOpacity && childrenCombineOpacity() && isFullyTransparent()); } /*! @@ -3703,11 +4231,10 @@ void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force, bool may Propagates updates to \a item and all its children. */ -void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool maybeDirtyClipPath) +void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool maybeDirtyClipPath, bool ignoreOpacity) { - if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, - /*ignoreVisibleBit=*/false, - /*ignoreDirtyBit=*/true)) { + if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/false, + /*ignoreDirtyBit=*/true, ignoreOpacity)) { return; } @@ -4135,7 +4662,7 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect) && (d->cacheMode == ItemCoordinateCache && !c->fixedSize.isValid()); if (scrollCache) { QPixmap pix; - if (QPixmapCache::find(c->key, pix)) { + if (QPixmapCache::find(c->key, &pix)) { // Adjust with 2 pixel margin. Notice the loss of precision // when converting to QRect. int adjust = 2; @@ -4144,7 +4671,7 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect) _q_scrollPixmap(&pix, irect, dx, dy); - QPixmapCache::insert(c->key, pix); + QPixmapCache::replace(c->key, pix); // Translate the existing expose. foreach (QRectF exposedRect, c->exposed) @@ -7617,9 +8144,7 @@ void QGraphicsPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsIte painter->setRenderHint(QPainter::SmoothPixmapTransform, (d->transformationMode == Qt::SmoothTransformation)); - QRectF exposed = option->exposedRect.adjusted(-1, -1, 1, 1); - exposed &= QRectF(d->offset.x(), d->offset.y(), d->pixmap.width(), d->pixmap.height()); - painter->drawPixmap(exposed, d->pixmap, exposed.translated(-d->offset)); + painter->drawPixmap(d->offset, d->pixmap); if (option->state & QStyle::State_Selected) qt_graphicsItem_highlightSelected(this, painter, option); @@ -7785,6 +8310,7 @@ QGraphicsTextItem::QGraphicsTextItem(const QString &text, QGraphicsItem *parent setPlainText(text); setAcceptDrops(true); setAcceptHoverEvents(true); + setFlags(ItemUsesExtendedStyleOption); } /*! @@ -7804,6 +8330,7 @@ QGraphicsTextItem::QGraphicsTextItem(QGraphicsItem *parent dd->qq = this; setAcceptDrops(true); setAcceptHoverEvents(true); + setFlag(ItemUsesExtendedStyleOption); } /*! @@ -8074,19 +8601,19 @@ bool QGraphicsTextItem::sceneEvent(QEvent *event) void QGraphicsTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { if ((QGraphicsItem::d_ptr->flags & (ItemIsSelectable | ItemIsMovable)) - && (event->buttons() & Qt::LeftButton) && dd->_q_mouseOnEdge(event)) { - // User left-pressed on edge of selectable/movable item, use - // base impl. - dd->useDefaultImpl = true; + && (event->buttons() & Qt::LeftButton) && dd->_q_mouseOnEdge(event)) { + // User left-pressed on edge of selectable/movable item, use + // base impl. + dd->useDefaultImpl = true; } else if (event->buttons() == event->button() - && dd->control->textInteractionFlags() == Qt::NoTextInteraction) { - // User pressed first button on non-interactive item. - dd->useDefaultImpl = true; + && dd->control->textInteractionFlags() == Qt::NoTextInteraction) { + // User pressed first button on non-interactive item. + dd->useDefaultImpl = true; } if (dd->useDefaultImpl) { QGraphicsItem::mousePressEvent(event); - if (!event->isAccepted()) - dd->useDefaultImpl = false; + if (!event->isAccepted()) + dd->useDefaultImpl = false; return; } dd->sendControlEvent(event); @@ -8111,14 +8638,14 @@ void QGraphicsTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (dd->useDefaultImpl) { QGraphicsItem::mouseReleaseEvent(event); - if (dd->control->textInteractionFlags() == Qt::NoTextInteraction - && !event->buttons()) { - // User released last button on non-interactive item. + if (dd->control->textInteractionFlags() == Qt::NoTextInteraction + && !event->buttons()) { + // User released last button on non-interactive item. dd->useDefaultImpl = false; - } else if ((event->buttons() & Qt::LeftButton) == 0) { - // User released the left button on an interactive item. + } else if ((event->buttons() & Qt::LeftButton) == 0) { + // User released the left button on an interactive item. dd->useDefaultImpl = false; - } + } return; } dd->sendControlEvent(event); @@ -8408,9 +8935,9 @@ bool QGraphicsTextItemPrivate::_q_mouseOnEdge(QGraphicsSceneMouseEvent *event) Sets the flags \a flags to specify how the text item should react to user input. - The default for a QGraphicsTextItem is Qt::NoTextInteraction. Setting a - value different to Qt::NoTextInteraction will also set the ItemIsFocusable - QGraphicsItem flag. + The default for a QGraphicsTextItem is Qt::NoTextInteraction. This function + also affects the ItemIsFocusable QGraphicsItem flag by setting it if \a flags + is different from Qt::NoTextInteraction and clearing it otherwise. By default, the text is read-only. To transform the item into an editor, set the Qt::TextEditable flag. @@ -9149,6 +9676,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag) case QGraphicsItem::ItemStacksBehindParent: str = "ItemStacksBehindParent"; break; + case QGraphicsItem::ItemUsesExtendedStyleOption: + str = "ItemUsesExtendedStyleOption"; + break; } debug << str; return debug; @@ -9156,17 +9686,17 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag) QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags) { - debug << "("; + debug << '('; bool f = false; for (int i = 0; i < 9; ++i) { if (flags & (1 << i)) { if (f) - debug << "|"; + debug << '|'; f = true; debug << QGraphicsItem::GraphicsItemFlag(int(flags & (1 << i))); } } - debug << ")"; + debug << ')'; return debug; } diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 1b41232..cb86020 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -94,7 +94,9 @@ public: ItemIgnoresTransformations = 0x20, ItemIgnoresParentOpacity = 0x40, ItemDoesntPropagateOpacityToChildren = 0x80, - ItemStacksBehindParent = 0x100 + ItemStacksBehindParent = 0x100, + ItemUsesExtendedStyleOption = 0x200 + // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag. }; Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag) @@ -239,11 +241,41 @@ public: QTransform itemTransform(const QGraphicsItem *other, bool *ok = 0) const; void setTransform(const QTransform &matrix, bool combine = false); void resetTransform(); - - void rotate(qreal angle); - void scale(qreal sx, qreal sy); - void shear(qreal sh, qreal sv); - void translate(qreal dx, qreal dy); + + void rotate(qreal angle); // ### obsolete + void scale(qreal sx, qreal sy); // ### obsolete + void shear(qreal sh, qreal sv); // ### obsolete + void translate(qreal dx, qreal dy); // ### obsolete + + qreal xRotation() const; + void setXRotation(qreal angle); + + qreal yRotation() const; + void setYRotation(qreal angle); + + qreal zRotation() const; + void setZRotation(qreal angle); + void setRotation(qreal x, qreal y, qreal z); + + qreal xScale() const; + void setXScale(qreal factor); + + qreal yScale() const; + void setYScale(qreal factor); + void setScale(qreal sx, qreal sy); + + qreal horizontalShear() const; + void setHorizontalShear(qreal shear); + + qreal verticalShear() const; + void setVerticalShear(qreal shear); + void setShear(qreal sh, qreal sv); + + QPointF transformOrigin() const; + void setTransformOrigin(const QPointF &origin); + inline void setTransformOrigin(qreal x, qreal y) + { setTransformOrigin(QPointF(x,y)); } + virtual void advance(int phase); // Stacking order @@ -1014,4 +1046,3 @@ QT_END_NAMESPACE QT_END_HEADER #endif // QGRAPHICSITEM_H - diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 940e566..bd81fe5 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -54,6 +54,9 @@ // #include "qgraphicsitem.h" +#include "qpixmapcache.h" + +#include <QtCore/qpoint.h> #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW @@ -69,13 +72,14 @@ public: // ItemCoordinateCache only QRect boundingRect; QSize fixedSize; - QString key; + QPixmapCache::Key key; // DeviceCoordinateCache only struct DeviceData { + DeviceData() {} QTransform lastTransform; QPoint cacheIndent; - QString key; + QPixmapCache::Key key; }; QMap<QPaintDevice *, DeviceData> deviceData; @@ -91,6 +95,15 @@ class Q_AUTOTEST_EXPORT QGraphicsItemPrivate { Q_DECLARE_PUBLIC(QGraphicsItem) public: + struct TransformData + { + TransformData() : rotationX(0),rotationY(0),rotationZ(0),scaleX(1),scaleY(1), dirty(true) {} + QTransform baseTransform; + QTransform transform; + QPointF transformCenter; + qreal rotationX,rotationY,rotationZ,scaleX,scaleY; + bool dirty; + }; enum Extra { ExtraTransform, ExtraToolTip, @@ -99,7 +112,8 @@ public: ExtraMaxDeviceCoordCacheSize, ExtraBoundingRegionGranularity, ExtraOpacity, - ExtraEffectiveOpacity + ExtraEffectiveOpacity, + ExtraDecomposedTransform }; enum AncestorFlag { @@ -132,7 +146,6 @@ public: ancestorFlags(0), cacheMode(0), hasBoundingRegionGranularity(0), - flags(0), hasOpacity(0), hasEffectiveOpacity(0), isWidget(0), @@ -142,7 +155,11 @@ public: dirtyClipPath(1), emptyClipPath(0), inSetPosHelper(0), + flags(0), allChildrenCombineOpacity(1), + hasDecomposedTransform(0), + dirtyTransform(0), + dirtyTransformComponents(0), globalStackingOrder(-1), sceneTransformIndex(-1), q_ptr(0) @@ -166,11 +183,10 @@ public: void setPosHelper(const QPointF &pos); void setVisibleHelper(bool newVisible, bool explicitly, bool update = true); void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true); - bool discardUpdateRequest(bool ignoreClipping = false, - bool ignoreVisibleBit = false, - bool ignoreDirtyBit = false) const; + bool discardUpdateRequest(bool ignoreClipping = false, bool ignoreVisibleBit = false, + bool ignoreDirtyBit = false, bool ignoreOpacity = false) const; void updateHelper(const QRectF &rect = QRectF(), bool force = false, bool maybeDirtyClipPath = false); - void fullUpdateHelper(bool childrenOnly = false, bool maybeDirtyClipPath = false); + void fullUpdateHelper(bool childrenOnly = false, bool maybeDirtyClipPath = false, bool ignoreOpacity = false); void updateEffectiveOpacity(); void resolveEffectiveOpacity(qreal effectiveParentOpacity); void resolveDepth(int parentDepth); @@ -179,6 +195,8 @@ public: void removeChild(QGraphicsItem *child); void setParentItemHelper(QGraphicsItem *parent, bool deleting); void childrenBoundingRectHelper(QTransform *x, QRectF *rect); + void initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, + const QRegion &exposedRegion, bool allItems = false) const; virtual void resolveFont(uint inheritedMask) { @@ -230,7 +248,7 @@ public: } } } - + struct ExtraStruct { ExtraStruct(Extra type, QVariant value) : type(type), value(value) @@ -242,6 +260,7 @@ public: bool operator<(Extra extra) const { return type < extra; } }; + QList<ExtraStruct> extras; QGraphicsItemCache *maybeExtraItemCache() const; @@ -298,7 +317,7 @@ public: int index; int depth; - // Packed 32 bytes + // Packed 32 bits quint32 acceptedMouseButtons : 5; quint32 visible : 1; quint32 explicitlyHidden : 1; @@ -315,9 +334,6 @@ public: quint32 ancestorFlags : 3; quint32 cacheMode : 2; quint32 hasBoundingRegionGranularity : 1; - quint32 flags : 9; - - // New 32 bytes quint32 hasOpacity : 1; quint32 hasEffectiveOpacity : 1; quint32 isWidget : 1; @@ -327,17 +343,90 @@ public: quint32 dirtyClipPath : 1; quint32 emptyClipPath : 1; quint32 inSetPosHelper : 1; + + // New 32 bits + quint32 flags : 10; quint32 allChildrenCombineOpacity : 1; + quint32 hasDecomposedTransform : 1; + quint32 dirtyTransform : 1; + quint32 dirtyTransformComponents : 1; + quint32 padding : 18; // feel free to use // Optional stacking order int globalStackingOrder; int sceneTransformIndex; + struct DecomposedTransform; + DecomposedTransform *decomposedTransform() const + { + QGraphicsItemPrivate *that = const_cast<QGraphicsItemPrivate *>(this); + DecomposedTransform *decomposed; + if (hasDecomposedTransform) { + decomposed = qVariantValue<DecomposedTransform *>(extra(ExtraDecomposedTransform)); + } else { + decomposed = new DecomposedTransform; + that->setExtra(ExtraDecomposedTransform, qVariantFromValue<DecomposedTransform *>(decomposed)); + that->hasDecomposedTransform = 1; + if (!dirtyTransformComponents) + decomposed->reset(); + } + if (dirtyTransformComponents) { + decomposed->initFrom(q_ptr->transform()); + that->dirtyTransformComponents = 0; + } + return decomposed; + } + + struct DecomposedTransform { + qreal xScale; + qreal yScale; + qreal xRotation; + qreal yRotation; + qreal zRotation; + qreal horizontalShear; + qreal verticalShear; + qreal xOrigin; + qreal yOrigin; + + inline void reset() + { + xScale = 1.0; + yScale = 1.0; + xRotation = 0.0; + yRotation = 0.0; + zRotation = 0.0; + horizontalShear = 0.0; + verticalShear = 0.0; + xOrigin = 0.0; + yOrigin = 0.0; + } + + inline void initFrom(const QTransform &x) + { + reset(); + // ### decompose transform + Q_UNUSED(x); + } + + inline void generateTransform(QTransform *x) const + { + x->translate(xOrigin, yOrigin); + x->rotate(xRotation, Qt::XAxis); + x->rotate(yRotation, Qt::YAxis); + x->rotate(zRotation, Qt::ZAxis); + x->shear(horizontalShear, verticalShear); + x->scale(xScale, yScale); + x->translate(-xOrigin, -yOrigin); + } + }; + QGraphicsItem *q_ptr; }; QT_END_NAMESPACE +Q_DECLARE_METATYPE(QGraphicsItemPrivate::DecomposedTransform *) + #endif // QT_NO_GRAPHICSVIEW #endif diff --git a/src/gui/graphicsview/qgraphicslayoutitem.cpp b/src/gui/graphicsview/qgraphicslayoutitem.cpp index eaa97ff..b58eb53 100644 --- a/src/gui/graphicsview/qgraphicslayoutitem.cpp +++ b/src/gui/graphicsview/qgraphicslayoutitem.cpp @@ -108,13 +108,22 @@ static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qre \internal */ QGraphicsLayoutItemPrivate::QGraphicsLayoutItemPrivate(QGraphicsLayoutItem *par, bool layout) - : parent(par), isLayout(layout), ownedByLayout(false), graphicsItem(0) + : parent(par), userSizeHints(0), isLayout(layout), ownedByLayout(false), graphicsItem(0) { } /*! \internal */ +QGraphicsLayoutItemPrivate::~QGraphicsLayoutItemPrivate() +{ + // Remove any lazily allocated data + delete[] userSizeHints; +} + +/*! + \internal +*/ void QGraphicsLayoutItemPrivate::init() { sizeHintCacheDirty = true; @@ -132,7 +141,8 @@ QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint) for (int i = 0; i < Qt::NSizeHints; ++i) { cachedSizeHints[i] = constraint; - combineSize(cachedSizeHints[i], userSizeHints[i]); + if (userSizeHints) + combineSize(cachedSizeHints[i], userSizeHints[i]); } QSizeF &minS = cachedSizeHints[Qt::MinimumSize]; @@ -198,6 +208,58 @@ QGraphicsItem *QGraphicsLayoutItemPrivate::parentItem() const } /*! + \internal + + Ensures that userSizeHints is allocated. + This function must be called before any dereferencing. +*/ +void QGraphicsLayoutItemPrivate::ensureUserSizeHints() +{ + if (!userSizeHints) + userSizeHints = new QSizeF[Qt::NSizeHints]; +} + +/*! + \internal + + Sets the user size hint \a which to \a size. Use an invalid size to unset the size hint. + */ +void QGraphicsLayoutItemPrivate::setSize(Qt::SizeHint which, const QSizeF &size) +{ + Q_Q(QGraphicsLayoutItem); + + if (userSizeHints) { + if (size == userSizeHints[which]) + return; + } else if (!size.isValid()) { + return; + } + + ensureUserSizeHints(); + userSizeHints[which] = size; + q->updateGeometry(); +} + +/*! + \internal + + Sets the width of the user size hint \a which to \a width. + */ +void QGraphicsLayoutItemPrivate::setSizeComponent( + Qt::SizeHint which, SizeComponent component, qreal value) +{ + Q_Q(QGraphicsLayoutItem); + ensureUserSizeHints(); + qreal &userValue = (component == Width) + ? userSizeHints[which].rwidth() + : userSizeHints[which].rheight(); + if (value == userValue) + return; + userValue = value; + q->updateGeometry(); +} + +/*! \class QGraphicsLayoutItem \brief The QGraphicsLayoutItem class can be inherited to allow your custom items to be managed by layouts. @@ -255,7 +317,7 @@ QGraphicsItem *QGraphicsLayoutItemPrivate::parentItem() const passing a QGraphicsLayoutItem pointer to QGraphicsLayoutItem's protected constructor, or by calling setParentLayoutItem(). The parentLayoutItem() function returns a pointer to the item's layoutItem - parent. If the item's parent is 0 or if the the parent does not inherit + parent. If the item's parent is 0 or if the parent does not inherit from QGraphicsItem, the parentLayoutItem() function then returns 0. isLayout() returns true if the QGraphicsLayoutItem subclass is itself a layout, or false otherwise. @@ -381,12 +443,7 @@ QSizePolicy QGraphicsLayoutItem::sizePolicy() const */ void QGraphicsLayoutItem::setMinimumSize(const QSizeF &size) { - Q_D(QGraphicsLayoutItem); - if (size == d->userSizeHints[Qt::MinimumSize]) - return; - - d->userSizeHints[Qt::MinimumSize] = size; - updateGeometry(); + d_ptr->setSize(Qt::MinimumSize, size); } /*! @@ -416,12 +473,7 @@ QSizeF QGraphicsLayoutItem::minimumSize() const */ void QGraphicsLayoutItem::setMinimumWidth(qreal width) { - Q_D(QGraphicsLayoutItem); - qreal &userSizeHint = d->userSizeHints[Qt::MinimumSize].rwidth(); - if (width == userSizeHint) - return; - userSizeHint = width; - updateGeometry(); + d_ptr->setSizeComponent(Qt::MinimumSize, d_ptr->Width, width); } /*! @@ -431,12 +483,7 @@ void QGraphicsLayoutItem::setMinimumWidth(qreal width) */ void QGraphicsLayoutItem::setMinimumHeight(qreal height) { - Q_D(QGraphicsLayoutItem); - qreal &userSizeHint = d->userSizeHints[Qt::MinimumSize].rheight(); - if (height == userSizeHint) - return; - userSizeHint = height; - updateGeometry(); + d_ptr->setSizeComponent(Qt::MinimumSize, d_ptr->Height, height); } @@ -450,12 +497,7 @@ void QGraphicsLayoutItem::setMinimumHeight(qreal height) */ void QGraphicsLayoutItem::setPreferredSize(const QSizeF &size) { - Q_D(QGraphicsLayoutItem); - if (size == d->userSizeHints[Qt::PreferredSize]) - return; - - d->userSizeHints[Qt::PreferredSize] = size; - updateGeometry(); + d_ptr->setSize(Qt::PreferredSize, size); } /*! @@ -485,12 +527,7 @@ QSizeF QGraphicsLayoutItem::preferredSize() const */ void QGraphicsLayoutItem::setPreferredHeight(qreal height) { - Q_D(QGraphicsLayoutItem); - qreal &userSizeHint = d->userSizeHints[Qt::PreferredSize].rheight(); - if (height == userSizeHint) - return; - userSizeHint = height; - updateGeometry(); + d_ptr->setSizeComponent(Qt::PreferredSize, d_ptr->Height, height); } /*! @@ -500,12 +537,7 @@ void QGraphicsLayoutItem::setPreferredHeight(qreal height) */ void QGraphicsLayoutItem::setPreferredWidth(qreal width) { - Q_D(QGraphicsLayoutItem); - qreal &userSizeHint = d->userSizeHints[Qt::PreferredSize].rwidth(); - if (width == userSizeHint) - return; - userSizeHint = width; - updateGeometry(); + d_ptr->setSizeComponent(Qt::PreferredSize, d_ptr->Width, width); } /*! @@ -519,12 +551,7 @@ void QGraphicsLayoutItem::setPreferredWidth(qreal width) */ void QGraphicsLayoutItem::setMaximumSize(const QSizeF &size) { - Q_D(QGraphicsLayoutItem); - if (size == d->userSizeHints[Qt::MaximumSize]) - return; - - d->userSizeHints[Qt::MaximumSize] = size; - updateGeometry(); + d_ptr->setSize(Qt::MaximumSize, size); } /*! @@ -554,12 +581,7 @@ QSizeF QGraphicsLayoutItem::maximumSize() const */ void QGraphicsLayoutItem::setMaximumWidth(qreal width) { - Q_D(QGraphicsLayoutItem); - qreal &userSizeHint = d->userSizeHints[Qt::MaximumSize].rwidth(); - if (width == userSizeHint) - return; - userSizeHint = width; - updateGeometry(); + d_ptr->setSizeComponent(Qt::MaximumSize, d_ptr->Width, width); } /*! @@ -569,12 +591,7 @@ void QGraphicsLayoutItem::setMaximumWidth(qreal width) */ void QGraphicsLayoutItem::setMaximumHeight(qreal height) { - Q_D(QGraphicsLayoutItem); - qreal &userSizeHint = d->userSizeHints[Qt::MaximumSize].rheight(); - if (height == userSizeHint) - return; - userSizeHint = height; - updateGeometry(); + d_ptr->setSizeComponent(Qt::MaximumSize, d_ptr->Height, height); } /*! @@ -732,6 +749,11 @@ QRectF QGraphicsLayoutItem::contentsRect() const */ QSizeF QGraphicsLayoutItem::effectiveSizeHint(Qt::SizeHint which, const QSizeF &constraint) const { + Q_D(const QGraphicsLayoutItem); + + if (!d->userSizeHints && constraint.isValid()) + return constraint; + // ### should respect size policy??? return d_ptr->effectiveSizeHints(constraint)[which]; } diff --git a/src/gui/graphicsview/qgraphicslayoutitem_p.h b/src/gui/graphicsview/qgraphicslayoutitem_p.h index fab0f39..dc044e6 100644 --- a/src/gui/graphicsview/qgraphicslayoutitem_p.h +++ b/src/gui/graphicsview/qgraphicslayoutitem_p.h @@ -63,16 +63,20 @@ class Q_AUTOTEST_EXPORT QGraphicsLayoutItemPrivate { Q_DECLARE_PUBLIC(QGraphicsLayoutItem) public: - virtual ~QGraphicsLayoutItemPrivate() {} + virtual ~QGraphicsLayoutItemPrivate(); QGraphicsLayoutItemPrivate(QGraphicsLayoutItem *parent, bool isLayout); void init(); QSizeF *effectiveSizeHints(const QSizeF &constraint) const; QGraphicsItem *parentItem() const; + void ensureUserSizeHints(); + void setSize(Qt::SizeHint which, const QSizeF &size); + enum SizeComponent { Width, Height }; + void setSizeComponent(Qt::SizeHint which, SizeComponent component, qreal value); QSizePolicy sizePolicy; QGraphicsLayoutItem *parent; - QSizeF userSizeHints[Qt::NSizeHints]; + QSizeF *userSizeHints; mutable QSizeF cachedSizeHints[Qt::NSizeHints]; mutable QSizeF cachedConstraint; diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp index 01b7593..a5b11ff 100644 --- a/src/gui/graphicsview/qgraphicsproxywidget.cpp +++ b/src/gui/graphicsview/qgraphicsproxywidget.cpp @@ -976,6 +976,7 @@ void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *even } #endif // QT_NO_CONTEXTMENU +#ifndef QT_NO_DRAGANDDROP /*! \reimp */ @@ -1096,6 +1097,7 @@ void QGraphicsProxyWidget::dropEvent(QGraphicsSceneDragDropEvent *event) } #endif } +#endif /*! \reimp diff --git a/src/gui/graphicsview/qgraphicsproxywidget.h b/src/gui/graphicsview/qgraphicsproxywidget.h index b2c3c8f..ab8c9da 100644 --- a/src/gui/graphicsview/qgraphicsproxywidget.h +++ b/src/gui/graphicsview/qgraphicsproxywidget.h @@ -90,10 +90,12 @@ protected: void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); #endif +#ifndef QT_NO_DRAGANDDROP void dragEnterEvent(QGraphicsSceneDragDropEvent *event); void dragLeaveEvent(QGraphicsSceneDragDropEvent *event); void dragMoveEvent(QGraphicsSceneDragDropEvent *event); void dropEvent(QGraphicsSceneDragDropEvent *event); +#endif void hoverEnterEvent(QGraphicsSceneHoverEvent *event); void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index f2e5f57..51c8294 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1071,7 +1071,8 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou // check if the item we are sending to are disabled (before we send the event) bool disabled = !item->isEnabled(); bool isWindow = item->isWindow(); - if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick && item != lastMouseGrabberItem) { + if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick + && item != lastMouseGrabberItem && lastMouseGrabberItem) { // If this item is different from the item that received the last // mouse event, and mouseEvent is a doubleclick event, then the // event is converted to a press. Known limitation: @@ -1983,8 +1984,6 @@ void QGraphicsScene::setSceneRect(const QRectF &rect) void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source, Qt::AspectRatioMode aspectRatioMode) { - Q_D(QGraphicsScene); - // Default source rect = scene rect QRectF sourceRect = source; if (sourceRect.isNull()) @@ -2041,41 +2040,8 @@ void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRect // Generate the style options QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems]; - for (int i = 0; i < numItems; ++i) { - QGraphicsItem *item = itemArray[i]; - - QStyleOptionGraphicsItem option; - option.state = QStyle::State_None; - option.rect = item->boundingRect().toRect(); - if (item->isSelected()) - option.state |= QStyle::State_Selected; - if (item->isEnabled()) - option.state |= QStyle::State_Enabled; - if (item->hasFocus()) - option.state |= QStyle::State_HasFocus; - if (d->hoverItems.contains(item)) - option.state |= QStyle::State_MouseOver; - if (item == mouseGrabberItem()) - option.state |= QStyle::State_Sunken; - - // Calculate a simple level-of-detail metric. - // ### almost identical code in QGraphicsView::paintEvent() - // and QGraphicsView::render() - consider refactoring - QTransform itemToDeviceTransform; - if (item->d_ptr->itemIsUntransformable()) { - itemToDeviceTransform = item->deviceTransform(painterTransform); - } else { - itemToDeviceTransform = item->sceneTransform() * painterTransform; - } - - option.levelOfDetail = qSqrt(itemToDeviceTransform.map(v1).length() * itemToDeviceTransform.map(v2).length()); - option.matrix = itemToDeviceTransform.toAffine(); //### discards perspective - - option.exposedRect = item->boundingRect(); - option.exposedRect &= itemToDeviceTransform.inverted().mapRect(targetRect); - - styleOptionArray[i] = option; - } + for (int i = 0; i < numItems; ++i) + itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect()); // Render the scene. drawBackground(painter, sourceRect); @@ -4525,8 +4491,9 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte return; // Fetch the off-screen transparent buffer and exposed area info. - QString pixmapKey; + QPixmapCache::Key pixmapKey; QPixmap pix; + bool pixmapFound; QGraphicsItemCache *itemCache = itemd->extraItemCache(); if (cacheMode == QGraphicsItem::ItemCoordinateCache) { if (itemCache->boundingRect != brect.toRect()) { @@ -4536,17 +4503,11 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } pixmapKey = itemCache->key; } else { - if ((pixmapKey = itemCache->deviceData.value(widget).key).isEmpty()) { - pixmapKey.sprintf("qgv-%p-%p", item, widget); - QGraphicsItemCache::DeviceData data; - data.key = pixmapKey; - itemCache->deviceData.insert(widget, data); - } + pixmapKey = itemCache->deviceData.value(widget).key; } // Find pixmap in cache. - if (!itemCache->allExposed) - QPixmapCache::find(pixmapKey, pix); + pixmapFound = QPixmapCache::find(pixmapKey, &pix); // Render using item coordinate cache mode. if (cacheMode == QGraphicsItem::ItemCoordinateCache) { @@ -4571,6 +4532,12 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte // Redraw any newly exposed areas. if (itemCache->allExposed || !itemCache->exposed.isEmpty()) { + + //We know that we will modify the pixmap, removing it from the cache + //will detach the one we have and avoid a deep copy + if (pixmapFound) + QPixmapCache::remove(pixmapKey); + // Fit the item's bounding rect into the pixmap's coordinates. QTransform itemToPixmap; if (fixedCacheSize) { @@ -4599,8 +4566,8 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(), &cacheOption, painterStateProtection); - // Reinsert this pixmap into the cache. - QPixmapCache::insert(pixmapKey, pix); + // insert this pixmap into the cache. + itemCache->key = QPixmapCache::insert(pix); // Reset expose data. itemCache->allExposed = false; @@ -4727,6 +4694,11 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte // Check for newly invalidated areas. if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) { + //We know that we will modify the pixmap, removing it from the cache + //will detach the one we have and avoid a deep copy + if (pixmapFound) + QPixmapCache::remove(pixmapKey); + // Construct an item-to-pixmap transform. QPointF p = deviceRect.topLeft(); QTransform itemToPixmap = painter->worldTransform(); @@ -4767,8 +4739,8 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } if (pixModified) { - // Reinsert this pixmap into the cache - QPixmapCache::insert(pixmapKey, pix); + // Insert this pixmap into the cache. + deviceData->key = QPixmapCache::insert(pix); } // Redraw the exposed area using an untransformed painter. This @@ -4881,11 +4853,7 @@ void QGraphicsScene::drawItems(QPainter *painter, // optimization, but it's hit very rarely. for (int i = clippers.size() - 1; i >= 0; --i) { QGraphicsItem *clipper = clippers[i]; - if (clipper->d_ptr->itemIsUntransformable()) { - painter->setWorldTransform(clipper->deviceTransform(viewTransform), false); - } else { - painter->setWorldTransform(clipper->sceneTransform() * viewTransform, false); - } + painter->setWorldTransform(clipper->deviceTransform(viewTransform), false); childClippers.append(clipper); painter->save(); @@ -4896,12 +4864,8 @@ void QGraphicsScene::drawItems(QPainter *painter, } // Set up the painter transform - if (item->d_ptr->itemIsUntransformable()) { - painter->setWorldTransform(item->deviceTransform(viewTransform), false); - } else { - painter->setWorldTransform(item->sceneTransform() * viewTransform, false); - } - + painter->setWorldTransform(item->deviceTransform(viewTransform), false); + // Save painter bool saveState = (d->painterStateProtection || (item->flags() & QGraphicsItem::ItemClipsToShape)); if (saveState) diff --git a/src/gui/graphicsview/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp index b819c2c..0ffd2b1 100644 --- a/src/gui/graphicsview/qgraphicssceneevent.cpp +++ b/src/gui/graphicsview/qgraphicssceneevent.cpp @@ -844,7 +844,7 @@ QGraphicsSceneContextMenuEvent::~QGraphicsSceneContextMenuEvent() /*! Returns the position of the mouse cursor in item coordinates at the moment - the the context menu was requested. + the context menu was requested. \sa scenePos(), screenPos() */ @@ -992,7 +992,7 @@ QGraphicsSceneHoverEvent::~QGraphicsSceneHoverEvent() /*! Returns the position of the mouse cursor in item coordinates at the moment - the the hover event was sent. + the hover event was sent. \sa scenePos(), screenPos() */ @@ -1017,7 +1017,7 @@ void QGraphicsSceneHoverEvent::setPos(const QPointF &pos) /*! Returns the position of the mouse cursor in scene coordinates at the - moment the the hover event was sent. + moment the hover event was sent. \sa pos(), screenPos() */ @@ -1042,7 +1042,7 @@ void QGraphicsSceneHoverEvent::setScenePos(const QPointF &pos) /*! Returns the position of the mouse cursor in screen coordinates at the - moment the the hover event was sent. + moment the hover event was sent. \sa pos(), scenePos() */ @@ -1138,7 +1138,7 @@ void QGraphicsSceneHoverEvent::setLastScreenPos(const QPoint &pos) /*! \since 4.4 - Returns the keyboard modifiers at the moment the the hover event was sent. + Returns the keyboard modifiers at the moment the hover event was sent. */ Qt::KeyboardModifiers QGraphicsSceneHoverEvent::modifiers() const { @@ -1184,7 +1184,7 @@ QGraphicsSceneHelpEvent::~QGraphicsSceneHelpEvent() /*! Returns the position of the mouse cursor in scene coordinates at the - moment the the help event was sent. + moment the help event was sent. \sa screenPos() */ @@ -1209,7 +1209,7 @@ void QGraphicsSceneHelpEvent::setScenePos(const QPointF &pos) /*! Returns the position of the mouse cursor in screen coordinates at the - moment the the help event was sent. + moment the help event was sent. \sa scenePos() */ diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 7720a10..10b837a 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -200,16 +200,7 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < Note that setting a flag usually imposes a side effect, and this effect can vary between paint devices and platforms. - \value DontClipPainter QGraphicsView sometimes clips the painter when - rendering the scene contents. This can generally improve performance - (e.g., rendering only small parts of a large pixmap), and protects against - rendering mistakes (e.g., drawing outside bounding rectangles, or outside - the exposed area). In some situations, however, the painter clip can slow - down rendering; especially when all painting is restricted to inside - exposed areas. By enabling this flag, QGraphicsView will completely - disable its implicit clipping. Note that rendering artifacts from using a - semi-transparent foreground or background brush can occur if clipping is - disabled. + \value DontClipPainter This value is obsolete and has no effect. \value DontSavePainterState When rendering, QGraphicsView protects the painter state (see QPainter::save()) when rendering the background or @@ -587,10 +578,6 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event) return; if (!scene) return; - if (scene->d_func()->allItemsIgnoreHoverEvents && scene->d_func()->allItemsUseDefaultCursor - && !event->buttons()) { // forward event to the scene if something is pressed. - return; // No need to process this event further. - } QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove); mouseEvent.setWidget(q->viewport()); @@ -1085,8 +1072,12 @@ QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedReg QList<QGraphicsItem *> itemList(scene->items()); int i = 0; while (i < itemList.size()) { + const QGraphicsItem *item = itemList.at(i); // But we only want to include items that are visible - if (!itemList.at(i)->isVisible()) + // The following check is basically the same as item->d_ptr->isInvisible(), except + // that we don't check whether the item clips children to shape or propagates its + // opacity (we loop through all items, so those checks are wrong in this context). + if (!item->isVisible() || item->d_ptr->isClippedAway() || item->d_ptr->isFullyTransparent()) itemList.removeAt(i); else ++i; @@ -1127,73 +1118,6 @@ QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedReg return itemsInArea(exposedPath, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder); } -void QGraphicsViewPrivate::generateStyleOptions(const QList<QGraphicsItem *> &itemList, - QGraphicsItem **itemArray, - QStyleOptionGraphicsItem *styleOptionArray, - const QTransform &worldTransform, - bool allItems, - const QRegion &exposedRegion) const -{ - // Two unit vectors. - QLineF v1(0, 0, 1, 0); - QLineF v2(0, 0, 0, 1); - QTransform itemToViewportTransform; - QRectF brect; - QTransform reverseMap; - - for (int i = 0; i < itemList.size(); ++i) { - QGraphicsItem *item = itemArray[i] = itemList[i]; - - QStyleOptionGraphicsItem &option = styleOptionArray[i]; - brect = item->boundingRect(); - option.state = QStyle::State_None; - option.rect = brect.toRect(); - option.exposedRect = QRectF(); - if (item->d_ptr->selected) - option.state |= QStyle::State_Selected; - if (item->d_ptr->enabled) - option.state |= QStyle::State_Enabled; - if (item->hasFocus()) - option.state |= QStyle::State_HasFocus; - if (scene->d_func()->hoverItems.contains(item)) - option.state |= QStyle::State_MouseOver; - if (item == scene->mouseGrabberItem()) - option.state |= QStyle::State_Sunken; - - // Calculate a simple level-of-detail metric. - // ### almost identical code in QGraphicsScene::render() - // and QGraphicsView::render() - consider refactoring - if (item->d_ptr->itemIsUntransformable()) { - itemToViewportTransform = item->deviceTransform(worldTransform); - } else { - itemToViewportTransform = item->sceneTransform() * worldTransform; - } - - if (itemToViewportTransform.type() <= QTransform::TxTranslate) { - // Translation and rotation only? The LOD is 1. - option.levelOfDetail = 1; - } else { - // LOD is the transformed area of a 1x1 rectangle. - option.levelOfDetail = qSqrt(itemToViewportTransform.map(v1).length() * itemToViewportTransform.map(v2).length()); - } - option.matrix = itemToViewportTransform.toAffine(); //### discards perspective - - if (!allItems) { - // Determine the item's exposed area - reverseMap = itemToViewportTransform.inverted(); - foreach (const QRect &rect, exposedRegion.rects()) { - option.exposedRect |= reverseMap.mapRect(QRectF(rect.adjusted(-1, -1, 1, 1))); - if (option.exposedRect.contains(brect)) - break; - } - option.exposedRect &= brect; - } else { - // The whole item is exposed - option.exposedRect = brect; - } - } -} - /*! Constructs a QGraphicsView. \a parent is passed to QWidget's constructor. */ @@ -1691,6 +1615,7 @@ void QGraphicsView::setScene(QGraphicsScene *scene) disconnect(d->scene, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(updateSceneRect(QRectF))); d->scene->d_func()->views.removeAll(this); + d->connectedToScene = false; } // Assign the new scene and update the contents (scrollbars, etc.)). @@ -2149,45 +2074,10 @@ void QGraphicsView::render(QPainter *painter, const QRectF &target, const QRect .scale(xratio, yratio) .translate(-sourceRect.left(), -sourceRect.top()); - // Two unit vectors. - QLineF v1(0, 0, 1, 0); - QLineF v2(0, 0, 0, 1); - // Generate the style options QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems); - QStyleOptionGraphicsItem* option = styleOptionArray; - for (int i = 0; i < numItems; ++i, ++option) { - QGraphicsItem *item = itemArray[i]; - - option->state = QStyle::State_None; - option->rect = item->boundingRect().toRect(); - if (item->isSelected()) - option->state |= QStyle::State_Selected; - if (item->isEnabled()) - option->state |= QStyle::State_Enabled; - if (item->hasFocus()) - option->state |= QStyle::State_HasFocus; - if (d->scene->d_func()->hoverItems.contains(item)) - option->state |= QStyle::State_MouseOver; - if (item == d->scene->mouseGrabberItem()) - option->state |= QStyle::State_Sunken; - - // Calculate a simple level-of-detail metric. - // ### almost identical code in QGraphicsScene::render() - // and QGraphicsView::paintEvent() - consider refactoring - QTransform itemToViewportTransform; - if (item->d_ptr->itemIsUntransformable()) { - itemToViewportTransform = item->deviceTransform(painterMatrix); - } else { - itemToViewportTransform = item->sceneTransform() * painterMatrix; - } - - option->levelOfDetail = qSqrt(itemToViewportTransform.map(v1).length() * itemToViewportTransform.map(v2).length()); - option->matrix = itemToViewportTransform.toAffine(); - - option->exposedRect = item->boundingRect(); - option->exposedRect &= itemToViewportTransform.inverted().mapRect(targetRect); - } + for (int i = 0; i < numItems; ++i) + itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterMatrix, targetRect.toRect()); painter->save(); @@ -3490,7 +3380,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event) #ifdef QGRAPHICSVIEW_DEBUG QTime stopWatch; stopWatch.start(); - qDebug() << "QGraphicsView::paintEvent(" << exposedRegion << ")"; + qDebug() << "QGraphicsView::paintEvent(" << exposedRegion << ')'; #endif // Find all exposed items @@ -3546,15 +3436,17 @@ void QGraphicsView::paintEvent(QPaintEvent *event) int backgroundTime = stopWatch.elapsed() - exposedTime; #endif - // Generate the style options - QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()]; - QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(itemList.size()); - - d->generateStyleOptions(itemList, itemArray, styleOptionArray, viewTransform, - allItems, exposedRegion); - - // Items - drawItems(&painter, itemList.size(), itemArray, styleOptionArray); + if (!itemList.isEmpty()) { + // Generate the style options. + const int numItems = itemList.size(); + QGraphicsItem **itemArray = &itemList[0]; // Relies on QList internals, but is perfectly valid. + QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems); + for (int i = 0; i < numItems; ++i) + itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], viewTransform, exposedRegion, allItems); + // Draw the items. + drawItems(&painter, numItems, itemArray, styleOptionArray); + d->freeStyleOptionsArray(styleOptionArray); + } #ifdef QGRAPHICSVIEW_DEBUG int itemsTime = stopWatch.elapsed() - exposedTime - backgroundTime; @@ -3563,9 +3455,6 @@ void QGraphicsView::paintEvent(QPaintEvent *event) // Foreground drawForeground(&painter, exposedSceneRect); - delete [] itemArray; - d->freeStyleOptionsArray(styleOptionArray); - #ifdef QGRAPHICSVIEW_DEBUG int foregroundTime = stopWatch.elapsed() - exposedTime - backgroundTime - itemsTime; #endif diff --git a/src/gui/graphicsview/qgraphicsview.h b/src/gui/graphicsview/qgraphicsview.h index e77e45c..c3ea6e5 100644 --- a/src/gui/graphicsview/qgraphicsview.h +++ b/src/gui/graphicsview/qgraphicsview.h @@ -110,7 +110,7 @@ public: }; enum OptimizationFlag { - DontClipPainter = 0x1, + DontClipPainter = 0x1, // obsolete DontSavePainterState = 0x2, DontAdjustForAntialiasing = 0x4 }; diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h index a76279e..c18f85d 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE -class Q_GUI_EXPORT QGraphicsViewPrivate : public QAbstractScrollAreaPrivate +class QGraphicsViewPrivate : public QAbstractScrollAreaPrivate { Q_DECLARE_PUBLIC(QGraphicsView) public: @@ -174,13 +174,6 @@ public: bool updateSceneSlotReimplementedChecked; QList<QGraphicsItem *> findItems(const QRegion &exposedRegion, bool *allItems) const; - - void generateStyleOptions(const QList<QGraphicsItem *> &itemList, - QGraphicsItem **itemArray, - QStyleOptionGraphicsItem *styleOptionArray, - const QTransform &worldTransform, - bool allItems, - const QRegion &exposedRegion) const; }; QT_END_NAMESPACE diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 66930f2..341f9a2 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -200,7 +200,55 @@ QT_BEGIN_NAMESPACE /*! \property QGraphicsWidget::pos \brief the position of the widget -*/ +*/ + +/*! + \property QGraphicsWidget::xRotation + \since 4.6 + \brief the rotation angle in degrees around the X axis +*/ + +/*! + \property QGraphicsWidget::yRotation + \since 4.6 + \brief the rotation angle in degrees around the Y axis +*/ + +/*! + \property QGraphicsWidget::zRotation + \since 4.6 + \brief the rotation angle in degrees around the Z axis +*/ + +/*! + \property QGraphicsWidget::xScale + \since 4.6 + \brief the scale factor on the X axis. +*/ + +/*! + \property QGraphicsWidget::yScale + \since 4.6 + \brief the scale factor on the Y axis. +*/ + +/*! + \property QGraphicsWidget::horizontalShear + \since 4.6 + \brief the horizontal shear. +*/ + +/*! + \property QGraphicsWidget::verticalShear + \since 4.6 + \brief the vertical shear. +*/ + +/*! + \property QGraphicsWidget::transformOrigin + \since 4.6 + \brief the transformation origin for the transformation properties. +*/ /*! Constructs a QGraphicsWidget instance. The optional \a parent argument is @@ -459,17 +507,19 @@ void QGraphicsWidget::setContentsMargins(qreal left, qreal top, qreal right, qre { Q_D(QGraphicsWidget); - if (left == d->leftMargin - && top == d->topMargin - && right == d->rightMargin - && bottom == d->bottomMargin) { + if (!d->margins && left == 0 && top == 0 && right == 0 && bottom == 0) + return; + d->ensureMargins(); + if (left == d->margins[d->Left] + && top == d->margins[d->Top] + && right == d->margins[d->Right] + && bottom == d->margins[d->Bottom]) return; - } - d->leftMargin = left; - d->topMargin = top; - d->rightMargin = right; - d->bottomMargin = bottom; + d->margins[d->Left] = left; + d->margins[d->Top] = top; + d->margins[d->Right] = right; + d->margins[d->Bottom] = bottom; if (QGraphicsLayout *l = d->layout) l->invalidate(); @@ -490,14 +540,16 @@ void QGraphicsWidget::setContentsMargins(qreal left, qreal top, qreal right, qre void QGraphicsWidget::getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const { Q_D(const QGraphicsWidget); + if (left || top || right || bottom) + d->ensureMargins(); if (left) - *left = d->leftMargin; + *left = d->margins[d->Left]; if (top) - *top = d->topMargin; + *top = d->margins[d->Top]; if (right) - *right = d->rightMargin; + *right = d->margins[d->Right]; if (bottom) - *bottom = d->bottomMargin; + *bottom = d->margins[d->Bottom]; } /*! @@ -513,16 +565,23 @@ void QGraphicsWidget::getContentsMargins(qreal *left, qreal *top, qreal *right, void QGraphicsWidget::setWindowFrameMargins(qreal left, qreal top, qreal right, qreal bottom) { Q_D(QGraphicsWidget); - bool unchanged = left == d->leftWindowFrameMargin && top == d->topWindowFrameMargin - && right == d->rightWindowFrameMargin && bottom == d->bottomWindowFrameMargin; + + if (!d->windowFrameMargins && left == 0 && top == 0 && right == 0 && bottom == 0) + return; + d->ensureWindowFrameMargins(); + bool unchanged = + d->windowFrameMargins[d->Left] == left + && d->windowFrameMargins[d->Top] == top + && d->windowFrameMargins[d->Right] == right + && d->windowFrameMargins[d->Bottom] == bottom; if (d->setWindowFrameMargins && unchanged) return; if (!unchanged) prepareGeometryChange(); - d->leftWindowFrameMargin = left; - d->topWindowFrameMargin = top; - d->rightWindowFrameMargin = right; - d->bottomWindowFrameMargin = bottom; + d->windowFrameMargins[d->Left] = left; + d->windowFrameMargins[d->Top] = top; + d->windowFrameMargins[d->Right] = right; + d->windowFrameMargins[d->Bottom] = bottom; d->setWindowFrameMargins = true; } @@ -536,14 +595,16 @@ void QGraphicsWidget::setWindowFrameMargins(qreal left, qreal top, qreal right, void QGraphicsWidget::getWindowFrameMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const { Q_D(const QGraphicsWidget); + if (left || top || right || bottom) + d->ensureWindowFrameMargins(); if (left) - *left = d->leftWindowFrameMargin; + *left = d->windowFrameMargins[d->Left]; if (top) - *top = d->topWindowFrameMargin; + *top = d->windowFrameMargins[d->Top]; if (right) - *right = d->rightWindowFrameMargin; + *right = d->windowFrameMargins[d->Right]; if (bottom) - *bottom = d->bottomWindowFrameMargin; + *bottom = d->windowFrameMargins[d->Bottom]; } /*! @@ -577,8 +638,10 @@ void QGraphicsWidget::unsetWindowFrameMargins() QRectF QGraphicsWidget::windowFrameGeometry() const { Q_D(const QGraphicsWidget); - return geometry().adjusted(-d->leftWindowFrameMargin, -d->topWindowFrameMargin, - d->rightWindowFrameMargin, d->bottomWindowFrameMargin); + return d->windowFrameMargins + ? geometry().adjusted(-d->windowFrameMargins[d->Left], -d->windowFrameMargins[d->Top], + d->windowFrameMargins[d->Right], d->windowFrameMargins[d->Bottom]) + : geometry(); } /*! @@ -589,8 +652,10 @@ QRectF QGraphicsWidget::windowFrameGeometry() const QRectF QGraphicsWidget::windowFrameRect() const { Q_D(const QGraphicsWidget); - return rect().adjusted(-d->leftWindowFrameMargin, -d->topWindowFrameMargin, - d->rightWindowFrameMargin, d->bottomWindowFrameMargin); + return d->windowFrameMargins + ? rect().adjusted(-d->windowFrameMargins[d->Left], -d->windowFrameMargins[d->Top], + d->windowFrameMargins[d->Right], d->windowFrameMargins[d->Bottom]) + : rect(); } /*! @@ -699,7 +764,10 @@ QSizeF QGraphicsWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) c QSizeF sh; if (d->layout) { sh = d->layout->effectiveSizeHint(which, constraint); - sh += QSizeF(d->leftMargin + d->rightMargin, d->topMargin + d->bottomMargin); + if (d->margins) { + sh += QSizeF(d->margins[d->Left] + d->margins[d->Right], + d->margins[d->Top] + d->margins[d->Bottom]); + } } else { switch (which) { case Qt::MinimumSize: @@ -1127,7 +1195,8 @@ bool QGraphicsWidget::windowFrameEvent(QEvent *event) d->windowFrameMousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event)); break; case QEvent::GraphicsSceneMouseMove: - if (d->grabbedSection != Qt::NoSection) { + d->ensureWindowData(); + if (d->windowData->grabbedSection != Qt::NoSection) { d->windowFrameMouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event)); event->accept(); } @@ -1182,7 +1251,8 @@ Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos) const qreal cornerMargin = 20; //### Not sure of this one, it should be the same value for all edges. - const qreal windowFrameWidth = d->leftWindowFrameMargin; + const qreal windowFrameWidth = d->windowFrameMargins + ? d->windowFrameMargins[d->Left] : 0; Qt::WindowFrameSection s = Qt::NoSection; if (x <= left + cornerMargin) { @@ -1208,7 +1278,8 @@ Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos) } if (s == Qt::NoSection) { QRectF r1 = r; - r1.setHeight(d->topWindowFrameMargin); + r1.setHeight(d->windowFrameMargins + ? d->windowFrameMargins[d->Top] : 0); if (r1.contains(pos)) s = Qt::TitleBarArea; } @@ -1316,7 +1387,8 @@ bool QGraphicsWidget::event(QEvent *event) case QEvent::GraphicsSceneMouseMove: case QEvent::GraphicsSceneMouseRelease: case QEvent::GraphicsSceneMouseDoubleClick: - if (d->hasDecoration() && d->grabbedSection != Qt::NoSection) + d->ensureWindowData(); + if (d->hasDecoration() && d->windowData->grabbedSection != Qt::NoSection) return windowFrameEvent(event); break; case QEvent::GraphicsSceneHoverEnter: @@ -1669,12 +1741,13 @@ bool QGraphicsWidget::isActiveWindow() const void QGraphicsWidget::setWindowTitle(const QString &title) { Q_D(QGraphicsWidget); - d->windowTitle = title; + d->ensureWindowData(); + d->windowData->windowTitle = title; } QString QGraphicsWidget::windowTitle() const { Q_D(const QGraphicsWidget); - return d->windowTitle; + return d->windowData ? d->windowData->windowTitle : QString(); } /*! @@ -2110,11 +2183,12 @@ void QGraphicsWidget::paintWindowFrame(QPainter *painter, const QStyleOptionGrap QStyleOptionTitleBar bar; bar.QStyleOption::operator=(*option); d->initStyleOptionTitleBar(&bar); // this clear flags in bar.state - if (d->buttonMouseOver) + d->ensureWindowData(); + if (d->windowData->buttonMouseOver) bar.state |= QStyle::State_MouseOver; else bar.state &= ~QStyle::State_MouseOver; - if (d->buttonSunken) + if (d->windowData->buttonSunken) bar.state |= QStyle::State_Sunken; else bar.state &= ~QStyle::State_Sunken; @@ -2269,7 +2343,7 @@ void QGraphicsWidget::dumpFocusChain() qWarning("Found a focus chain that is not circular, (next == 0)"); break; } - qDebug() << i++ << QString::number(uint(next), 16) << next->className() << next->data(0) << QString::fromAscii("focusItem:%1").arg(next->hasFocus() ? "1" : "0") << QLatin1String("next:") << next->d_func()->focusNext->data(0) << QLatin1String("prev:") << next->d_func()->focusPrev->data(0); + qDebug() << i++ << QString::number(uint(next), 16) << next->className() << next->data(0) << QString::fromAscii("focusItem:%1").arg(next->hasFocus() ? '1' : '0') << QLatin1String("next:") << next->d_func()->focusNext->data(0) << QLatin1String("prev:") << next->d_func()->focusPrev->data(0); if (visited.contains(next)) { qWarning("Already visited this node. However, I expected to dump until I found myself."); break; diff --git a/src/gui/graphicsview/qgraphicswidget.h b/src/gui/graphicsview/qgraphicswidget.h index 34f1c5f..a5c9068 100644 --- a/src/gui/graphicsview/qgraphicswidget.h +++ b/src/gui/graphicsview/qgraphicswidget.h @@ -81,7 +81,14 @@ class Q_GUI_EXPORT QGraphicsWidget : public QObject, public QGraphicsItem, publi Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) Q_PROPERTY(QPointF pos READ pos WRITE setPos) Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) - + Q_PROPERTY(QPointF transformOrigin READ transformOrigin WRITE setTransformOrigin) + Q_PROPERTY(qreal xRotation READ xRotation WRITE setXRotation) + Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation) + Q_PROPERTY(qreal zRotation READ zRotation WRITE setZRotation) + Q_PROPERTY(qreal xScale READ xScale WRITE setXScale) + Q_PROPERTY(qreal yScale READ yScale WRITE setYScale) + Q_PROPERTY(qreal horizontalShear READ horizontalShear WRITE setHorizontalShear) + Q_PROPERTY(qreal verticalShear READ verticalShear WRITE setVerticalShear) public: QGraphicsWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0); ~QGraphicsWidget(); diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp index 4b41a31..a435758 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.cpp +++ b/src/gui/graphicsview/qgraphicswidget_p.cpp @@ -76,6 +76,7 @@ void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFl resolveLayoutDirection(); q->unsetWindowFrameMargins(); + q->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption); } qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const { @@ -89,56 +90,57 @@ qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options return (qreal)height; } -void QGraphicsWidgetPrivate::getLayoutItemMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const +/*! + \internal +*/ +QGraphicsWidgetPrivate::~QGraphicsWidgetPrivate() { - if (left) - *left = leftLayoutItemMargin; - if (top) - *top = topLayoutItemMargin; - if (right) - *right = rightLayoutItemMargin; - if (bottom) - *bottom = bottomLayoutItemMargin; + // Remove any lazily allocated data + delete[] margins; + delete[] windowFrameMargins; + delete windowData; } -void QGraphicsWidgetPrivate::setLayoutItemMargins(qreal left, qreal top, qreal right, qreal bottom) -{ - if (leftLayoutItemMargin == left - && topLayoutItemMargin == top - && rightLayoutItemMargin == right - && bottomLayoutItemMargin == bottom) - return; +/*! + \internal - Q_Q(QGraphicsWidget); - leftLayoutItemMargin = left; - topLayoutItemMargin = top; - rightLayoutItemMargin = right; - bottomLayoutItemMargin = bottom; - q->updateGeometry(); + Ensures that margins is allocated. + This function must be called before any dereferencing. +*/ +void QGraphicsWidgetPrivate::ensureMargins() const +{ + if (!margins) { + margins = new qreal[4]; + for (int i = 0; i < 4; ++i) + margins[i] = 0; + } } -void QGraphicsWidgetPrivate::setLayoutItemMargins(QStyle::SubElement element, const QStyleOption *opt) +/*! + \internal + + Ensures that windowFrameMargins is allocated. + This function must be called before any dereferencing. +*/ +void QGraphicsWidgetPrivate::ensureWindowFrameMargins() const { - Q_Q(QGraphicsWidget); - QStyleOption myOpt; - if (!opt) { - q->initStyleOption(&myOpt); - myOpt.rect.setRect(0, 0, 32768, 32768); // arbitrary - opt = &myOpt; + if (!windowFrameMargins) { + windowFrameMargins = new qreal[4]; + for (int i = 0; i < 4; ++i) + windowFrameMargins[i] = 0; } +} - QRect liRect = q->style()->subElementRect(element, opt, /* q */ 0); - if (liRect.isValid()) { - leftLayoutItemMargin = (opt->rect.left() - liRect.left()); - topLayoutItemMargin = (opt->rect.top() - liRect.top()); - rightLayoutItemMargin = (liRect.right() - opt->rect.right()); - bottomLayoutItemMargin = (liRect.bottom() - opt->rect.bottom()); - } else { - leftLayoutItemMargin = 0; - topLayoutItemMargin = 0; - rightLayoutItemMargin = 0; - bottomLayoutItemMargin = 0; - } +/*! + \internal + + Ensures that windowData is allocated. + This function must be called before any dereferencing. +*/ +void QGraphicsWidgetPrivate::ensureWindowData() +{ + if (!windowData) + windowData = new WindowData; } void QGraphicsWidgetPrivate::setPalette_helper(const QPalette &palette) @@ -297,11 +299,12 @@ QFont QGraphicsWidgetPrivate::naturalWidgetFont() const void QGraphicsWidgetPrivate::initStyleOptionTitleBar(QStyleOptionTitleBar *option) { Q_Q(QGraphicsWidget); + ensureWindowData(); q->initStyleOption(option); option->rect.setHeight(titleBarHeight(*option)); option->titleBarFlags = windowFlags; option->subControls = QStyle::SC_TitleBarCloseButton | QStyle::SC_TitleBarLabel | QStyle::SC_TitleBarSysMenu; - option->activeSubControls = hoveredSubControl; + option->activeSubControls = windowData->hoveredSubControl; bool isActive = q->isActiveWindow(); if (isActive) { option->state |= QStyle::State_Active; @@ -313,7 +316,8 @@ void QGraphicsWidgetPrivate::initStyleOptionTitleBar(QStyleOptionTitleBar *optio } QFont windowTitleFont = QApplication::font("QWorkspaceTitleBar"); QRect textRect = q->style()->subControlRect(QStyle::CC_TitleBar, option, QStyle::SC_TitleBarLabel, 0); - option->text = QFontMetrics(windowTitleFont).elidedText(windowTitle, Qt::ElideRight, textRect.width()); + option->text = QFontMetrics(windowTitleFont).elidedText( + windowData->windowTitle, Qt::ElideRight, textRect.width()); } void QGraphicsWidgetPrivate::adjustWindowFlags(Qt::WindowFlags *flags) @@ -341,9 +345,10 @@ void QGraphicsWidgetPrivate::adjustWindowFlags(Qt::WindowFlags *flags) void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEvent *event) { Q_Q(QGraphicsWidget); - if (grabbedSection != Qt::NoSection) { - if (grabbedSection == Qt::TitleBarArea) { - buttonSunken = false; + ensureWindowData(); + if (windowData->grabbedSection != Qt::NoSection) { + if (windowData->grabbedSection == Qt::TitleBarArea) { + windowData->buttonSunken = false; QStyleOptionTitleBar bar; initStyleOptionTitleBar(&bar); // make sure that the coordinates (rect and pos) we send to the style are positive. @@ -351,8 +356,10 @@ void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEve bar.rect.moveTo(0,0); bar.rect.setHeight(q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &bar)); QPointF pos = event->pos(); - pos.rx() += leftWindowFrameMargin; - pos.ry() += topWindowFrameMargin; + if (windowFrameMargins) { + pos.rx() += windowFrameMargins[Left]; + pos.ry() += windowFrameMargins[Top]; + } bar.subControls = QStyle::SC_TitleBarCloseButton; if (q->style()->subControlRect(QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarCloseButton, @@ -361,7 +368,7 @@ void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEve } } if (!(static_cast<QGraphicsSceneMouseEvent *>(event)->buttons())) - grabbedSection = Qt::NoSection; + windowData->grabbedSection = Qt::NoSection; event->accept(); } } @@ -372,35 +379,16 @@ void QGraphicsWidgetPrivate::windowFrameMousePressEvent(QGraphicsSceneMouseEvent if (event->button() != Qt::LeftButton) return; - startGeometry = q->geometry(); - grabbedSection = q->windowFrameSectionAt(event->pos()); - switch (grabbedSection) { - case Qt::LeftSection: - case Qt::TopLeftSection: - mouseDelta = event->pos() - q->rect().topLeft(); - break; - case Qt::TopSection: - case Qt::TopRightSection: - mouseDelta = event->pos() - q->rect().topRight(); - break; - case Qt::RightSection: - case Qt::BottomRightSection: - mouseDelta = event->pos() - q->rect().bottomRight(); - break; - case Qt::BottomSection: - case Qt::BottomLeftSection: - mouseDelta = event->pos() - q->rect().bottomLeft(); - break; - case Qt::TitleBarArea: - if (hoveredSubControl == QStyle::SC_TitleBarCloseButton) { - buttonSunken = true; - q->update(); - } - break; - case Qt::NoSection: - break; + ensureWindowData(); + windowData->startGeometry = q->geometry(); + windowData->grabbedSection = q->windowFrameSectionAt(event->pos()); + ensureWindowData(); + if (windowData->grabbedSection == Qt::TitleBarArea + && windowData->hoveredSubControl == QStyle::SC_TitleBarCloseButton) { + windowData->buttonSunken = true; + q->update(); } - event->setAccepted(grabbedSection != Qt::NoSection); + event->setAccepted(windowData->grabbedSection != Qt::NoSection); } static void _q_boundGeometryToSizeConstraints(const QRectF &startGeometry, @@ -455,7 +443,8 @@ static void _q_boundGeometryToSizeConstraints(const QRectF &startGeometry, void QGraphicsWidgetPrivate::windowFrameMouseMoveEvent(QGraphicsSceneMouseEvent *event) { Q_Q(QGraphicsWidget); - if (!(event->buttons() & Qt::LeftButton) || hoveredSubControl != QStyle::SC_TitleBarLabel) + ensureWindowData(); + if (!(event->buttons() & Qt::LeftButton) || windowData->hoveredSubControl != QStyle::SC_TitleBarLabel) return; QLineF delta(q->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)), event->pos()); @@ -464,49 +453,56 @@ void QGraphicsWidgetPrivate::windowFrameMouseMoveEvent(QGraphicsSceneMouseEvent QLineF parentYDelta(q->mapToParent(QPointF(0, delta.p1().y())), q->mapToParent(QPointF(0, delta.p2().y()))); QRectF newGeometry; - switch (grabbedSection) { + switch (windowData->grabbedSection) { case Qt::LeftSection: - newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentXDelta.dx(), parentXDelta.dy()), - startGeometry.size() - QSizeF(delta.dx(), delta.dy())); + newGeometry = QRectF(windowData->startGeometry.topLeft() + + QPointF(parentXDelta.dx(), parentXDelta.dy()), + windowData->startGeometry.size() - QSizeF(delta.dx(), delta.dy())); break; case Qt::TopLeftSection: - newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentDelta.dx(), parentDelta.dy()), - startGeometry.size() - QSizeF(delta.dx(), delta.dy())); + newGeometry = QRectF(windowData->startGeometry.topLeft() + + QPointF(parentDelta.dx(), parentDelta.dy()), + windowData->startGeometry.size() - QSizeF(delta.dx(), delta.dy())); break; case Qt::TopSection: - newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentYDelta.dx(), parentYDelta.dy()), - startGeometry.size() - QSizeF(0, delta.dy())); + newGeometry = QRectF(windowData->startGeometry.topLeft() + + QPointF(parentYDelta.dx(), parentYDelta.dy()), + windowData->startGeometry.size() - QSizeF(0, delta.dy())); break; case Qt::TopRightSection: - newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentYDelta.dx(), parentYDelta.dy()), - startGeometry.size() - QSizeF(-delta.dx(), delta.dy())); + newGeometry = QRectF(windowData->startGeometry.topLeft() + + QPointF(parentYDelta.dx(), parentYDelta.dy()), + windowData->startGeometry.size() - QSizeF(-delta.dx(), delta.dy())); break; case Qt::RightSection: - newGeometry = QRectF(startGeometry.topLeft(), - startGeometry.size() + QSizeF(delta.dx(), 0)); + newGeometry = QRectF(windowData->startGeometry.topLeft(), + windowData->startGeometry.size() + QSizeF(delta.dx(), 0)); break; case Qt::BottomRightSection: - newGeometry = QRectF(startGeometry.topLeft(), - startGeometry.size() + QSizeF(delta.dx(), delta.dy())); + newGeometry = QRectF(windowData->startGeometry.topLeft(), + windowData->startGeometry.size() + QSizeF(delta.dx(), delta.dy())); break; case Qt::BottomSection: - newGeometry = QRectF(startGeometry.topLeft(), - startGeometry.size() + QSizeF(0, delta.dy())); + newGeometry = QRectF(windowData->startGeometry.topLeft(), + windowData->startGeometry.size() + QSizeF(0, delta.dy())); break; case Qt::BottomLeftSection: - newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentXDelta.dx(), parentXDelta.dy()), - startGeometry.size() - QSizeF(delta.dx(), -delta.dy())); + newGeometry = QRectF(windowData->startGeometry.topLeft() + + QPointF(parentXDelta.dx(), parentXDelta.dy()), + windowData->startGeometry.size() - QSizeF(delta.dx(), -delta.dy())); break; case Qt::TitleBarArea: - newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentDelta.dx(), parentDelta.dy()), - startGeometry.size()); + newGeometry = QRectF(windowData->startGeometry.topLeft() + + QPointF(parentDelta.dx(), parentDelta.dy()), + windowData->startGeometry.size()); break; case Qt::NoSection: break; } - if (grabbedSection != Qt::NoSection) { - _q_boundGeometryToSizeConstraints(startGeometry, &newGeometry, grabbedSection, + if (windowData->grabbedSection != Qt::NoSection) { + _q_boundGeometryToSizeConstraints(windowData->startGeometry, &newGeometry, + windowData->grabbedSection, q->effectiveSizeHint(Qt::MinimumSize), q->effectiveSizeHint(Qt::MaximumSize)); q->setGeometry(newGeometry); @@ -519,21 +515,25 @@ void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent if (!hasDecoration()) return; + ensureWindowData(); + if (q->rect().contains(event->pos())) { - if (buttonMouseOver || hoveredSubControl != QStyle::SC_None) + if (windowData->buttonMouseOver || windowData->hoveredSubControl != QStyle::SC_None) windowFrameHoverLeaveEvent(event); return; } - bool wasMouseOver = buttonMouseOver; - QRect oldButtonRect = buttonRect; - buttonRect = QRect(); - buttonMouseOver = false; + bool wasMouseOver = windowData->buttonMouseOver; + QRect oldButtonRect = windowData->buttonRect; + windowData->buttonRect = QRect(); + windowData->buttonMouseOver = false; QPointF pos = event->pos(); QStyleOptionTitleBar bar; // make sure that the coordinates (rect and pos) we send to the style are positive. - pos.rx() += leftWindowFrameMargin; - pos.ry() += topWindowFrameMargin; + if (windowFrameMargins) { + pos.rx() += windowFrameMargins[Left]; + pos.ry() += windowFrameMargins[Top]; + } initStyleOptionTitleBar(&bar); bar.rect = q->windowFrameRect().toRect(); bar.rect.moveTo(0,0); @@ -559,14 +559,17 @@ void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent cursorShape = Qt::SizeVerCursor; break; case Qt::TitleBarArea: - buttonRect = q->style()->subControlRect(QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarCloseButton, 0); + windowData->buttonRect = q->style()->subControlRect( + QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarCloseButton, 0); #ifdef Q_WS_MAC // On mac we should hover if we are in the 'area' of the buttons - buttonRect |= q->style()->subControlRect(QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMinButton, 0); - buttonRect |= q->style()->subControlRect(QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMaxButton, 0); + windowData->buttonRect |= q->style()->subControlRect( + QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMinButton, 0); + windowData->buttonRect |= q->style()->subControlRect( + QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMaxButton, 0); #endif - if (buttonRect.contains(pos.toPoint())) - buttonMouseOver = true; + if (windowData->buttonRect.contains(pos.toPoint())) + windowData->buttonMouseOver = true; event->ignore(); break; default: @@ -578,15 +581,15 @@ void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent q->setCursor(cursorShape); #endif // update buttons if we hover over them - hoveredSubControl = q->style()->hitTestComplexControl(QStyle::CC_TitleBar, &bar, pos.toPoint(), 0); - if (hoveredSubControl != QStyle::SC_TitleBarCloseButton) - hoveredSubControl = QStyle::SC_TitleBarLabel; + windowData->hoveredSubControl = q->style()->hitTestComplexControl(QStyle::CC_TitleBar, &bar, pos.toPoint(), 0); + if (windowData->hoveredSubControl != QStyle::SC_TitleBarCloseButton) + windowData->hoveredSubControl = QStyle::SC_TitleBarLabel; - if (buttonMouseOver != wasMouseOver) { + if (windowData->buttonMouseOver != wasMouseOver) { if (!oldButtonRect.isNull()) q->update(QRectF(oldButtonRect).translated(q->windowFrameRect().topLeft())); - if (!buttonRect.isNull()) - q->update(QRectF(buttonRect).translated(q->windowFrameRect().topLeft())); + if (!windowData->buttonRect.isNull()) + q->update(QRectF(windowData->buttonRect).translated(q->windowFrameRect().topLeft())); } } @@ -600,16 +603,19 @@ void QGraphicsWidgetPrivate::windowFrameHoverLeaveEvent(QGraphicsSceneHoverEvent q->unsetCursor(); #endif + ensureWindowData(); + bool needsUpdate = false; - if (hoveredSubControl == QStyle::SC_TitleBarCloseButton || buttonMouseOver) + if (windowData->hoveredSubControl == QStyle::SC_TitleBarCloseButton + || windowData->buttonMouseOver) needsUpdate = true; // update the hover state (of buttons etc...) - hoveredSubControl = QStyle::SC_None; - buttonMouseOver = false; - buttonRect = QRect(); + windowData->hoveredSubControl = QStyle::SC_None; + windowData->buttonMouseOver = false; + windowData->buttonRect = QRect(); if (needsUpdate) - q->update(buttonRect); + q->update(windowData->buttonRect); } } diff --git a/src/gui/graphicsview/qgraphicswidget_p.h b/src/gui/graphicsview/qgraphicswidget_p.h index 53eaa31..f4cdeca 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.h +++ b/src/gui/graphicsview/qgraphicswidget_p.h @@ -68,19 +68,12 @@ class QStyleOptionTitleBar; #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW -class Q_GUI_EXPORT QGraphicsWidgetPrivate : public QGraphicsItemPrivate +class QGraphicsWidgetPrivate : public QGraphicsItemPrivate { Q_DECLARE_PUBLIC(QGraphicsWidget) public: QGraphicsWidgetPrivate() - : leftMargin(0), - topMargin(0), - rightMargin(0), - bottomMargin(0), - leftLayoutItemMargin(0), - topLayoutItemMargin(0), - rightLayoutItemMargin(0), - bottomLayoutItemMargin(0), + : margins(0), layout(0), inheritedPaletteResolveMask(0), inheritedFontResolveMask(0), @@ -92,40 +85,23 @@ public: focusPrev(0), focusChild(0), windowFlags(0), - hoveredSubControl(QStyle::SC_None), - grabbedSection(Qt::NoSection), - buttonMouseOver(false), - buttonSunken(false), + windowData(0), setWindowFrameMargins(false), - leftWindowFrameMargin(0), - topWindowFrameMargin(0), - rightWindowFrameMargin(0), - bottomWindowFrameMargin(0) + windowFrameMargins(0) { } + virtual ~QGraphicsWidgetPrivate(); void init(QGraphicsItem *parentItem, Qt::WindowFlags wFlags); qreal titleBarHeight(const QStyleOptionTitleBar &options) const; // Margins - qreal leftMargin; - qreal topMargin; - qreal rightMargin; - qreal bottomMargin; - QRectF contentsRect; - - // Layout item margins - void getLayoutItemMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const; - void setLayoutItemMargins(qreal left, qreal top, qreal right, qreal bottom); - void setLayoutItemMargins(QStyle::SubElement element, const QStyleOption *opt = 0); + enum {Left, Top, Right, Bottom}; + mutable qreal *margins; + void ensureMargins() const; void fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *newScene = 0); void setLayout_helper(QGraphicsLayout *l); - qreal leftLayoutItemMargin; - qreal topLayoutItemMargin; - qreal rightLayoutItemMargin; - qreal bottomLayoutItemMargin; - // Layouts QGraphicsLayout *layout; void setLayoutDirection_helper(Qt::LayoutDirection direction); @@ -208,20 +184,26 @@ public: // Windows Qt::WindowFlags windowFlags; - QString windowTitle; - QStyle::SubControl hoveredSubControl; - Qt::WindowFrameSection grabbedSection; - uint buttonMouseOver : 1; - uint buttonSunken : 1; - QPointF mouseDelta; // to compensate for small error when interactively resizing - QRectF startGeometry; - QRect buttonRect; + struct WindowData { + QString windowTitle; + QStyle::SubControl hoveredSubControl; + Qt::WindowFrameSection grabbedSection; + uint buttonMouseOver : 1; + uint buttonSunken : 1; + QRectF startGeometry; + QRect buttonRect; + WindowData() + : hoveredSubControl(QStyle::SC_None) + , grabbedSection(Qt::NoSection) + , buttonMouseOver(false) + , buttonSunken(false) + {} + } *windowData; + void ensureWindowData(); bool setWindowFrameMargins; - qreal leftWindowFrameMargin; - qreal topWindowFrameMargin; - qreal rightWindowFrameMargin; - qreal bottomWindowFrameMargin; + mutable qreal *windowFrameMargins; + void ensureWindowFrameMargins() const; #ifndef QT_NO_ACTION QList<QAction *> actions; diff --git a/src/gui/graphicsview/qgridlayoutengine.cpp b/src/gui/graphicsview/qgridlayoutengine.cpp index dc5ca21..88712c2 100644 --- a/src/gui/graphicsview/qgridlayoutengine.cpp +++ b/src/gui/graphicsview/qgridlayoutengine.cpp @@ -275,7 +275,7 @@ void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSiz if (hasIgnoreFlag) { factors[i] = (stretch < 0) ? 1.0 : 0.0; } else { - factors[i] = (stretch < 0) ? sizes[i] : 0.0; + factors[i] = (stretch < 0) ? sizes[i] : 0.0; } } else if (stretch == sumStretches) { factors[i] = 1.0; @@ -615,7 +615,7 @@ QRectF QGridLayoutItem::geometryWithin(qreal x, qreal y, qreal width, qreal heig QSizeF size = effectiveMaxSize().boundedTo(QSizeF(cellWidth, cellHeight)); width = size.width(); height = size.height(); - + Qt::Alignment align = q_engine->effectiveAlignment(this); switch (align & Qt::AlignHorizontal_Mask) { case Qt::AlignHCenter: @@ -717,7 +717,7 @@ void QGridLayoutItem::dump(int indent) const void QGridLayoutRowInfo::insertOrRemoveRows(int row, int delta) { count += delta; - + insertOrRemoveItems(stretches, row, delta); insertOrRemoveItems(spacings, row, delta); insertOrRemoveItems(alignments, row, delta); @@ -1076,7 +1076,7 @@ QSizeF QGridLayoutEngine::sizeHint(const QLayoutStyleInfo &styleInfo, Qt::SizeHi break; } return QSizeF(); -} +} QSizePolicy::ControlTypes QGridLayoutEngine::controlTypes(LayoutSide side) const { @@ -1131,9 +1131,9 @@ void QGridLayoutEngine::dump(int indent) const QString message = QLatin1String("[ "); for (int column = 0; column < internalGridColumnCount(); ++column) { message += QString::number(q_items.indexOf(itemAt(row, column))).rightJustified(3); - message += QLatin1String(" "); + message += QLatin1Char(' '); } - message += QLatin1String("]"); + message += QLatin1Char(']'); qDebug("%*s %s", indent, "", qPrintable(message)); } @@ -1150,16 +1150,16 @@ void QGridLayoutEngine::dump(int indent) const q_rowData.dump(indent + 2); qDebug("%*s Geometries output", indent, ""); + QVector<qreal> *cellPos = &q_yy; for (int pass = 0; pass < 2; ++pass) { - QVector<qreal> &cellPos = q_yy; QString message; - for (i = 0; i < cellPos.count(); ++i) { + for (i = 0; i < cellPos->count(); ++i) { message += QLatin1String((message.isEmpty() ? "[" : ", ")); - message += QString::number(cellPos.at(i)); + message += QString::number(cellPos->at(i)); } - message += QLatin1String("]"); + message += QLatin1Char(']'); qDebug("%*s %s %s", indent, "", (pass == 0 ? "rows:" : "columns:"), qPrintable(message)); - cellPos = q_xx; + cellPos = &q_xx; } } #endif @@ -1538,5 +1538,5 @@ void QGridLayoutEngine::ensureGeometries(const QLayoutStyleInfo &styleInfo, } QT_END_NAMESPACE - + #endif //QT_NO_GRAPHICSVIEW diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 1aa6558..329fb01 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -19,6 +19,7 @@ win32:include(kernel/win.pri) embedded:include(embedded/embedded.pri) #modules +include(animation/animation.pri) include(kernel/kernel.pri) include(image/image.pri) include(painting/painting.pri) @@ -31,6 +32,7 @@ include(itemviews/itemviews.pri) include(inputmethod/inputmethod.pri) include(graphicsview/graphicsview.pri) include(util/util.pri) +include(statemachine/statemachine.pri) include(math3d/math3d.pri) embedded: QT += network diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index ca52974..bf348af 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -22,6 +22,7 @@ HEADERS += \ image/qpixmap.h \ image/qpixmap_raster_p.h \ image/qpixmapcache.h \ + image/qpixmapcache_p.h \ image/qpixmapdata_p.h \ image/qpixmapdatafactory_p.h \ image/qpixmapfilter_p.h diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 0514567..471062f 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -856,6 +856,9 @@ void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state) QImageWriter::supportedImageFormats() functions to retrieve a complete list of the supported file formats. + Note: When you add a non-empty filename to a QIcon, the icon becomes + non-null, even if the file doesn't exist or points to a corrupt file. + \sa addPixmap() */ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state) @@ -921,7 +924,7 @@ QList<QSize> QIcon::availableSizes(Mode mode, State state) const \relates QIcon \since 4.2 - Writes the given \a icon to the the given \a stream as a PNG + Writes the given \a icon to the given \a stream as a PNG image. If the icon contains more than one image, all images will be written to the stream. Note that writing the stream to a file will not produce a valid image file. diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 14e8b8f..c1c5631 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -4853,8 +4853,6 @@ bool QImage::operator==(const QImage & i) const return false; if (d->format != Format_RGB32) { - if (d->colortable != i.d->colortable) - return false; if (d->format >= Format_ARGB32) { // all bits defined const int n = d->width * d->depth / 8; if (n == d->bytes_per_line && n == i.d->bytes_per_line) { @@ -4867,11 +4865,13 @@ bool QImage::operator==(const QImage & i) const } } } else { - int w = width(); - int h = height(); + const int w = width(); + const int h = height(); + const QVector<QRgb> &colortable = d->colortable; + const QVector<QRgb> &icolortable = i.d->colortable; for (int y=0; y<h; ++y) { for (int x=0; x<w; ++x) { - if (pixelIndex(x, y) != i.pixelIndex(x, y)) + if (colortable[pixelIndex(x, y)] != icolortable[i.pixelIndex(x, y)]) return false; } } @@ -5000,7 +5000,7 @@ QPoint QImage::offset() const /*! \fn void QImage::setOffset(const QPoint& offset) - Sets the the number of pixels by which the image is intended to be + Sets the number of pixels by which the image is intended to be offset by when positioning relative to other images, to \a offset. \sa offset(), {QImage#Image Information}{Image Information} diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index 5de39d9..7f36be9 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -1337,6 +1337,7 @@ QByteArray QImageReader::imageFormat(QIODevice *device) \row \o TIFF \o Tagged Image File Format \row \o XBM \o X11 Bitmap \row \o XPM \o X11 Pixmap + \row \o SVG \o Scalable Vector Graphics \endtable Reading and writing SVG files is supported through Qt's diff --git a/src/gui/image/qnativeimage_p.h b/src/gui/image/qnativeimage_p.h index 860485a..6402af2 100644 --- a/src/gui/image/qnativeimage_p.h +++ b/src/gui/image/qnativeimage_p.h @@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE class QWidget; -class Q_GUI_EXPORT QNativeImage +class QNativeImage { public: QNativeImage(int width, int height, QImage::Format format, bool isTextBuffer = false, QWidget *widget = 0); diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 5568c0d..8ed9e93 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1282,7 +1282,7 @@ bool QPixmap::convertFromImage(const QImage &image, ColorMode mode) /*! \relates QPixmap - Writes the given \a pixmap to the the given \a stream as a PNG + Writes the given \a pixmap to the given \a stream as a PNG image. Note that writing the stream to a file will not produce a valid image file. @@ -2050,4 +2050,99 @@ QPixmapData* QPixmap::pixmapData() const return data; } +/*! + \enum QPixmap::HBitmapFormat + + \bold{Win32 only:} This enum defines how the conversion between \c + HBITMAP and QPixmap is performed. + + \warning This enum is only available on Windows. + + \value NoAlpha The alpha channel is ignored and always treated as + being set to fully opaque. This is preferred if the \c HBITMAP is + used with standard GDI calls, such as \c BitBlt(). + + \value PremultipliedAlpha The \c HBITMAP is treated as having an + alpha channel and premultiplied colors. This is preferred if the + \c HBITMAP is accessed through the \c AlphaBlend() GDI function. + + \value Alpha The \c HBITMAP is treated as having a plain alpha + channel. This is the preferred format if the \c HBITMAP is going + to be used as an application icon or systray icon. + + \sa fromWinHBITMAP(), toWinHBITMAP() +*/ + +/*! \fn HBITMAP QPixmap::toWinHBITMAP(HBitmapFormat format) const + \bold{Win32 only:} Creates a \c HBITMAP equivalent to the QPixmap, + based on the given \a format. Returns the \c HBITMAP handle. + + It is the caller's responsibility to free the \c HBITMAP data + after use. + + \warning This function is only available on Windows. + + \sa fromWinHBITMAP() +*/ + +/*! \fn QPixmap QPixmap::fromWinHBITMAP(HBITMAP bitmap, HBitmapFormat format) + \bold{Win32 only:} Returns a QPixmap that is equivalent to the + given \a bitmap. The conversion is based on the specified \a + format. + + \warning This function is only available on Windows. + + \sa toWinHBITMAP(), {QPixmap#Pixmap Conversion}{Pixmap Conversion} + +*/ + +/*! \fn const QX11Info &QPixmap::x11Info() const + \bold{X11 only:} Returns information about the configuration of + the X display used to display the widget. + + \warning This function is only available on X11. + + \sa {QPixmap#Pixmap Information}{Pixmap Information} +*/ + +/*! \fn Qt::HANDLE QPixmap::x11PictureHandle() const + \bold{X11 only:} Returns the X11 Picture handle of the pixmap for + XRender support. + + This function will return 0 if XRender support is not compiled + into Qt, if the XRender extension is not supported on the X11 + display, or if the handle could not be created. Use of this + function is not portable. + + \warning This function is only available on X11. + + \sa {QPixmap#Pixmap Information}{Pixmap Information} +*/ + +/*! \fn int QPixmap::x11SetDefaultScreen(int screen) + \internal +*/ + +/*! \fn void QPixmap::x11SetScreen(int screen) + \internal +*/ + +/*! \fn QRgb* QPixmap::clut() const + \internal +*/ + +/*! \fn int QPixmap::numCols() const + \internal +*/ + +/*! \fn const uchar* QPixmap::qwsBits() const + \internal + \since 4.1 +*/ + +/*! \fn int QPixmap::qwsBytesPerLine() const + \internal + \since 4.1 +*/ + QT_END_NAMESPACE diff --git a/src/gui/image/qpixmap_qws.cpp b/src/gui/image/qpixmap_qws.cpp index 6cc7981..7e383ab 100644 --- a/src/gui/image/qpixmap_qws.cpp +++ b/src/gui/image/qpixmap_qws.cpp @@ -109,9 +109,6 @@ QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h) return QPixmap::fromImage(img); } -/*! - \internal -*/ QRgb* QPixmap::clut() const { if (data->classId() == QPixmapData::RasterClass) { @@ -122,9 +119,6 @@ QRgb* QPixmap::clut() const return 0; } -/*! - \internal -*/ int QPixmap::numCols() const { if (data->classId() == QPixmapData::RasterClass) { @@ -135,10 +129,6 @@ int QPixmap::numCols() const return 0; } -/*! - \internal - \since 4.1 -*/ const uchar* QPixmap::qwsBits() const { if (data->classId() == QPixmapData::RasterClass) { @@ -149,10 +139,6 @@ const uchar* QPixmap::qwsBits() const return 0; } -/*! - \internal - \since 4.1 -*/ int QPixmap::qwsBytesPerLine() const { if (data->classId() == QPixmapData::RasterClass) { diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index b5556cd..29e4f3f 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -322,25 +322,36 @@ extern int qt_defaultDpiY(); int QRasterPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const { + QImageData *d = image.d; + if (!d) + return 0; + // override the image dpi with the screen dpi when rendering to a pixmap - const int dpmX = qRound(qt_defaultDpiX() * 100 / qreal(2.54)); - const int dpmY = qRound(qt_defaultDpiY() * 100 / qreal(2.54)); switch (metric) { + case QPaintDevice::PdmWidth: + return d->width; + case QPaintDevice::PdmHeight: + return d->height; case QPaintDevice::PdmWidthMM: - return qRound(image.width() * 1000 / dpmX); + return qRound(d->width * 25.4 / qt_defaultDpiX()); case QPaintDevice::PdmHeightMM: - return qRound(image.height() * 1000 / dpmY); - case QPaintDevice::PdmDpiX: - return qRound(dpmX * qreal(0.0254)); - case QPaintDevice::PdmDpiY: - return qRound(dpmY * qreal(0.0254)); + return qRound(d->width * 25.4 / qt_defaultDpiY()); + case QPaintDevice::PdmNumColors: + return d->colortable.size(); + case QPaintDevice::PdmDepth: + return d->depth; + case QPaintDevice::PdmDpiX: // fall-through case QPaintDevice::PdmPhysicalDpiX: - return qRound(dpmX * qreal(0.0254)); + return qt_defaultDpiX(); + case QPaintDevice::PdmDpiY: // fall-through case QPaintDevice::PdmPhysicalDpiY: - return qRound(dpmY * qreal(0.0254)); + return qt_defaultDpiY(); default: - return image.metric(metric); + qWarning("QRasterPixmapData::metric(): Unhandled metric type %d", metric); + break; } + + return 0; } QImage* QRasterPixmapData::buffer() diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp index 20bed02..ac02f97 100644 --- a/src/gui/image/qpixmap_win.cpp +++ b/src/gui/image/qpixmap_win.cpp @@ -119,42 +119,6 @@ QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h ) return pixmap; } - - -/*! - \enum QPixmap::HBitmapFormat - - This enum defines how the conversion between \c HBITMAP - and QPixmap is performed. - - \warning This enum is only available on Windows. - - \value NoAlpha The alpha channel is ignored and always treated as - being set to fully opaque. This is preferred if the \c HBITMAP is - used with standard GDI calls, such as \c BitBlt(). - - \value PremultipliedAlpha The \c HBITMAP is treated as having an - alpha channel and premultiplied colors. This is preferred if the - \c HBITMAP is accessed through the \c AlphaBlend() GDI function. - - \value Alpha The \c HBITMAP is treated as having a plain alpha - channel. This is the preferred format if the \c HBITMAP is going - to be used as an application icon or systray icon. - - \sa fromWinHBITMAP(), toWinHBITMAP() -*/ - -/*! - Creates a \c HBITMAP equivalent to the QPixmap, based on the given - \a format. Returns the \c HBITMAP handle. - - It is the caller's responsibility to free the \c HBITMAP data - after use. - - \warning This function is only available on Windows. - - \sa fromWinHBITMAP() -*/ HBITMAP QPixmap::toWinHBITMAP(HBitmapFormat format) const { HBITMAP bitmap = 0; @@ -209,15 +173,6 @@ HBITMAP QPixmap::toWinHBITMAP(HBitmapFormat format) const return bitmap; } -/*! - Returns a QPixmap that is equivalent to the given \a bitmap. The - conversion is based on the specified \a format. - - \warning This function is only available on Windows. - - \sa toWinHBITMAP(), {QPixmap#Pixmap Conversion}{Pixmap Conversion} - -*/ QPixmap QPixmap::fromWinHBITMAP(HBITMAP bitmap, HBitmapFormat format) { // Verify size @@ -319,6 +274,7 @@ static QImage qt_fromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h) } else { qWarning("qt_fromWinHBITMAP(), failed to get bitmap bits"); } + qFree(data); return image; } diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp index d9c10db..a0ae01f 100644 --- a/src/gui/image/qpixmap_x11.cpp +++ b/src/gui/image/qpixmap_x11.cpp @@ -1914,9 +1914,6 @@ QPixmap QX11PixmapData::transformed(const QTransform &transform, } } -/*! - \internal -*/ int QPixmap::x11SetDefaultScreen(int screen) { int old = defaultScreen; @@ -1924,9 +1921,6 @@ int QPixmap::x11SetDefaultScreen(int screen) return old; } -/*! - \internal -*/ void QPixmap::x11SetScreen(int screen) { if (paintingActive()) { @@ -2034,14 +2028,6 @@ bool QX11PixmapData::hasAlphaChannel() const return d == 32; } -/*! - Returns information about the configuration of the X display used to display - the widget. - - \warning This function is only available on X11. - - \sa {QPixmap#Pixmap Information}{Pixmap Information} -*/ const QX11Info &QPixmap::x11Info() const { if (data->classId() == QPixmapData::X11Class) @@ -2098,20 +2084,6 @@ QPaintEngine* QX11PixmapData::paintEngine() const return that->pengine; } -/*! - Returns the X11 Picture handle of the pixmap for XRender - support. - - This function will return 0 if XRender support is not compiled - into Qt, if the XRender extension is not supported on the X11 - display, or if the handle could not be created. Use of this - function is not portable. - - \warning This function is only available on X11. - - \sa {QPixmap#Pixmap Information}{Pixmap Information} -*/ - Qt::HANDLE QPixmap::x11PictureHandle() const { #ifndef QT_NO_XRENDER diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index 4916489..82b42b4 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -40,13 +40,9 @@ ****************************************************************************/ #include "qpixmapcache.h" -#include "qcache.h" #include "qobject.h" #include "qdebug.h" - -#include "qpaintengine.h" -#include <private/qimage_p.h> -#include <private/qpixmap_raster_p.h> +#include "qpixmapcache_p.h" QT_BEGIN_NAMESPACE @@ -68,15 +64,17 @@ QT_BEGIN_NAMESPACE access the global pixmap cache. It creates an internal QCache object for caching the pixmaps. - The cache associates a pixmap with a string (key). If two pixmaps - are inserted into the cache using equal keys, then the last pixmap - will hide the first pixmap. The QHash and QCache classes do + The cache associates a pixmap with a string as a key or with a QPixmapCache::Key. + The QPixmapCache::Key is faster than using strings as key. + If two pixmaps are inserted into the cache using equal keys, then the + last pixmap will hide the first pixmap. The QHash and QCache classes do exactly the same. The cache becomes full when the total size of all pixmaps in the - cache exceeds cacheLimit(). The initial cache limit is 1024 KB (1 - MB); it is changed with setCacheLimit(). A pixmap takes roughly - (\e{width} * \e{height} * \e{depth})/8 bytes of memory. + cache exceeds cacheLimit(). The initial cache limit is + 2048 KB(2 MB) for Embedded, 10240 KB (10 + MB) for Desktops; it is changed with setCacheLimit(). + A pixmap takes roughly (\e{width} * \e{height} * \e{depth})/8 bytes of memory. The \e{Qt Quarterly} article \l{http://doc.trolltech.com/qq/qq12-qpixmapcache.html}{Optimizing @@ -92,52 +90,122 @@ static int cache_limit = 2048; // 2048 KB cache limit for embedded static int cache_limit = 10240; // 10 MB cache limit for desktop #endif -// XXX: hw: is this a general concept we need to abstract? -class QDetachedPixmap : public QPixmap +/*! + Constructs an empty Key object. +*/ +QPixmapCache::Key::Key() : d(0) { -public: - QDetachedPixmap(const QPixmap &pix) : QPixmap(pix) - { - if (data && data->classId() == QPixmapData::RasterClass) { - QRasterPixmapData *d = static_cast<QRasterPixmapData*>(data); - if (!d->image.isNull() && d->image.d->paintEngine - && !d->image.d->paintEngine->isActive()) - { - delete d->image.d->paintEngine; - d->image.d->paintEngine = 0; - } - } +} + +/*! + \internal + Constructs a copy of \a other. +*/ +QPixmapCache::Key::Key(const Key &other) +{ + if (other.d) + ++(other.d->ref); + d = other.d; +} + +/*! + Destructor; called immediately before the object is deleted. +*/ +QPixmapCache::Key::~Key() +{ + if (d && --(d->ref) == 0) + delete d; +} + +/*! + \internal + + Returns true if this key is the same as the given \a key. +*/ +bool QPixmapCache::Key::operator ==(const Key &key) const +{ + return (d == key.d); +} + +/*! + \fn bool QPixmapCache::Key::operator !=(const Key &key) const + \internal +*/ + +/*! + \internal +*/ +QPixmapCache::Key &QPixmapCache::Key::operator =(const Key &other) +{ + if (d != other.d) { + if (other.d) + ++(other.d->ref); + if (d && --(d->ref) == 0) + delete d; + d = other.d; } -}; + return *this; +} -class QPMCache : public QObject, public QCache<qint64, QDetachedPixmap> +class QPMCache : public QObject, public QCache<QPixmapCache::Key, QDetachedPixmap> { Q_OBJECT public: - QPMCache() - : QObject(0), - QCache<qint64, QDetachedPixmap>(cache_limit * 1024), - theid(0), ps(0), t(false) { } - ~QPMCache() { } + QPMCache(); + ~QPMCache(); void timerEvent(QTimerEvent *); bool insert(const QString& key, const QPixmap &pixmap, int cost); + QPixmapCache::Key insert(const QPixmap &pixmap, int cost); + bool replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost); bool remove(const QString &key); + bool remove(const QPixmapCache::Key &key); + + void resizeKeyArray(int size); + QPixmapCache::Key createKey(); + void releaseKey(const QPixmapCache::Key &key); + void clear(); QPixmap *object(const QString &key) const; + QPixmap *object(const QPixmapCache::Key &key) const; + + static inline QPixmapCache::KeyData *get(const QPixmapCache::Key &key) + {return key.d;} + + static QPixmapCache::KeyData* getKeyData(QPixmapCache::Key *key); private: - QHash<QString, qint64> cacheKeys; + int *keyArray; int theid; int ps; + int keyArraySize; + int freeKey; + QHash<QString, QPixmapCache::Key> cacheKeys; bool t; }; + QT_BEGIN_INCLUDE_NAMESPACE #include "qpixmapcache.moc" QT_END_INCLUDE_NAMESPACE +uint qHash(const QPixmapCache::Key &k) +{ + return qHash(QPMCache::get(k)->key); +} + +QPMCache::QPMCache() + : QObject(0), + QCache<QPixmapCache::Key, QDetachedPixmap>(cache_limit * 1024), + keyArray(0), theid(0), ps(0), keyArraySize(0), freeKey(0), t(false) +{ +} +QPMCache::~QPMCache() +{ + free(keyArray); +} + /* - This is supposed to cut the cache size down by about 80-90% in a + This is supposed to cut the cache size down by about 25% in a minute once the application becomes idle, to let any inserted pixmap remain in the cache for some time before it becomes a candidate for cleaning-up, and to not cut down the size of the cache while the @@ -146,23 +214,28 @@ QT_END_INCLUDE_NAMESPACE When the last pixmap has been deleted from the cache, kill the timer so Qt won't keep the CPU from going into sleep mode. */ - void QPMCache::timerEvent(QTimerEvent *) { int mc = maxCost(); bool nt = totalCost() == ps; + QList<QPixmapCache::Key> keys = QCache<QPixmapCache::Key, QDetachedPixmap>::keys(); setMaxCost(nt ? totalCost() * 3 / 4 : totalCost() -1); setMaxCost(mc); ps = totalCost(); - QHash<QString, qint64>::iterator it = cacheKeys.begin(); + QHash<QString, QPixmapCache::Key>::iterator it = cacheKeys.begin(); while (it != cacheKeys.end()) { if (!contains(it.value())) { + releaseKey(it.value()); it = cacheKeys.erase(it); } else { ++it; } } + for (int i = 0; i < keys.size(); ++i) { + if (!contains(keys.at(i))) + releaseKey(keys.at(i)); + } if (!size()) { killTimer(theid); @@ -176,38 +249,156 @@ void QPMCache::timerEvent(QTimerEvent *) QPixmap *QPMCache::object(const QString &key) const { - return QCache<qint64, QDetachedPixmap>::object(cacheKeys.value(key, -1)); + QPixmapCache::Key cacheKey = cacheKeys.value(key); + if (!cacheKey.d || !cacheKey.d->isValid) { + const_cast<QPMCache *>(this)->cacheKeys.remove(key); + return 0; + } + QPixmap *ptr = QCache<QPixmapCache::Key, QDetachedPixmap>::object(cacheKey); + //We didn't find the pixmap in the cache, the key is not valid anymore + if (!ptr) { + const_cast<QPMCache *>(this)->cacheKeys.remove(key); + const_cast<QPMCache *>(this)->releaseKey(cacheKey); + } + return ptr; } +QPixmap *QPMCache::object(const QPixmapCache::Key &key) const +{ + Q_ASSERT(key.d->isValid); + QPixmap *ptr = QCache<QPixmapCache::Key, QDetachedPixmap>::object(key); + //We didn't find the pixmap in the cache, the key is not valid anymore + if (!ptr) + const_cast<QPMCache *>(this)->releaseKey(key); + return ptr; +} bool QPMCache::insert(const QString& key, const QPixmap &pixmap, int cost) { - qint64 cacheKey = pixmap.cacheKey(); - if (QCache<qint64, QDetachedPixmap>::object(cacheKey)) { + QPixmapCache::Key cacheKey; + QPixmapCache::Key oldCacheKey = cacheKeys.value(key); + //If for the same key we add already a pixmap we should delete it + if (oldCacheKey.d) { + QCache<QPixmapCache::Key, QDetachedPixmap>::remove(oldCacheKey); + cacheKey = oldCacheKey; + } else { + cacheKey = createKey(); + } + + bool success = QCache<QPixmapCache::Key, QDetachedPixmap>::insert(cacheKey, new QDetachedPixmap(pixmap), cost); + if (success) { cacheKeys.insert(key, cacheKey); - return true; + if (!theid) { + theid = startTimer(30000); + t = false; + } + } else { + //Insertion failed we released the new allocated key + releaseKey(cacheKey); } - qint64 oldCacheKey = cacheKeys.value(key, -1); - //If for the same key we add already a pixmap we should delete it - if (oldCacheKey != -1) - QCache<qint64, QDetachedPixmap>::remove(oldCacheKey); + return success; +} - bool success = QCache<qint64, QDetachedPixmap>::insert(cacheKey, new QDetachedPixmap(pixmap), cost); +QPixmapCache::Key QPMCache::insert(const QPixmap &pixmap, int cost) +{ + QPixmapCache::Key cacheKey = createKey(); + bool success = QCache<QPixmapCache::Key, QDetachedPixmap>::insert(cacheKey, new QDetachedPixmap(pixmap), cost); if (success) { - cacheKeys.insert(key, cacheKey); if (!theid) { theid = startTimer(30000); t = false; } + } else { + //Insertion failed we released the key and return an invalid one + releaseKey(cacheKey); + } + return cacheKey; +} + +bool QPMCache::replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost) +{ + Q_ASSERT(key.d->isValid); + //If for the same key we add already a pixmap we should delete it + QCache<QPixmapCache::Key, QDetachedPixmap>::remove(key); + + bool success = QCache<QPixmapCache::Key, QDetachedPixmap>::insert(key, new QDetachedPixmap(pixmap), cost); + if (success && !theid) { + theid = startTimer(30000); + t = false; } return success; } bool QPMCache::remove(const QString &key) { - qint64 cacheKey = cacheKeys.value(key, -1); + QPixmapCache::Key cacheKey = cacheKeys.value(key); + //The key was not in the cache + if (!cacheKey.d) + return false; cacheKeys.remove(key); - return QCache<qint64, QDetachedPixmap>::remove(cacheKey); + releaseKey(cacheKey); + return QCache<QPixmapCache::Key, QDetachedPixmap>::remove(cacheKey); +} + +bool QPMCache::remove(const QPixmapCache::Key &key) +{ + bool result = QCache<QPixmapCache::Key, QDetachedPixmap>::remove(key); + //We release the key after we removed it from the cache + releaseKey(key); + return result; +} + +void QPMCache::resizeKeyArray(int size) +{ + if (size <= keyArraySize || size == 0) + return; + keyArray = reinterpret_cast<int *>(realloc(keyArray, size * sizeof(int))); + for (int i = keyArraySize; i != size; ++i) + keyArray[i] = i + 1; + keyArraySize = size; +} + +QPixmapCache::Key QPMCache::createKey() +{ + if (freeKey == keyArraySize) + resizeKeyArray(keyArraySize ? keyArraySize << 1 : 2); + int id = freeKey; + freeKey = keyArray[id]; + QPixmapCache::Key key; + QPixmapCache::KeyData *d = QPMCache::getKeyData(&key); + d->key = ++id; + return key; +} + +void QPMCache::releaseKey(const QPixmapCache::Key &key) +{ + if (key.d->key > keyArraySize || key.d->key <= 0) + return; + key.d->key--; + keyArray[key.d->key] = freeKey; + freeKey = key.d->key; + key.d->isValid = false; + key.d->key = 0; +} + +void QPMCache::clear() +{ + free(keyArray); + keyArray = 0; + freeKey = 0; + keyArraySize = 0; + //Mark all keys as invalid + QList<QPixmapCache::Key> keys = QCache<QPixmapCache::Key, QDetachedPixmap>::keys(); + for (int i = 0; i < keys.size(); ++i) + keys.at(i).d->isValid = false; + QCache<QPixmapCache::Key, QDetachedPixmap>::clear(); +} + +QPixmapCache::KeyData* QPMCache::getKeyData(QPixmapCache::Key *key) +{ + if (!key->d) + key->d = new QPixmapCache::KeyData; + return key->d; } Q_GLOBAL_STATIC(QPMCache, pm_cache) @@ -222,7 +413,7 @@ Q_GLOBAL_STATIC(QPMCache, pm_cache) \warning If valid, you should copy the pixmap immediately (this is fast). Subsequent insertions into the cache could cause the pointer to become invalid. For this reason, we recommend you use - find(const QString&, QPixmap&) instead. + bool find(const QString&, QPixmap*) instead. Example: \snippet doc/src/snippets/code/src_gui_image_qpixmapcache.cpp 0 @@ -235,25 +426,57 @@ QPixmap *QPixmapCache::find(const QString &key) /*! + \obsolete + + Use bool find(const QString&, QPixmap*) instead. +*/ + +bool QPixmapCache::find(const QString &key, QPixmap& pixmap) +{ + return find(key, &pixmap); +} + +/*! Looks for a cached pixmap associated with the \a key in the cache. - If the pixmap is found, the function sets \a pm to that pixmap and - returns true; otherwise it leaves \a pm alone and returns false. + If the pixmap is found, the function sets \a pixmap to that pixmap and + returns true; otherwise it leaves \a pixmap alone and returns false. + + \since 4.6 Example: \snippet doc/src/snippets/code/src_gui_image_qpixmapcache.cpp 1 */ -bool QPixmapCache::find(const QString &key, QPixmap& pm) +bool QPixmapCache::find(const QString &key, QPixmap* pixmap) { QPixmap *ptr = pm_cache()->object(key); - if (ptr) - pm = *ptr; + if (ptr && pixmap) + *pixmap = *ptr; return ptr != 0; } +/*! + Looks for a cached pixmap associated with the \a key in the cache. + If the pixmap is found, the function sets \a pixmap to that pixmap and + returns true; otherwise it leaves \a pixmap alone and returns false. If + the pixmap is not found, it means that the \a key is not valid anymore, + so it will be released for the next insertion. + + \since 4.6 +*/ +bool QPixmapCache::find(const Key &key, QPixmap* pixmap) +{ + //The key is not valid anymore, a flush happened before probably + if (!key.d || !key.d->isValid) + return false; + QPixmap *ptr = pm_cache()->object(key); + if (ptr && pixmap) + *pixmap = *ptr; + return ptr != 0; +} /*! - Inserts a copy of the pixmap \a pm associated with the \a key into + Inserts a copy of the pixmap \a pixmap associated with the \a key into the cache. All pixmaps inserted by the Qt library have a key starting with @@ -272,9 +495,46 @@ bool QPixmapCache::find(const QString &key, QPixmap& pm) \sa setCacheLimit() */ -bool QPixmapCache::insert(const QString &key, const QPixmap &pm) +bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap) { - return pm_cache()->insert(key, pm, pm.width() * pm.height() * pm.depth() / 8); + return pm_cache()->insert(key, pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8); +} + +/*! + Inserts a copy of the pixmap \a pixmap into + the cache and return you the key. + + When a pixmap is inserted and the cache is about to exceed its + limit, it removes pixmaps until there is enough room for the + pixmap to be inserted. + + The oldest pixmaps (least recently accessed in the cache) are + deleted when more space is needed. + + \sa setCacheLimit(), replace() + + \since 4.6 +*/ +QPixmapCache::Key QPixmapCache::insert(const QPixmap &pixmap) +{ + return pm_cache()->insert(pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8); +} + +/*! + Replace the pixmap associated to the \a key into + the cache. It return true if the pixmap \a pixmap has been correctly + inserted into the cache false otherwise. + + \sa setCacheLimit(), insert() + + \since 4.6 +*/ +bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap) +{ + //The key is not valid anymore, a flush happened before probably + if (!key.d || !key.d->isValid) + return false; + return pm_cache()->replace(key, pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8); } /*! @@ -314,6 +574,19 @@ void QPixmapCache::remove(const QString &key) pm_cache()->remove(key); } +/*! + Removes the pixmap associated with \a key from the cache and release + the key for a future insertion. + + \since 4.6 +*/ +void QPixmapCache::remove(const Key &key) +{ + //The key is not valid anymore, a flush happened before probably + if (!key.d || !key.d->isValid) + return; + pm_cache()->remove(key); +} /*! Removes all pixmaps from the cache. diff --git a/src/gui/image/qpixmapcache.h b/src/gui/image/qpixmapcache.h index 2750a88..ae64310 100644 --- a/src/gui/image/qpixmapcache.h +++ b/src/gui/image/qpixmapcache.h @@ -53,12 +53,35 @@ QT_MODULE(Gui) class Q_GUI_EXPORT QPixmapCache { public: + class KeyData; + class Key + { + public: + Key(); + Key(const Key &other); + ~Key(); + bool operator ==(const Key &key) const; + inline bool operator !=(const Key &key) const + { return !operator==(key); } + Key &operator =(const Key &other); + + private: + KeyData *d; + friend class QPMCache; + friend class QPixmapCache; + }; + static int cacheLimit(); static void setCacheLimit(int); static QPixmap *find(const QString &key); - static bool find(const QString &key, QPixmap&); - static bool insert(const QString &key, const QPixmap&); + static bool find(const QString &key, QPixmap &pixmap); + static bool find(const QString &key, QPixmap *pixmap); + static bool find(const Key &key, QPixmap *pixmap); + static bool insert(const QString &key, const QPixmap &pixmap); + static Key insert(const QPixmap &pixmap); + static bool replace(const Key &key, const QPixmap &pixmap); static void remove(const QString &key); + static void remove(const Key &key); static void clear(); }; diff --git a/src/gui/image/qpixmapcache_p.h b/src/gui/image/qpixmapcache_p.h new file mode 100644 index 0000000..a35e0d2 --- /dev/null +++ b/src/gui/image/qpixmapcache_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPIXMAPCACHE_P_H +#define QPIXMAPCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qpixmapcache.h" +#include "qpaintengine.h" +#include <private/qimage_p.h> +#include <private/qpixmap_raster_p.h> +#include "qcache.h" + +QT_BEGIN_NAMESPACE + +uint qHash(const QPixmapCache::Key &k); + +class QPixmapCache::KeyData +{ +public: + KeyData() : isValid(true), key(0), ref(1) {} + KeyData(const KeyData &other) + : isValid(other.isValid), key(other.key), ref(1) {} + ~KeyData() {} + + bool isValid; + int key; + int ref; +}; + +// XXX: hw: is this a general concept we need to abstract? +class QDetachedPixmap : public QPixmap +{ +public: + QDetachedPixmap(const QPixmap &pix) : QPixmap(pix) + { + if (data && data->classId() == QPixmapData::RasterClass) { + QRasterPixmapData *d = static_cast<QRasterPixmapData*>(data); + if (!d->image.isNull() && d->image.d->paintEngine + && !d->image.d->paintEngine->isActive()) + { + delete d->image.d->paintEngine; + d->image.d->paintEngine = 0; + } + } + } +}; + +QT_END_NAMESPACE + +#endif // QPIXMAPCACHE_P_H diff --git a/src/gui/image/qpixmapdatafactory_p.h b/src/gui/image/qpixmapdatafactory_p.h index 65e3f11..9604346 100644 --- a/src/gui/image/qpixmapdatafactory_p.h +++ b/src/gui/image/qpixmapdatafactory_p.h @@ -65,7 +65,7 @@ QT_MODULE(Gui) class QPixmapData; -class Q_GUI_EXPORT QPixmapDataFactory +class QPixmapDataFactory { public: static QPixmapDataFactory* instance(int screen = 0); diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp index 8631c8c..4e6adc0 100644 --- a/src/gui/image/qpixmapfilter.cpp +++ b/src/gui/image/qpixmapfilter.cpp @@ -401,6 +401,7 @@ static void convolute( } yk++; } + delete[] fixedKernel; } /*! diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp index 90bd2ab..f4062ad 100644 --- a/src/gui/image/qxpmhandler.cpp +++ b/src/gui/image/qxpmhandler.cpp @@ -1146,7 +1146,7 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const QTextStream s(device); s << "/* XPM */" << endl << "static char *" << fbname(fileName) << "[]={" << endl - << "\"" << w << " " << h << " " << ncolors << " " << cpp << "\""; + << '\"' << w << ' ' << h << ' ' << ncolors << ' ' << cpp << '\"'; // write palette QMap<QRgb, int>::Iterator c = colorMap.begin(); @@ -1162,7 +1162,7 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const qGreen(color), qBlue(color)); ++c; - s << "," << endl << line; + s << ',' << endl << line; } // write pixels, limit to 4 characters per pixel @@ -1184,7 +1184,7 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const } } } - s << "," << endl << "\"" << line << "\""; + s << ',' << endl << '\"' << line << '\"'; } s << "};" << endl; return (s.status() == QTextStream::Ok); diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 4e4392f..c90216b 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -1338,7 +1338,7 @@ QSize QAbstractItemView::iconSize() const /*! \property QAbstractItemView::textElideMode - \brief the the position of the "..." in elided text. + \brief the position of the "..." in elided text. The default value for all item views is Qt::ElideRight. */ @@ -2165,11 +2165,12 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) } #endif bool modified = (event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)); - if (!event->text().isEmpty() && !modified) { - if (!edit(currentIndex(), AnyKeyPressed, event)) - keyboardSearch(event->text()); + if (!event->text().isEmpty() && !modified && !edit(currentIndex(), AnyKeyPressed, event)) { + keyboardSearch(event->text()); + event->accept(); + } else { + event->ignore(); } - event->ignore(); break; } } } @@ -2844,9 +2845,9 @@ void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget d->persistent.insert(widget); d->addEditor(index, widget, true); widget->show(); + dataChanged(index, index); // update the geometry if (!d->delayedPendingLayout) widget->setGeometry(visualRect(index)); - dataChanged(index, index); // update the geometry } } @@ -3217,9 +3218,9 @@ QStyleOptionViewItem QAbstractItemView::viewOptions() const option.state &= ~QStyle::State_MouseOver; option.font = font(); -#ifdef Q_WS_WIN - // Note this is currently required on Windows - // do give non-focused item views inactive appearance +#ifndef Q_WS_MAC + // On mac the focus appearance follows window activation + // not widget activation if (!hasFocus()) option.state &= ~QStyle::State_Active; #endif diff --git a/src/gui/itemviews/qabstractitemview_p.h b/src/gui/itemviews/qabstractitemview_p.h index 16bd1ab..139d0b7 100644 --- a/src/gui/itemviews/qabstractitemview_p.h +++ b/src/gui/itemviews/qabstractitemview_p.h @@ -99,7 +99,7 @@ public: QVariant data(const QModelIndex &, int) const { return QVariant(); } }; -class Q_GUI_EXPORT QAbstractItemViewPrivate : public QAbstractScrollAreaPrivate +class QAbstractItemViewPrivate : public QAbstractScrollAreaPrivate { Q_DECLARE_PUBLIC(QAbstractItemView) diff --git a/src/gui/itemviews/qfileiconprovider.cpp b/src/gui/itemviews/qfileiconprovider.cpp index 9f33af3..434bcde 100644 --- a/src/gui/itemviews/qfileiconprovider.cpp +++ b/src/gui/itemviews/qfileiconprovider.cpp @@ -215,8 +215,7 @@ QIcon QFileIconProvider::icon(IconType type) const QIcon QFileIconProviderPrivate::getWinIcon(const QFileInfo &fileInfo) const { QIcon retIcon; - QString fileExtension = fileInfo.suffix().toUpper(); - fileExtension.prepend( QLatin1String(".") ); + const QString fileExtension = QLatin1Char('.') + fileInfo.suffix().toUpper(); QString key; if (fileInfo.isFile() && !fileInfo.isExecutable() && !fileInfo.isSymLink()) @@ -416,26 +415,22 @@ QString QFileIconProvider::type(const QFileInfo &info) const } if (info.isDir()) - return QApplication::translate("QFileDialog", #ifdef Q_WS_WIN - "File Folder", "Match Windows Explorer" + return QApplication::translate("QFileDialog", "File Folder", "Match Windows Explorer"); #else - "Folder", "All other platforms" + return QApplication::translate("QFileDialog", "Folder", "All other platforms"); #endif - ); // Windows - "File Folder" // OS X - "Folder" // Konqueror - "Folder" // Nautilus - "folder" if (info.isSymLink()) - return QApplication::translate("QFileDialog", #ifdef Q_OS_MAC - "Alias", "Mac OS X Finder" + return QApplication::translate("QFileDialog", "Alias", "Mac OS X Finder"); #else - "Shortcut", "All other platforms" + return QApplication::translate("QFileDialog", "Shortcut", "All other platforms"); #endif - ); // OS X - "Alias" // Windows - "Shortcut" // Konqueror - "Folder" or "TXT File" i.e. what it is pointing to diff --git a/src/gui/itemviews/qheaderview.cpp b/src/gui/itemviews/qheaderview.cpp index 6238df5..ad93922 100644 --- a/src/gui/itemviews/qheaderview.cpp +++ b/src/gui/itemviews/qheaderview.cpp @@ -1267,8 +1267,10 @@ void QHeaderView::setSortIndicator(int logicalIndex, Qt::SortOrder order) d->sortIndicatorSection = logicalIndex; d->sortIndicatorOrder = order; - if (logicalIndex >= d->sectionCount) + if (logicalIndex >= d->sectionCount) { + emit sortIndicatorChanged(logicalIndex, order); return; // nothing to do + } if (old != logicalIndex && ((logicalIndex >= 0 && resizeMode(logicalIndex) == ResizeToContents) diff --git a/src/gui/itemviews/qitemdelegate.cpp b/src/gui/itemviews/qitemdelegate.cpp index bf9b5c5..a748199 100644 --- a/src/gui/itemviews/qitemdelegate.cpp +++ b/src/gui/itemviews/qitemdelegate.cpp @@ -47,6 +47,7 @@ #include <qbrush.h> #include <qlineedit.h> #include <qtextedit.h> +#include <qplaintextedit.h> #include <qpainter.h> #include <qpalette.h> #include <qpoint.h> @@ -218,7 +219,7 @@ QSizeF QItemDelegatePrivate::doTextLayout(int lineWidth) const editor widget, which is a widget that is placed on top of the view while editing takes place. Editors are created with a QItemEditorFactory; a default static instance provided by - QItemEditorFactory is installed on all item delagates. You can set + QItemEditorFactory is installed on all item delegates. You can set a custom factory using setItemEditorFactory() or set a new default factory with QItemEditorFactory::setDefaultFactory(). It is the data stored in the item model with the Qt::EditRole that is edited. @@ -1194,7 +1195,7 @@ bool QItemDelegate::eventFilter(QObject *object, QEvent *event) case Qt::Key_Enter: case Qt::Key_Return: #ifndef QT_NO_TEXTEDIT - if (qobject_cast<QTextEdit*>(editor)) + if (qobject_cast<QTextEdit *>(editor) || qobject_cast<QPlainTextEdit *>(editor)) return false; // don't filter enter key events for QTextEdit // We want the editor to be able to process the key press // before committing the data (e.g. so it can do diff --git a/src/gui/itemviews/qitemselectionmodel.cpp b/src/gui/itemviews/qitemselectionmodel.cpp index 8baefdf..696b8fa 100644 --- a/src/gui/itemviews/qitemselectionmodel.cpp +++ b/src/gui/itemviews/qitemselectionmodel.cpp @@ -1553,7 +1553,7 @@ QDebug operator<<(QDebug dbg, const QItemSelectionRange &range) { #ifndef Q_BROKEN_DEBUG_STREAM dbg.nospace() << "QItemSelectionRange(" << range.topLeft() - << "," << range.bottomRight() << ")"; + << ',' << range.bottomRight() << ')'; return dbg.space(); #else qWarning("This compiler doesn't support streaming QItemSelectionRange to QDebug"); diff --git a/src/gui/itemviews/qlistview.cpp b/src/gui/itemviews/qlistview.cpp index a5a194f..8b50d0e 100644 --- a/src/gui/itemviews/qlistview.cpp +++ b/src/gui/itemviews/qlistview.cpp @@ -1608,6 +1608,10 @@ QRegion QListView::visualRegionForSelection(const QItemSelection &selection) con if (!selection.at(i).isValid()) continue; QModelIndex parent = selection.at(i).topLeft().parent(); + //we only display the children of the root in a listview + //we're not interested in the other model indexes + if (parent != d->root) + continue; int t = selection.at(i).topLeft().row(); int b = selection.at(i).bottomRight().row(); if (d->viewMode == IconMode || d->isWrapping()) { // in non-static mode, we have to go through all selected items @@ -1616,8 +1620,8 @@ QRegion QListView::visualRegionForSelection(const QItemSelection &selection) con } else { // in static mode, we can optimize a bit while (t <= b && d->isHidden(t)) ++t; while (b >= t && d->isHidden(b)) --b; - const QModelIndex top = d->model->index(t, c, d->root); - const QModelIndex bottom = d->model->index(b, c, d->root); + const QModelIndex top = d->model->index(t, c, parent); + const QModelIndex bottom = d->model->index(b, c, parent); QRect rect(visualRect(top).topLeft(), visualRect(bottom).bottomRight()); selectionRegion += QRegion(rect); @@ -1969,10 +1973,16 @@ void QListViewPrivate::prepareItemsLayout() int frameAroundContents = 0; if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2; - int verticalMargin = vbarpolicy==Qt::ScrollBarAlwaysOff ? 0 : - q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, q->verticalScrollBar()) + frameAroundContents; - int horizontalMargin = hbarpolicy==Qt::ScrollBarAlwaysOff ? 0 : - q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, q->horizontalScrollBar()) + frameAroundContents; + + // maximumViewportSize() already takes scrollbar into account if policy is + // Qt::ScrollBarAlwaysOn but scrollbar extent must be deduced if policy + // is Qt::ScrollBarAsNeeded + int verticalMargin = vbarpolicy==Qt::ScrollBarAsNeeded + ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, q->verticalScrollBar()) + frameAroundContents + : 0; + int horizontalMargin = hbarpolicy==Qt::ScrollBarAsNeeded + ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, q->horizontalScrollBar()) + frameAroundContents + : 0; layoutBounds.adjust(0, 0, -verticalMargin, -horizontalMargin); @@ -1997,14 +2007,15 @@ bool QListViewPrivate::doItemsLayout(int delta) int first = batchStartRow(); int last = qMin(first + delta - 1, max); - if (max < 0 || last < first) - return true; // nothing to do - if (first == 0) { layoutChildren(); // make sure the viewport has the right size prepareItemsLayout(); } + if (max < 0 || last < first) { + return true; // nothing to do + } + QListViewLayoutInfo info; info.bounds = layoutBounds; info.grid = gridSize(); diff --git a/src/gui/itemviews/qlistwidget.cpp b/src/gui/itemviews/qlistwidget.cpp index 7a366d1..bf3b43c 100644 --- a/src/gui/itemviews/qlistwidget.cpp +++ b/src/gui/itemviews/qlistwidget.cpp @@ -1158,7 +1158,7 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::addItem(QListWidgetItem *item) - Inserts the \a item at the the end of the list widget. + Inserts the \a item at the end of the list widget. \warning A QListWidgetItem can only be added to a QListWidget once. Adding the same QListWidgetItem multiple diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index 56925b8..96eb6f0 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -1539,7 +1539,8 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) d->clear_mapping(); reset(); - d->update_source_sort_column(); + if (d->update_source_sort_column() && d->dynamic_sortfilter) + d->sort(); } /*! diff --git a/src/gui/itemviews/qstyleditemdelegate.cpp b/src/gui/itemviews/qstyleditemdelegate.cpp index be0971b..7f2c8ed 100644 --- a/src/gui/itemviews/qstyleditemdelegate.cpp +++ b/src/gui/itemviews/qstyleditemdelegate.cpp @@ -47,6 +47,7 @@ #include <qbrush.h> #include <qlineedit.h> #include <qtextedit.h> +#include <qplaintextedit.h> #include <qpainter.h> #include <qpalette.h> #include <qpoint.h> @@ -646,7 +647,7 @@ bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event) case Qt::Key_Enter: case Qt::Key_Return: #ifndef QT_NO_TEXTEDIT - if (qobject_cast<QTextEdit*>(editor)) + if (qobject_cast<QTextEdit *>(editor) || qobject_cast<QPlainTextEdit *>(editor)) return false; // don't filter enter key events for QTextEdit // We want the editor to be able to process the key press // before committing the data (e.g. so it can do diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index 757ecf2..0bded54 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -282,7 +282,7 @@ void QTableViewPrivate::trimHiddenSelections(QItemSelectionRange *range) const void QTableViewPrivate::setSpan(int row, int column, int rowSpan, int columnSpan) { if (row < 0 || column < 0 || rowSpan <= 0 || columnSpan <= 0) { - qWarning() << "QTableView::setSpan: invalid span given: (" << row << "," << column << "," << rowSpan << "," << columnSpan << ")"; + qWarning() << "QTableView::setSpan: invalid span given: (" << row << ',' << column << ',' << rowSpan << ',' << columnSpan << ')'; return; } QSpanCollection::Span *sp = spans.spanAt(column, row); diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index 61f1b5b..7837700 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -246,7 +246,7 @@ void QTreeView::setModel(QAbstractItemModel *model) connect(d->model, SIGNAL(modelAboutToBeReset()), SLOT(_q_modelAboutToBeReset())); if (d->sortingEnabled) - sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); + d->_q_sortIndicatorChanged(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); } /*! @@ -680,10 +680,9 @@ void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto // refresh the height cache here; we don't really lose anything by getting the size hint, // since QAbstractItemView::dataChanged() will get the visualRect for the items anyway - QModelIndex top = topLeft.sibling(topLeft.row(), 0); - int topViewIndex = d->viewIndex(top); + int topViewIndex = d->viewIndex(topLeft); if (topViewIndex == 0) - d->defaultItemHeight = indexRowSizeHint(top); + d->defaultItemHeight = indexRowSizeHint(topLeft); bool sizeChanged = false; if (topViewIndex != -1) { if (topLeft == bottomRight) { @@ -691,8 +690,7 @@ void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto d->invalidateHeightCache(topViewIndex); sizeChanged = (oldHeight != d->itemHeight(topViewIndex)); } else { - QModelIndex bottom = bottomRight.sibling(bottomRight.row(), 0); - int bottomViewIndex = d->viewIndex(bottom); + int bottomViewIndex = d->viewIndex(bottomRight); for (int i = topViewIndex; i <= bottomViewIndex; ++i) { int oldHeight = d->itemHeight(i); d->invalidateHeightCache(i); @@ -846,17 +844,19 @@ void QTreeView::setExpanded(const QModelIndex &index, bool expanded) void QTreeView::setSortingEnabled(bool enable) { Q_D(QTreeView); - d->sortingEnabled = enable; header()->setSortIndicatorShown(enable); header()->setClickable(enable); if (enable) { - connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), - this, SLOT(_q_sortIndicatorChanged(int, Qt::SortOrder))); + //sortByColumn has to be called before we connect or set the sortingEnabled flag + // because otherwise it will not call sort on the model. sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); + connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), + this, SLOT(_q_sortIndicatorChanged(int, Qt::SortOrder)), Qt::UniqueConnection); } else { disconnect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(_q_sortIndicatorChanged(int, Qt::SortOrder))); } + d->sortingEnabled = enable; } bool QTreeView::isSortingEnabled() const @@ -1546,7 +1546,7 @@ void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, ? logicalIndexBeforeLeft : logicalIndices.at(currentLogicalSection - 1); if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1) - || (headerSection == 0 && nextLogicalSection == -1)) + || (headerSection == 0 && nextLogicalSection == -1) || spanning) opt.viewItemPosition = QStyleOptionViewItemV4::OnlyOne; else if (headerSection == 0 || (nextLogicalSection != 0 && prevLogicalSection == -1)) opt.viewItemPosition = QStyleOptionViewItemV4::Beginning; @@ -1815,10 +1815,10 @@ void QTreeView::mouseDoubleClickEvent(QMouseEvent *event) if (i == -1) return; // user clicked outside the items - const QModelIndex &index = d->viewItems.at(i).index; + const QPersistentModelIndex firstColumnIndex = d->viewItems.at(i).index; int column = d->header->logicalIndexAt(event->x()); - QPersistentModelIndex persistent = index.sibling(index.row(), column); + QPersistentModelIndex persistent = firstColumnIndex.sibling(firstColumnIndex.row(), column); if (d->pressedIndex != persistent) { mousePressEvent(event); @@ -1841,10 +1841,10 @@ void QTreeView::mouseDoubleClickEvent(QMouseEvent *event) if (d->itemsExpandable && d->expandsOnDoubleClick && d->hasVisibleChildren(persistent)) { - if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == persistent))) { + if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == firstColumnIndex))) { // find the new index of the item for (i = 0; i < d->viewItems.count(); ++i) { - if (d->viewItems.at(i).index == persistent) + if (d->viewItems.at(i).index == firstColumnIndex) break; } if (i == d->viewItems.count()) @@ -2422,14 +2422,10 @@ void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end) ? d->viewItems.count() : d->viewItems.at(parentItem).total) - 1; - int firstColumn = 0; - while (isColumnHidden(firstColumn) && firstColumn < header()->count() - 1) - ++firstColumn; - const int delta = end - start + 1; QVector<QTreeViewItem> insertedItems(delta); for (int i = 0; i < delta; ++i) { - insertedItems[i].index = d->model->index(i + start, firstColumn, parent); + insertedItems[i].index = d->model->index(i + start, 0, parent); insertedItems[i].level = childLevel; } if (d->viewItems.isEmpty()) @@ -2612,7 +2608,7 @@ void QTreeView::expandAll() d->viewItems[i].expanded = true; d->layout(i); QModelIndex idx = d->viewItems.at(i).index; - d->expandedIndexes.insert(idx.sibling(idx.row(), 0)); + d->expandedIndexes.insert(idx); } updateGeometries(); d->viewport->update(); @@ -3092,10 +3088,6 @@ void QTreeViewPrivate::layout(int i) Q_Q(QTreeView); QModelIndex current; QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i); - // modelIndex() will return an index that don't have a parent if column 0 is hidden, - // so we must make sure that parent points to the actual parent that has children. - if (parent != root) - parent = model->index(parent.row(), 0, parent.parent()); if (i>=0 && !parent.isValid()) { //modelIndex() should never return something invalid for the real items. @@ -3130,13 +3122,9 @@ void QTreeViewPrivate::layout(int i) int last = 0; int children = 0; - int firstColumn = 0; - while (header->isSectionHidden(firstColumn) && firstColumn < header->count()) - ++firstColumn; - for (int j = first; j < first + count; ++j) { - current = model->index(j - first, firstColumn, parent); - if (isRowHidden(current.sibling(current.row(), 0))) { + current = model->index(j - first, 0, parent); + if (isRowHidden(current)) { ++hidden; last = j - hidden + children; } else { @@ -3319,15 +3307,11 @@ int QTreeViewPrivate::itemAtCoordinate(int coordinate) const int QTreeViewPrivate::viewIndex(const QModelIndex &_index) const { - Q_Q(const QTreeView); if (!_index.isValid() || viewItems.isEmpty()) return -1; const int totalCount = viewItems.count(); - int firstColumn = 0; - while (q->isColumnHidden(firstColumn) && firstColumn < header->count()) - ++firstColumn; - const QModelIndex index = _index.sibling(_index.row(), firstColumn); + const QModelIndex index = _index.sibling(_index.row(), 0); // A quick check near the last item to see if we are just incrementing diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 98285f0..a9424db 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -838,6 +838,9 @@ void QApplicationPrivate::initialize() // trigger registering of QVariant's GUI types extern int qRegisterGuiVariant(); qRegisterGuiVariant(); + // trigger registering of QStateMachine's GUI types + extern int qRegisterGuiStateMachine(); + qRegisterGuiStateMachine(); is_app_running = true; // no longer starting up @@ -1059,6 +1062,9 @@ QApplication::~QApplication() QApplicationPrivate::fade_tooltip = false; QApplicationPrivate::widgetCount = false; + // trigger unregistering of QStateMachine's GUI types + extern int qUnregisterGuiStateMachine(); + qUnregisterGuiStateMachine(); // trigger unregistering of QVariant's GUI types extern int qUnregisterGuiVariant(); qUnregisterGuiVariant(); @@ -2022,12 +2028,10 @@ QWidget *QApplication::focusWidget() void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) { - if (focus && focus->window() #ifndef QT_NO_GRAPHICSVIEW - && focus->window()->graphicsProxyWidget() -#endif - ) + if (focus && focus->window()->graphicsProxyWidget()) return; +#endif hidden_focus_widget = 0; @@ -4989,6 +4993,137 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) return true; } +/*! \fn QDecoration &QApplication::qwsDecoration() + Return the QWSDecoration used for decorating windows. + + \warning This method is non-portable. It is only available in + Qt for Embedded Linux. + + \sa QDecoration +*/ + +/*! + \fn void QApplication::qwsSetDecoration(QDecoration *decoration) + + Sets the QDecoration derived class to use for decorating the + windows used by Qt for Embedded Linux to the \a decoration + specified. + + This method is non-portable. It is only available in Qt for Embedded Linux. + + \sa QDecoration +*/ + +/*! \fn QDecoration* QApplication::qwsSetDecoration(const QString &decoration) + \overload + + Requests a QDecoration object for \a decoration from the QDecorationFactory. + + The string must be one of the QDecorationFactory::keys(). Keys are + case insensitive. + + A later call to the QApplication constructor will override the + requested style when a "-style" option is passed in as a commandline + parameter. + + Returns 0 if an unknown \a decoration is passed, otherwise the QStyle object + returned is set as the application's GUI style. +*/ + +/*! + \fn bool QApplication::qwsEventFilter(QWSEvent *event) + + This virtual function is only implemented under Qt for Embedded Linux. + + If you create an application that inherits QApplication and + reimplement this function, you get direct access to all QWS (Q + Window System) events that the are received from the QWS master + process. The events are passed in the \a event parameter. + + Return true if you want to stop the event from being processed. + Return false for normal event dispatching. The default + implementation returns false. +*/ + +/*! \fn void QApplication::qwsSetCustomColors(QRgb *colorTable, int start, int numColors) + Set Qt for Embedded Linux custom color table. + + Qt for Embedded Linux on 8-bpp displays allocates a standard 216 color cube. + The remaining 40 colors may be used by setting a custom color + table in the QWS master process before any clients connect. + + \a colorTable is an array of up to 40 custom colors. \a start is + the starting index (0-39) and \a numColors is the number of colors + to be set (1-40). + + This method is non-portable. It is available \e only in + Qt for Embedded Linux. + + \note The custom colors will not be used by the default screen + driver. To make use of the new colors, implement a custom screen + driver, or use QDirectPainter. +*/ + +/*! \fn int QApplication::qwsProcessEvent(QWSEvent* event) + \internal +*/ + +/*! \fn int QApplication::x11ClientMessage(QWidget* w, XEvent* event, bool passive_only) + \internal +*/ + +/*! \fn int QApplication::x11ProcessEvent(XEvent* event) + This function does the core processing of individual X + \a{event}s, normally by dispatching Qt events to the right + destination. + + It returns 1 if the event was consumed by special handling, 0 if + the \a event was consumed by normal handling, and -1 if the \a + event was for an unrecognized widget. + + \sa x11EventFilter() +*/ + +/*! + \fn bool QApplication::x11EventFilter(XEvent *event) + + \warning This virtual function is only implemented under X11. + + If you create an application that inherits QApplication and + reimplement this function, you get direct access to all X events + that the are received from the X server. The events are passed in + the \a event parameter. + + Return true if you want to stop the event from being processed. + Return false for normal event dispatching. The default + implementation returns false. + + It is only the directly addressed messages that are filtered. + You must install an event filter directly on the event + dispatcher, which is returned by + QAbstractEventDispatcher::instance(), to handle system wide + messages. + + \sa x11ProcessEvent() +*/ + +/*! \fn void QApplication::winFocus(QWidget *widget, bool gotFocus) + \internal + \since 4.1 + + If \a gotFocus is true, \a widget will become the active window. + Otherwise the active window is reset to 0. +*/ + +/*! \fn void QApplication::winMouseButtonUp() + \internal + */ + +/*! \fn void QApplication::syncX() + Synchronizes with the X server in the X11 implementation. + This normally takes some time. Does nothing on other platforms. +*/ + QT_END_NAMESPACE #include "moc_qapplication.cpp" diff --git a/src/gui/kernel/qapplication_qws.cpp b/src/gui/kernel/qapplication_qws.cpp index fcfd2a4..ea52e11 100644 --- a/src/gui/kernel/qapplication_qws.cpp +++ b/src/gui/kernel/qapplication_qws.cpp @@ -194,7 +194,7 @@ QString qws_dataDir() static QString result; if (!result.isEmpty()) return result; - QByteArray dataDir = QString(QLatin1String("/tmp/qtembedded-%1")).arg(qws_display_id).toLocal8Bit(); + QByteArray dataDir = QString::fromLatin1("/tmp/qtembedded-%1").arg(qws_display_id).toLocal8Bit(); if (QT_MKDIR(dataDir, 0700)) { if (errno != EEXIST) { qFatal("Cannot create Qt for Embedded Linux data directory: %s", dataDir.constData()); @@ -215,7 +215,7 @@ QString qws_dataDir() if ((buf.st_mode & 0677) != 0600) qFatal("Qt for Embedded Linux data directory has incorrect permissions: %s", dataDir.constData()); #endif - dataDir += "/"; + dataDir += '/'; result = QString::fromLocal8Bit(dataDir); return result; @@ -224,7 +224,7 @@ QString qws_dataDir() // Get the filename of the pipe Qt for Embedded Linux uses for server/client comms Q_GUI_EXPORT QString qws_qtePipeFilename() { - return (qws_dataDir() + QString(QLatin1String(QTE_PIPE)).arg(qws_display_id)); + return (qws_dataDir() + QString::fromLatin1(QTE_PIPE).arg(qws_display_id)); } static void setMaxWindowRect(const QRect &rect) @@ -2676,9 +2676,6 @@ void QApplication::alert(QWidget *, int) { } -/*! - \internal -*/ int QApplication::qwsProcessEvent(QWSEvent* event) { Q_D(QApplication); @@ -3057,43 +3054,11 @@ int QApplication::qwsProcessEvent(QWSEvent* event) return 0; } -/*! - \fn bool QApplication::qwsEventFilter(QWSEvent *event) - - This virtual function is only implemented under Qt for Embedded Linux. - - If you create an application that inherits QApplication and - reimplement this function, you get direct access to all QWS (Q - Window System) events that the are received from the QWS master - process. The events are passed in the \a event parameter. - - Return true if you want to stop the event from being processed. - Return false for normal event dispatching. The default - implementation returns false. -*/ bool QApplication::qwsEventFilter(QWSEvent *) { return false; } -/*! - Set Qt for Embedded Linux custom color table. - - Qt for Embedded Linux on 8-bpp displays allocates a standard 216 color cube. - The remaining 40 colors may be used by setting a custom color - table in the QWS master process before any clients connect. - - \a colorTable is an array of up to 40 custom colors. \a start is - the starting index (0-39) and \a numColors is the number of colors - to be set (1-40). - - This method is non-portable. It is available \e only in - Qt for Embedded Linux. - - \note The custom colors will not be used by the default screen - driver. To make use of the new colors, implement a custom screen - driver, or use QDirectPainter. -*/ void QApplication::qwsSetCustomColors(QRgb *colorTable, int start, int numColors) { if (start < 0 || start > 39) { @@ -3112,30 +3077,11 @@ void QApplication::qwsSetCustomColors(QRgb *colorTable, int start, int numColors } #ifndef QT_NO_QWS_MANAGER -/*! - Return the QWSDecoration used for decorating windows. - - \warning This method is non-portable. It is only available in - Qt for Embedded Linux. - - \sa QDecoration -*/ QDecoration &QApplication::qwsDecoration() { return *qws_decoration; } -/*! - \fn void QApplication::qwsSetDecoration(QDecoration *decoration) - - Sets the QDecoration derived class to use for decorating the - windows used by Qt for Embedded Linux to the \a decoration - specified. - - This method is non-portable. It is only available in Qt for Embedded Linux. - - \sa QDecoration -*/ void QApplication::qwsSetDecoration(QDecoration *dec) { if (dec) { @@ -3154,21 +3100,6 @@ void QApplication::qwsSetDecoration(QDecoration *dec) } } -/*! - \overload - - Requests a QDecoration object for \a decoration from the QDecorationFactory. - - The string must be one of the QDecorationFactory::keys(). Keys are - case insensitive. - - A later call to the QApplication constructor will override the - requested style when a "-style" option is passed in as a commandline - parameter. - - Returns 0 if an unknown \a decoration is passed, otherwise the QStyle object - returned is set as the application's GUI style. -*/ QDecoration* QApplication::qwsSetDecoration(const QString &decoration) { QDecoration *decore = QDecorationFactory::create(decoration); diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 07b3865..670058b 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -376,11 +376,6 @@ QRgb qt_colorref2qrgb(COLORREF col) Internal variables and functions *****************************************************************************/ -extern Q_CORE_EXPORT char theAppName[]; -extern Q_CORE_EXPORT char appFileName[]; -extern Q_CORE_EXPORT HINSTANCE appInst; // handle to app instance -extern Q_CORE_EXPORT HINSTANCE appPrevInst; // handle to prev app instance -extern Q_CORE_EXPORT int appCmdShow; // main window show command static HWND curWin = 0; // current window static HDC displayDC = 0; // display device context @@ -752,20 +747,11 @@ void qt_init(QApplicationPrivate *priv, int) priv->argc = j; } - // Get the application name/instance if qWinMain() was not invoked #ifndef Q_WS_WINCE // No message boxes but important ones SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); #endif - if (appInst == 0) { - QT_WA({ - appInst = GetModuleHandle(0); - }, { - appInst = GetModuleHandleA(0); - }); - } - #ifndef Q_WS_WINCE // Initialize OLE/COM // S_OK means success and S_FALSE means that it has already @@ -790,7 +776,7 @@ void qt_init(QApplicationPrivate *priv, int) #ifndef QT_NO_CURSOR QCursorData::initialize(); #endif - qApp->setObjectName(QLatin1String(theAppName)); + qApp->setObjectName(priv->appName()); #if !defined(Q_WS_WINCE) // default font @@ -888,12 +874,6 @@ void qt_cleanup() Platform specific global and internal functions *****************************************************************************/ -Q_GUI_EXPORT int qWinAppCmdShow() // get main window show command -{ - return appCmdShow; -} - - Q_GUI_EXPORT HDC qt_win_display_dc() // get display DC { Q_ASSERT(qApp && qApp->thread() == QThread::currentThread()); @@ -975,8 +955,8 @@ const QString qt_reg_winclass(QWidget *w) // register window class wchar_t uniqueAppID[256]; GetModuleFileNameW(0, uniqueAppID, 255); cname = QString::number(RegisterWindowMessageW( - (const wchar_t *) QString::fromUtf16((const ushort *)uniqueAppID).toLower().replace(QString(QString::fromLatin1("\\")), - QString(QString::fromLatin1("_"))).utf16())); + (const wchar_t *) QString::fromUtf16((const ushort *)uniqueAppID).toLower().replace(QLatin1Char('\\'), + QLatin1Char('_')).utf16())); #endif // since multiple Qt versions can be used in one process @@ -989,11 +969,11 @@ const QString qt_reg_winclass(QWidget *w) // register window class if (classExists == -1) { QT_WA({ WNDCLASS wcinfo; - classExists = GetClassInfo((HINSTANCE)qWinAppInst(), (TCHAR*)cname.utf16(), &wcinfo); + classExists = GetClassInfo(qWinAppInst(), (TCHAR*)cname.utf16(), &wcinfo); classExists = classExists && wcinfo.lpfnWndProc != QtWndProc; }, { WNDCLASSA wcinfo; - classExists = GetClassInfoA((HINSTANCE)qWinAppInst(), cname.toLatin1(), &wcinfo); + classExists = GetClassInfoA(qWinAppInst(), cname.toLatin1(), &wcinfo); classExists = classExists && wcinfo.lpfnWndProc != QtWndProc; }); } @@ -1013,9 +993,9 @@ const QString qt_reg_winclass(QWidget *w) // register window class wc.lpfnWndProc = (WNDPROC)QtWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; - wc.hInstance = (HINSTANCE)qWinAppInst(); + wc.hInstance = qWinAppInst(); if (icon) { - wc.hIcon = LoadIcon(appInst, L"IDI_ICON1"); + wc.hIcon = LoadIcon(qWinAppInst(), L"IDI_ICON1"); if (!wc.hIcon) wc.hIcon = LoadIcon(0, IDI_APPLICATION); } else { @@ -1032,9 +1012,9 @@ const QString qt_reg_winclass(QWidget *w) // register window class wc.lpfnWndProc = (WNDPROC)QtWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; - wc.hInstance = (HINSTANCE)qWinAppInst(); + wc.hInstance = qWinAppInst(); if (icon) { - wc.hIcon = LoadIconA(appInst, (char*)"IDI_ICON1"); + wc.hIcon = LoadIconA(qWinAppInst(), (char*)"IDI_ICON1"); if (!wc.hIcon) wc.hIcon = LoadIconA(0, (char*)IDI_APPLICATION); } else { @@ -1053,9 +1033,9 @@ const QString qt_reg_winclass(QWidget *w) // register window class wc.lpfnWndProc = (WNDPROC)QtWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; - wc.hInstance = (HINSTANCE)qWinAppInst(); + wc.hInstance = qWinAppInst(); if (icon) { - wc.hIcon = LoadIcon(appInst, L"IDI_ICON1"); + wc.hIcon = LoadIcon(qWinAppInst(), L"IDI_ICON1"); // if (!wc.hIcon) // wc.hIcon = LoadIcon(0, IDI_APPLICATION); } else { @@ -1089,9 +1069,9 @@ static void unregWinClasses() QHash<QString, int>::ConstIterator it = hash->constBegin(); while (it != hash->constEnd()) { QT_WA({ - UnregisterClass((TCHAR*)it.key().utf16(), (HINSTANCE)qWinAppInst()); + UnregisterClass((TCHAR*)it.key().utf16(), qWinAppInst()); } , { - UnregisterClassA(it.key().toLatin1(), (HINSTANCE)qWinAppInst()); + UnregisterClassA(it.key().toLatin1(), qWinAppInst()); }); ++it; } @@ -1126,7 +1106,7 @@ void qWinRequestConfig(WId id, int req, int x, int y, int w, int h) configRequests->append(r); // store request in queue } -Q_GUI_EXPORT void qWinProcessConfigRequests() // perform requests in queue +static void qWinProcessConfigRequests() // perform requests in queue { if (!configRequests) return; @@ -1368,13 +1348,6 @@ QString QApplicationPrivate::appName() const extern uint qGlobalPostedEventsCount(); -/*! - \internal - \since 4.1 - - If \a gotFocus is true, \a widget will become the active window. - Otherwise the active window is reset to 0. -*/ void QApplication::winFocus(QWidget *widget, bool gotFocus) { if (d_func()->inPopupMode()) // some delayed focus event to ignore @@ -1679,20 +1652,23 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam // send the context menu event is a different one if (!alienWidget->testAttribute(Qt::WA_NativeWindow) && !alienWidget->testAttribute(Qt::WA_PaintOnScreen)) { alienWidget = QApplication::widgetAt(globalPos); - pos = alienWidget->mapFromGlobal(globalPos); + if (alienWidget) + pos = alienWidget->mapFromGlobal(globalPos); } - SHRGINFO shrg; - shrg.cbSize = sizeof(shrg); - shrg.hwndClient = hwnd; - shrg.ptDown.x = GET_X_LPARAM(lParam); - shrg.ptDown.y = GET_Y_LPARAM(lParam); - shrg.dwFlags = SHRG_RETURNCMD | SHRG_NOANIMATION; - resolveAygLibs(); - if (ptrRecognizeGesture && (ptrRecognizeGesture(&shrg) == GN_CONTEXTMENU)) { - if (qApp->activePopupWidget()) - qApp->activePopupWidget()->close(); - QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos); - result = qt_sendSpontaneousEvent(alienWidget, &e); + if (alienWidget) { + SHRGINFO shrg; + shrg.cbSize = sizeof(shrg); + shrg.hwndClient = hwnd; + shrg.ptDown.x = GET_X_LPARAM(lParam); + shrg.ptDown.y = GET_Y_LPARAM(lParam); + shrg.dwFlags = SHRG_RETURNCMD | SHRG_NOANIMATION; + resolveAygLibs(); + if (ptrRecognizeGesture && (ptrRecognizeGesture(&shrg) == GN_CONTEXTMENU)) { + if (qApp->activePopupWidget()) + qApp->activePopupWidget()->close(); + QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos); + result = qt_sendSpontaneousEvent(alienWidget, &e); + } } } } @@ -1729,6 +1705,21 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam // fall-through intended case WM_KEYUP: case WM_SYSKEYUP: +#if Q_OS_WINCE_WM + case WM_HOTKEY: + if(HIWORD(msg.lParam) == VK_TBACK) { + const bool hotKeyDown = !(LOWORD(msg.lParam) & MOD_KEYUP); + msg.lParam = 0x69 << 16; + msg.wParam = VK_BACK; + if (hotKeyDown) { + msg.message = WM_KEYDOWN; + qt_keymapper_private()->updateKeyMap(msg); + } else { + msg.message = WM_KEYUP; + } + } + // fall-through intended +#endif case WM_IME_CHAR: case WM_IME_KEYDOWN: case WM_CHAR: { @@ -2429,10 +2420,12 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam widget = (QETWidget*)qApp->focusWidget(); HWND focus = ::GetFocus(); //if there is a current widget and the new widget belongs to the same toplevel window + //or if the current widget was embedded into non-qt window (i.e. we won't get WM_ACTIVATEAPP) //then we clear the focus on the widget //in case the new widget belongs to a different widget hierarchy, clearing the focus //will be handled because the active window will change - if (widget && ::IsChild(widget->window()->internalWinId(), focus)) { + const bool embedded = widget && ((QETWidget*)widget->window())->topData()->embedded; + if (widget && (embedded || ::IsChild(widget->window()->internalWinId(), focus))) { widget->clearFocus(); result = true; } else { @@ -2916,7 +2909,6 @@ void qt_win_eatMouseMove() // In DnD, the mouse release event never appears, so the // mouse button state machine must be manually reset -/*! \internal */ void QApplication::winMouseButtonUp() { qt_button_down = 0; diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index d7ca2f4..90376b3 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -2975,15 +2975,10 @@ QWidget *QApplication::topLevelAt(const QPoint &p) #endif } -/*! - Synchronizes with the X server in the X11 implementation. This - normally takes some time. Does nothing on other platforms. -*/ - void QApplication::syncX() { if (X11->display) - XSync(X11->display, False); // don't discard events + XSync(X11->display, False); // don't discard events } @@ -3085,9 +3080,6 @@ static QETWidget *qPRFindWidget(Window oldwin) return wPRmapper ? (QETWidget*)wPRmapper->value((int)oldwin, 0) : 0; } -/*! - \internal -*/ int QApplication::x11ClientMessage(QWidget* w, XEvent* event, bool passive_only) { if (w && !w->internalWinId()) @@ -3150,17 +3142,6 @@ int QApplication::x11ClientMessage(QWidget* w, XEvent* event, bool passive_only) return 0; } -/*! - This function does the core processing of individual X - \a{event}s, normally by dispatching Qt events to the right - destination. - - It returns 1 if the event was consumed by special handling, 0 if - the \a event was consumed by normal handling, and -1 if the \a - event was for an unrecognized widget. - - \sa x11EventFilter() -*/ int QApplication::x11ProcessEvent(XEvent* event) { Q_D(QApplication); @@ -3168,43 +3149,48 @@ int QApplication::x11ProcessEvent(XEvent* event) #ifdef ALIEN_DEBUG //qDebug() << "QApplication::x11ProcessEvent:" << event->type; #endif + Time time = 0, userTime = 0; switch (event->type) { case ButtonPress: pressed_window = event->xbutton.window; - X11->userTime = event->xbutton.time; + userTime = event->xbutton.time; // fallthrough intended case ButtonRelease: - X11->time = event->xbutton.time; + time = event->xbutton.time; break; case MotionNotify: - X11->time = event->xmotion.time; + time = event->xmotion.time; break; case XKeyPress: - X11->userTime = event->xkey.time; + userTime = event->xkey.time; // fallthrough intended case XKeyRelease: - X11->time = event->xkey.time; + time = event->xkey.time; break; case PropertyNotify: - X11->time = event->xproperty.time; + time = event->xproperty.time; break; case EnterNotify: case LeaveNotify: - X11->time = event->xcrossing.time; + time = event->xcrossing.time; break; case SelectionClear: - X11->time = event->xselectionclear.time; + time = event->xselectionclear.time; break; default: - break; - } #ifndef QT_NO_XFIXES - if (X11->use_xfixes && event->type == (X11->xfixes_eventbase + XFixesSelectionNotify)) { - XFixesSelectionNotifyEvent *req = - reinterpret_cast<XFixesSelectionNotifyEvent *>(event); - X11->time = req->selection_timestamp; - } + if (X11->use_xfixes && event->type == (X11->xfixes_eventbase + XFixesSelectionNotify)) { + XFixesSelectionNotifyEvent *req = + reinterpret_cast<XFixesSelectionNotifyEvent *>(event); + time = req->selection_timestamp; + } #endif + break; + } + if (time > X11->time) + X11->time = time; + if (userTime > X11->userTime) + X11->userTime = userTime; QETWidget *widget = (QETWidget*)QWidget::find((WId)event->xany.window); @@ -3837,29 +3823,6 @@ int QApplication::x11ProcessEvent(XEvent* event) return 0; } -/*! - \fn bool QApplication::x11EventFilter(XEvent *event) - - \warning This virtual function is only implemented under X11. - - If you create an application that inherits QApplication and - reimplement this function, you get direct access to all X events - that the are received from the X server. The events are passed in - the \a event parameter. - - Return true if you want to stop the event from being processed. - Return false for normal event dispatching. The default - implementation returns false. - - It is only the directly addressed messages that are filtered. - You must install an event filter directly on the event - dispatcher, which is returned by - QAbstractEventDispatcher::instance(), to handle system wide - messages. - - \sa x11ProcessEvent() -*/ - bool QApplication::x11EventFilter(XEvent *) { return false; diff --git a/src/gui/kernel/qclipboard.cpp b/src/gui/kernel/qclipboard.cpp index 6daf433..96e9580 100644 --- a/src/gui/kernel/qclipboard.cpp +++ b/src/gui/kernel/qclipboard.cpp @@ -476,7 +476,7 @@ void QClipboard::setPixmap(const QPixmap &pixmap, Mode mode) The \a mode argument is used to control which part of the system clipboard is used. If \a mode is QClipboard::Clipboard, this - function clears the the global clipboard contents. If \a mode is + function clears the global clipboard contents. If \a mode is QClipboard::Selection, this function clears the global mouse selection contents. If \a mode is QClipboard::FindBuffer, this function clears the search string buffer. diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm index dad15d9..2ca6a3d 100644 --- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm +++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm @@ -90,6 +90,7 @@ QT_BEGIN_NAMESPACE extern void onApplicationChangedActivation(bool); // qapplication_mac.mm +extern void qt_release_apple_event_handler(); //qapplication_mac.mm QT_END_NAMESPACE QT_FORWARD_DECLARE_CLASS(QDesktopWidgetImplementation) @@ -183,28 +184,30 @@ static void cleanupCocoaApplicationDelegate() { Q_UNUSED(sender); // The reflection delegate gets precedence - NSApplicationTerminateReply reply = NSTerminateCancel; if (reflectionDelegate && [reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)]) { return [reflectionDelegate applicationShouldTerminate:sender]; } if (qtPrivate->canQuit()) { - reply = NSTerminateNow; if (!startedQuit) { startedQuit = true; qAppInstance()->quit(); startedQuit = false; } } - return reply; + + // Prevent Cocoa from terminating the application, since this simply + // exits the program whithout allowing QApplication::exec() to return. + // The call to QApplication::quit() above will instead quit the + // application from the Qt side. + return NSTerminateCancel; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { Q_UNUSED(aNotification); inLaunch = false; - extern void qt_release_apple_event_handler(); //qapplication_mac.mm qt_release_apple_event_handler(); } diff --git a/src/gui/kernel/qcocoapanel_mac.mm b/src/gui/kernel/qcocoapanel_mac.mm index c69826f..b2941fe 100644 --- a/src/gui/kernel/qcocoapanel_mac.mm +++ b/src/gui/kernel/qcocoapanel_mac.mm @@ -107,9 +107,16 @@ QT_USE_NAMESPACE - (void)sendEvent:(NSEvent *)event { - [self retain]; - QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; + + // Cocoa can hold onto the window after we've disavowed its knowledge. So, + // if we get sent an event afterwards just have it go through the super's + // version and don't do any stuff with Qt. + if (!widget) { + [super sendEvent:event]; + return; + } + [self retain]; QT_MANGLE_NAMESPACE(QCocoaView) *view = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(qt_mac_nativeview_for(widget)); Qt::MouseButton mouseButton = cocoaButton2QtButton([event buttonNumber]); diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 60ac062..838f751 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -199,6 +199,7 @@ extern "C" { composingText = new QString(); composing = false; sendKeyEvents = true; + currentCustomTypes = 0; [self setHidden:YES]; return self; } @@ -213,10 +214,16 @@ extern "C" { object:self]; } --(void)registerDragTypes:(bool)accept +-(void)registerDragTypes { QMacCocoaAutoReleasePool pool; - if (accept) { + // Calling registerForDraggedTypes is slow, so only do it once for each widget + // or when the custom types change. + const QStringList& customTypes = qEnabledDraggedTypes(); + if (currentCustomTypes == 0 || *currentCustomTypes != customTypes) { + if (currentCustomTypes == 0) + currentCustomTypes = new QStringList(); + *currentCustomTypes = customTypes; const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName"; NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType, NSFilenamesPboardType, NSStringPboardType, @@ -228,13 +235,10 @@ extern "C" { NSFilesPromisePboardType, NSInkTextPboardType, NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil]; // Add custom types supported by the application. - const QStringList& customTypes = qEnabledDraggedTypes(); for (int i = 0; i < customTypes.size(); i++) { [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))]; } [self registerForDraggedTypes:supportedTypes]; - } else { - [self unregisterDraggedTypes]; } } @@ -283,6 +287,8 @@ extern "C" { - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender { + if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false) + return NSDragOperationNone; [self addDropData:sender]; QMimeData *mimeData = dropData; if (QDragManager::self()->source()) @@ -416,6 +422,8 @@ extern "C" { { delete composingText; [[NSNotificationCenter defaultCenter] removeObserver:self]; + delete currentCustomTypes; + [self unregisterDraggedTypes]; [super dealloc]; } @@ -783,10 +791,22 @@ extern "C" { bool wheelOK = false; Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]); + QWidget *widgetToGetMouse = qwidget; + if (widgetToGetMouse->testAttribute(Qt::WA_TransparentForMouseEvents)) { + // Simulate passing the event through since Cocoa doesn't do that for us. + // Start by building a tree up. + NSView *candidateView = [self viewUnderTransparentForMouseView:self + widget:widgetToGetMouse + withWindowPoint:windowPoint]; + if (candidateView != nil) { + widgetToGetMouse = QWidget::find(WId(candidateView)); + } + } + // Mouse wheel deltas seem to tick in at increments of 0.1. Qt widgets - // expect the delta to be a multiple of 120. + // expect the delta to be a multiple of 120. const int ScrollFactor = 10 * 120; - // The qMax(...) factor reduces the + // The qMax(...) factor reduces the // acceleration for large wheel deltas. int deltaX = [theEvent deltaX] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaX])); int deltaY = [theEvent deltaY] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaY])); @@ -794,10 +814,10 @@ extern "C" { if (deltaX != 0) { QWheelEvent qwe(qlocal, qglobal, deltaX, buttons, keyMods, Qt::Horizontal); - qt_sendSpontaneousEvent(qwidget, &qwe); + qt_sendSpontaneousEvent(widgetToGetMouse, &qwe); wheelOK = qwe.isAccepted(); if (!wheelOK && QApplicationPrivate::focus_widget - && QApplicationPrivate::focus_widget != qwidget) { + && QApplicationPrivate::focus_widget != widgetToGetMouse) { QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal, deltaX, buttons, keyMods, Qt::Horizontal); qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); @@ -807,10 +827,10 @@ extern "C" { if (deltaY) { QWheelEvent qwe(qlocal, qglobal, deltaY, buttons, keyMods, Qt::Vertical); - qt_sendSpontaneousEvent(qwidget, &qwe); + qt_sendSpontaneousEvent(widgetToGetMouse, &qwe); wheelOK = qwe.isAccepted(); if (!wheelOK && QApplicationPrivate::focus_widget - && QApplicationPrivate::focus_widget != qwidget) { + && QApplicationPrivate::focus_widget != widgetToGetMouse) { QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal, deltaY, buttons, keyMods, Qt::Vertical); qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); @@ -822,10 +842,10 @@ extern "C" { // Qt doesn't explicitly support wheels with a Z component. In a misguided attempt to // try to be ahead of the pack, I'm adding this extra value. QWheelEvent qwe(qlocal, qglobal, deltaZ, buttons, keyMods, (Qt::Orientation)3); - qt_sendSpontaneousEvent(qwidget, &qwe); + qt_sendSpontaneousEvent(widgetToGetMouse, &qwe); wheelOK = qwe.isAccepted(); if (!wheelOK && QApplicationPrivate::focus_widget - && QApplicationPrivate::focus_widget != qwidget) { + && QApplicationPrivate::focus_widget != widgetToGetMouse) { QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal, deltaZ, buttons, keyMods, (Qt::Orientation)3); qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); diff --git a/src/gui/kernel/qcocoaview_mac_p.h b/src/gui/kernel/qcocoaview_mac_p.h index ec1281e..be4501f3 100644 --- a/src/gui/kernel/qcocoaview_mac_p.h +++ b/src/gui/kernel/qcocoaview_mac_p.h @@ -59,6 +59,7 @@ QT_FORWARD_DECLARE_CLASS(QWidgetPrivate); QT_FORWARD_DECLARE_CLASS(QWidget); QT_FORWARD_DECLARE_CLASS(QEvent); QT_FORWARD_DECLARE_CLASS(QCocoaDropData); +QT_FORWARD_DECLARE_CLASS(QStringList); QT_BEGIN_NAMESPACE struct DnDParams @@ -84,6 +85,7 @@ Q_GUI_EXPORT int composingLength; bool sendKeyEvents; QString *composingText; + QStringList *currentCustomTypes; } - (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate; - (void) finishInitWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate; @@ -92,7 +94,7 @@ Q_GUI_EXPORT - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender; - (void)draggingExited:(id < NSDraggingInfo >)sender; - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender; -- (void)registerDragTypes:(bool)accept; +- (void)registerDragTypes; - (void)removeDropData; - (void)addDropData:(id <NSDraggingInfo>)sender; - (void)setSupportedActions:(NSDragOperation)actions; diff --git a/src/gui/kernel/qcocoawindow_mac.mm b/src/gui/kernel/qcocoawindow_mac.mm index 89f481f..8e62f02 100644 --- a/src/gui/kernel/qcocoawindow_mac.mm +++ b/src/gui/kernel/qcocoawindow_mac.mm @@ -128,12 +128,19 @@ QT_USE_NAMESPACE - (void)sendEvent:(NSEvent *)event { - [self retain]; - QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; + + // Cocoa can hold onto the window after we've disavowed its knowledge. So, + // if we get sent an event afterwards just have it go through the super's + // version and don't do any stuff with Qt. + if (!widget) { + [super sendEvent:event]; + return; + } + + [self retain]; QT_MANGLE_NAMESPACE(QCocoaView) *view = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(qt_mac_nativeview_for(widget)); Qt::MouseButton mouseButton = cocoaButton2QtButton([event buttonNumber]); - // sometimes need to redirect mouse events to the popup. QWidget *popup = qAppInstance()->activePopupWidget(); if (popup && popup != widget) { diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp index ed7e020..598f4ba 100644 --- a/src/gui/kernel/qcursor.cpp +++ b/src/gui/kernel/qcursor.cpp @@ -375,7 +375,9 @@ void QCursorData::cleanup() return; for (int shape = 0; shape <= Qt::LastCursor; ++shape) { - delete qt_cursorTable[shape]; + // In case someone has a static QCursor defined with this shape + if (!qt_cursorTable[shape]->ref.deref()) + delete qt_cursorTable[shape]; qt_cursorTable[shape] = 0; } QCursorData::initialized = false; diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h index 7a0cb7a..9871658 100644 --- a/src/gui/kernel/qdnd_p.h +++ b/src/gui/kernel/qdnd_p.h @@ -202,7 +202,7 @@ public: #endif }; -class Q_GUI_EXPORT QDragManager: public QObject { +class QDragManager: public QObject { Q_OBJECT QDragManager(); diff --git a/src/gui/kernel/qdnd_x11.cpp b/src/gui/kernel/qdnd_x11.cpp index ed93b34..9b2305d 100644 --- a/src/gui/kernel/qdnd_x11.cpp +++ b/src/gui/kernel/qdnd_x11.cpp @@ -543,7 +543,7 @@ bool QX11Data::xdndMimeDataForAtom(Atom a, QMimeData *mimeData, QByteArray *data (dm->xdndMimeTransferedPixmapIndex + 1) % 2; } } else { - DEBUG("QClipboard: xdndMimeDataForAtom(): converting to type '%s' is not supported", atomName); + DEBUG("QClipboard: xdndMimeDataForAtom(): converting to type '%s' is not supported", qPrintable(atomName)); } } return data; @@ -624,7 +624,6 @@ QVariant QX11Data::xdndMimeConvertToFormat(Atom a, const QByteArray &data, const if (format == QLatin1String("image/ppm")) { if (a == XA_PIXMAP && data.size() == sizeof(Pixmap)) { Pixmap xpm = *((Pixmap*)data.data()); - Display *dpy = display; if (!xpm) return QByteArray(); QPixmap qpm = QPixmap::fromX11Pixmap(xpm); diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 8c7e47d..a59e870 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -675,12 +675,13 @@ QWheelEvent::QWheelEvent(const QPoint &pos, const QPoint& globalPos, int delta, The \a type parameter must be QEvent::KeyPress, QEvent::KeyRelease, or QEvent::ShortcutOverride. - If \a key is 0, the event is not a result of - a known key; for example, it may be the result of a compose - sequence or keyboard macro. The \a modifiers holds the keyboard - modifiers, and the given \a text is the Unicode text that the - key generated. If \a autorep is true, isAutoRepeat() will be - true. \a count is the number of keys involved in the event. + Int \a key is the code for the Qt::Key that the event loop should listen + for. If \a key is 0, the event is not a result of a known key; for + example, it may be the result of a compose sequence or keyboard macro. + The \a modifiers holds the keyboard modifiers, and the given \a text + is the Unicode text that the key generated. If \a autorep is true, + isAutoRepeat() will be true. \a count is the number of keys involved + in the event. */ QKeyEvent::QKeyEvent(Type type, int key, Qt::KeyboardModifiers modifiers, const QString& text, bool autorep, ushort count) @@ -860,6 +861,17 @@ bool QKeyEvent::matches(QKeySequence::StandardKey matchKey) const uint searchkey = (modifiers() | key()) & ~(Qt::KeypadModifier); //The keypad modifier should not make a difference uint platform = QApplicationPrivate::currentPlatform(); +#ifdef Q_WS_MAC + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + uint oldSearchKey = searchkey; + searchkey &= ~(Qt::ControlModifier | Qt::MetaModifier); + if (oldSearchKey & Qt::ControlModifier) + searchkey |= Qt::MetaModifier; + if (oldSearchKey & Qt::MetaModifier) + searchkey |= Qt::ControlModifier; + } +#endif + uint N = QKeySequencePrivate::numberOfKeyBindings; int first = 0; int last = N - 1; @@ -3069,7 +3081,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) { << ", " << me->button() << ", " << hex << (int)me->buttons() << ", " << hex << (int)me->modifiers() - << ")"; + << ')'; } return dbg.space(); @@ -3090,7 +3102,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) { #ifndef QT_NO_WHEELEVENT case QEvent::Wheel: dbg.nospace() << "QWheelEvent(" << static_cast<const QWheelEvent *>(e)->delta() - << ")"; + << ')'; return dbg.space(); #endif case QEvent::KeyPress: @@ -3116,7 +3128,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) { << ", \"" << ke->text() << "\", " << ke->isAutoRepeat() << ", " << ke->count() - << ")"; + << ')'; } return dbg.space(); case QEvent::FocusIn: diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h index cc94aad..8e762d6 100644 --- a/src/gui/kernel/qevent_p.h +++ b/src/gui/kernel/qevent_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE // // ### Qt 5: remove -class Q_GUI_EXPORT QKeyEventEx : public QKeyEvent +class QKeyEventEx : public QKeyEvent { public: QKeyEventEx(Type type, int key, Qt::KeyboardModifiers modifiers, @@ -76,7 +76,7 @@ protected: }; // ### Qt 5: remove -class Q_GUI_EXPORT QMouseEventEx : public QMouseEvent +class QMouseEventEx : public QMouseEvent { public: QMouseEventEx(Type type, const QPointF &pos, const QPoint &globalPos, diff --git a/src/gui/kernel/qformlayout.cpp b/src/gui/kernel/qformlayout.cpp index e2d6108..a665c89 100644 --- a/src/gui/kernel/qformlayout.cpp +++ b/src/gui/kernel/qformlayout.cpp @@ -689,12 +689,16 @@ void QFormLayoutPrivate::setupVerticalLayoutData(int width) // are split. maxLabelWidth = 0; if (!wrapAllRows) { + int maxFieldMinWidth = 0; //the maximum minimum size of the field for (int i = 0; i < rr; ++i) { const QFormLayoutItem *label = m_matrix(i, 0); const QFormLayoutItem *field = m_matrix(i, 1); - if (label && (label->sizeHint.width() + (field ? field->minSize.width() : 0) <= width)) + if (label && field && label->sideBySide) maxLabelWidth = qMax(maxLabelWidth, label->sizeHint.width()); + if (field) + maxFieldMinWidth = qMax(maxFieldMinWidth, field->minSize.width() + field->sbsHSpace); } + maxLabelWidth = qMin(maxLabelWidth, width - maxFieldMinWidth); } else { maxLabelWidth = width; } diff --git a/src/gui/kernel/qkeymapper.cpp b/src/gui/kernel/qkeymapper.cpp index 535d009..503a33b 100644 --- a/src/gui/kernel/qkeymapper.cpp +++ b/src/gui/kernel/qkeymapper.cpp @@ -116,6 +116,4 @@ QKeyMapperPrivate *qt_keymapper_private() return QKeyMapper::instance()->d_func(); } -Q_GUI_EXPORT QList<int> qt_keymapper_possibleKeys(QKeyEvent *e) { return QKeyMapper::instance()->possibleKeys(e); } - QT_END_NAMESPACE diff --git a/src/gui/kernel/qkeymapper_mac.cpp b/src/gui/kernel/qkeymapper_mac.cpp index 39abc5e..01b2c13 100644 --- a/src/gui/kernel/qkeymapper_mac.cpp +++ b/src/gui/kernel/qkeymapper_mac.cpp @@ -161,6 +161,14 @@ Qt::KeyboardModifiers qt_mac_get_modifiers(int keys) ret |= Qt::KeyboardModifier(qt_mac_modifier_symbols[i].qt_code); } } + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + Qt::KeyboardModifiers oldModifiers = ret; + ret &= ~(Qt::MetaModifier | Qt::ControlModifier); + if (oldModifiers & Qt::ControlModifier) + ret |= Qt::MetaModifier; + if (oldModifiers & Qt::MetaModifier) + ret |= Qt::ControlModifier; + } return ret; } static int qt_mac_get_mac_modifiers(Qt::KeyboardModifiers keys) @@ -177,6 +185,15 @@ static int qt_mac_get_mac_modifiers(Qt::KeyboardModifiers keys) ret |= qt_mac_modifier_symbols[i].mac_code; } } + + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + int oldModifiers = ret; + ret &= ~(controlKeyBit | cmdKeyBit); + if (oldModifiers & controlKeyBit) + ret |= cmdKeyBit; + if (oldModifiers & cmdKeyBit) + ret |= controlKeyBit; + } return ret; } void qt_mac_send_modifiers_changed(quint32 modifiers, QObject *object) diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 352d26a..ee45969 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -105,20 +105,39 @@ static bool operator<(int key, const MacSpecialKey &entry) static const MacSpecialKey * const MacSpecialKeyEntriesEnd = entries + NumEntries; -static QChar macSymbolForQtKey(int key) +QChar qt_macSymbolForQtKey(int key) { const MacSpecialKey *i = qBinaryFind(entries, MacSpecialKeyEntriesEnd, key); if (i == MacSpecialKeyEntriesEnd) return QChar(); - return QChar(i->macSymbol); + ushort macSymbol = i->macSymbol; + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) + && (macSymbol == kControlUnicode || macSymbol == kCommandUnicode)) { + if (macSymbol == kControlUnicode) + macSymbol = kCommandUnicode; + else + macSymbol = kControlUnicode; + } + + return QChar(macSymbol); } static int qtkeyForMacSymbol(const QChar ch) { + const ushort unicode = ch.unicode(); for (int i = 0; i < NumEntries; ++i) { const MacSpecialKey &entry = entries[i]; - if (entry.macSymbol == ch.unicode()) - return entry.key; + if (entry.macSymbol == unicode) { + int key = entry.key; + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) + && (unicode == kControlUnicode || unicode == kCommandUnicode)) { + if (unicode == kControlUnicode) + key = Qt::Key_Control; + else + key = Qt::Key_Meta; + } + return key; + } } return -1; } @@ -126,7 +145,7 @@ static int qtkeyForMacSymbol(const QChar ch) #else static bool qt_sequence_no_mnemonics = false; #endif -void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemonics = !b; } +void Q_AUTOTEST_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemonics = !b; } /*! \class QKeySequence @@ -213,12 +232,14 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni \row \i Open \i Ctrl+O \i Ctrl+O \i Ctrl+O \i Ctrl+O \row \i Close \i Ctrl+F4, Ctrl+W \i Ctrl+W, Ctrl+F4 \i Ctrl+W \i Ctrl+W \row \i Save \i Ctrl+S \i Ctrl+S \i Ctrl+S \i Ctrl+S + \row \i Quit \i \i Ctrl+Q \i Qtrl+Q \i Qtrl+Q \row \i SaveAs \i \i Ctrl+Shift+S \i \i Ctrl+Shift+S \row \i New \i Ctrl+N \i Ctrl+N \i Ctrl+N \i Ctrl+N \row \i Delete \i Del \i Del, Meta+D \i Del, Ctrl+D \i Del, Ctrl+D \row \i Cut \i Ctrl+X, Shift+Del \i Ctrl+X \i Ctrl+X, F20, Shift+Del \i Ctrl+X, F20, Shift+Del \row \i Copy \i Ctrl+C, Ctrl+Ins \i Ctrl+C \i Ctrl+C, F16, Ctrl+Ins \i Ctrl+C, F16, Ctrl+Ins \row \i Paste \i Ctrl+V, Shift+Ins \i Ctrl+V \i Ctrl+V, F18, Shift+Ins \i Ctrl+V, F18, Shift+Ins + \row \i Preferences \i \i Ctrl+, \i \i \row \i Undo \i Ctrl+Z, Alt+Backspace \i Ctrl+Z \i Ctrl+Z, F14 \i Ctrl+Z, F14 \row \i Redo \i Ctrl+Y, Shift+Ctrl+Z, Alt+Shift+Backspace \i Ctrl+Shift+Z, Ctrl+Y \i Ctrl+Shift+Z \i Ctrl+Shift+Z \row \i Back \i Alt+Left, Backspace \i Ctrl+[ \i Alt+Left \i Alt+Left @@ -521,6 +542,7 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::FindPrevious, 1, Qt::SHIFT | Qt::Key_F3, QApplicationPrivate::KB_Win}, {QKeySequence::ZoomIn, 1, Qt::CTRL | Qt::Key_Plus, QApplicationPrivate::KB_All}, {QKeySequence::NextChild, 0, Qt::CTRL | Qt::Key_Comma, QApplicationPrivate::KB_KDE}, + {QKeySequence::Preferences, 0, Qt::CTRL | Qt::Key_Comma, QApplicationPrivate::KB_Mac}, {QKeySequence::ZoomOut, 1, Qt::CTRL | Qt::Key_Minus, QApplicationPrivate::KB_All}, {QKeySequence::PreviousChild, 0, Qt::CTRL | Qt::Key_Period, QApplicationPrivate::KB_KDE}, {QKeySequence::HelpContents, 1, Qt::CTRL | Qt::Key_Question, QApplicationPrivate::KB_Mac}, @@ -538,6 +560,7 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::New, 1, Qt::CTRL | Qt::Key_N, QApplicationPrivate::KB_All}, {QKeySequence::Open, 1, Qt::CTRL | Qt::Key_O, QApplicationPrivate::KB_All}, {QKeySequence::Print, 1, Qt::CTRL | Qt::Key_P, QApplicationPrivate::KB_All}, + {QKeySequence::Quit, 0, Qt::CTRL | Qt::Key_Q, QApplicationPrivate::KB_Gnome | QApplicationPrivate::KB_KDE | QApplicationPrivate::KB_Mac}, {QKeySequence::Refresh, 1, Qt::CTRL | Qt::Key_R, QApplicationPrivate::KB_Gnome | QApplicationPrivate::KB_Mac}, {QKeySequence::Replace, 0, Qt::CTRL | Qt::Key_R, QApplicationPrivate::KB_KDE}, {QKeySequence::Save, 1, Qt::CTRL | Qt::Key_S, QApplicationPrivate::KB_All}, @@ -629,8 +652,6 @@ const uint QKeySequencePrivate::numberOfKeyBindings = sizeof(QKeySequencePrivate This enum represent standard key bindings. They can be used to assign platform dependent keyboard shortcuts to a QAction. - QKeyEvent also provides the function QKeyEvent::standardKey() to - query if it matches an existing key binding. Note that the key bindings are platform dependent. The currently bound shortcuts can be queried using keyBindings(). @@ -671,12 +692,14 @@ const uint QKeySequencePrivate::numberOfKeyBindings = sizeof(QKeySequencePrivate \value NextChild Navigate to next tab or child window. \value Open Open document. \value Paste Paste. + \value Preferences Open the preferences dialog. \value PreviousChild Navigate to previous tab or child window. \value Print Print document. + \value Quit Quit the application. \value Redo Redo. \value Refresh Refresh or reload current document. \value Replace Find and replace. - \value SaveAs Save document after prompting the user for a file name. + \value SaveAs Save document after prompting the user for a file name. \value Save Save document. \value SelectAll Select all text. \value SelectEndOfBlock Extend selection to the end of a text block. This shortcut is only used on OS X. @@ -782,6 +805,21 @@ QKeySequence::QKeySequence(const QKeySequence& keysequence) d->ref.ref(); } +#ifdef Q_WS_MAC +static inline int maybeSwapShortcut(int shortcut) +{ + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + uint oldshortcut = shortcut; + shortcut &= ~(Qt::CTRL | Qt::META); + if (oldshortcut & Qt::CTRL) + shortcut |= Qt::META; + if (oldshortcut & Qt::META) + shortcut |= Qt::CTRL; + } + return shortcut; +} +#endif + /*! \since 4.2 @@ -798,10 +836,16 @@ QList<QKeySequence> QKeySequence::keyBindings(StandardKey key) for (uint i = 0; i < QKeySequencePrivate::numberOfKeyBindings ; ++i) { QKeyBinding keyBinding = QKeySequencePrivate::keyBindings[i]; if (keyBinding.standardKey == key && (keyBinding.platform & platform)) { - if (keyBinding.priority > 0) - list.prepend(QKeySequence(QKeySequencePrivate::keyBindings[i].shortcut)); - else - list.append(QKeySequence(QKeySequencePrivate::keyBindings[i].shortcut)); + uint shortcut = +#ifdef Q_WS_MAC + maybeSwapShortcut(QKeySequencePrivate::keyBindings[i].shortcut); +#else + QKeySequencePrivate::keyBindings[i].shortcut; +#endif + if (keyBinding.priority > 0) + list.prepend(QKeySequence(shortcut)); + else + list.append(QKeySequence(shortcut)); } } return list; @@ -969,9 +1013,16 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence gmodifs = globalModifs(); if (gmodifs->isEmpty()) { #ifdef Q_WS_MAC - *gmodifs << QModifKeyName(Qt::CTRL, QChar(kCommandUnicode)); + const bool dontSwap = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta); + if (dontSwap) + *gmodifs << QModifKeyName(Qt::META, QChar(kCommandUnicode)); + else + *gmodifs << QModifKeyName(Qt::CTRL, QChar(kCommandUnicode)); *gmodifs << QModifKeyName(Qt::ALT, QChar(kOptionUnicode)); - *gmodifs << QModifKeyName(Qt::META, QChar(kControlUnicode)); + if (dontSwap) + *gmodifs << QModifKeyName(Qt::CTRL, QChar(kControlUnicode)); + else + *gmodifs << QModifKeyName(Qt::META, QChar(kControlUnicode)); *gmodifs << QModifKeyName(Qt::SHIFT, QChar(kShiftUnicode)); #endif *gmodifs << QModifKeyName(Qt::CTRL, QLatin1String("ctrl+")) @@ -1069,8 +1120,6 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence if (found) break; } -#ifdef Q_WS_MAC -#endif } return ret; } @@ -1099,15 +1148,30 @@ QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat QString s; #if defined(Q_WS_MAC) if (nativeText) { - // On MAC the order is Meta, Alt, Shift, Control. - if ((key & Qt::META) == Qt::META) - s += macSymbolForQtKey(Qt::Key_Meta); - if ((key & Qt::ALT) == Qt::ALT) - s += macSymbolForQtKey(Qt::Key_Alt); - if ((key & Qt::SHIFT) == Qt::SHIFT) - s += macSymbolForQtKey(Qt::Key_Shift); - if ((key & Qt::CTRL) == Qt::CTRL) - s += macSymbolForQtKey(Qt::Key_Control); + // On Mac OS X the order (by default) is Meta, Alt, Shift, Control. + // If the AA_MacDontSwapCtrlAndMeta is enabled, then the order + // is Ctrl, Alt, Shift, Meta. The macSymbolForQtKey does this swap + // for us, which means that we have to adjust our order here. + // The upshot is a lot more infrastructure to keep the number of + // if tests down and the code relatively clean. + static const int ModifierOrder[] = { Qt::META, Qt::ALT, Qt::SHIFT, Qt::CTRL, 0 }; + static const int QtKeyOrder[] = { Qt::Key_Meta, Qt::Key_Alt, Qt::Key_Shift, Qt::Key_Control, 0 }; + static const int DontSwapModifierOrder[] = { Qt::CTRL, Qt::ALT, Qt::SHIFT, Qt::META, 0 }; + static const int DontSwapQtKeyOrder[] = { Qt::Key_Control, Qt::Key_Alt, Qt::Key_Shift, Qt::Key_Meta, 0 }; + const int *modifierOrder; + const int *qtkeyOrder; + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + modifierOrder = DontSwapModifierOrder; + qtkeyOrder = DontSwapQtKeyOrder; + } else { + modifierOrder = ModifierOrder; + qtkeyOrder = QtKeyOrder; + } + + for (int i = 0; modifierOrder[i] != 0; ++i) { + if (key & modifierOrder[i]) + s += qt_macSymbolForQtKey(qtkeyOrder[i]); + } } else #endif { @@ -1140,7 +1204,7 @@ QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat int i=0; #if defined(Q_WS_MAC) if (nativeText) { - QChar ch = macSymbolForQtKey(key); + QChar ch = qt_macSymbolForQtKey(key); if (!ch.isNull()) p = ch; else diff --git a/src/gui/kernel/qkeysequence.h b/src/gui/kernel/qkeysequence.h index 1c4776f..f78e34a 100644 --- a/src/gui/kernel/qkeysequence.h +++ b/src/gui/kernel/qkeysequence.h @@ -136,7 +136,9 @@ public: DeleteEndOfLine, InsertParagraphSeparator, InsertLineSeparator, - SaveAs + SaveAs, + Preferences, + Quit }; QKeySequence(); diff --git a/src/gui/kernel/qlayout.cpp b/src/gui/kernel/qlayout.cpp index 1d5a70d..4463aab 100644 --- a/src/gui/kernel/qlayout.cpp +++ b/src/gui/kernel/qlayout.cpp @@ -1028,8 +1028,13 @@ void QLayout::freeze(int w, int h) void QLayout::setMenuBar(QWidget *widget) { Q_D(QLayout); - if (widget) - addChildWidget(widget); + +#ifdef Q_OS_WINCE_WM + if (widget && widget->size().height() > 0) +#else + if (widget) +#endif + addChildWidget(widget); d->menubar = widget; } diff --git a/src/gui/kernel/qlayoutengine.cpp b/src/gui/kernel/qlayoutengine.cpp index fbaa388..3673f08 100644 --- a/src/gui/kernel/qlayoutengine.cpp +++ b/src/gui/kernel/qlayoutengine.cpp @@ -329,7 +329,7 @@ void qGeomCalc(QVector<QLayoutStruct> &chain, int start, int count, qDebug() << "qGeomCalc" << "start" << start << "count" << count << "pos" << pos << "space" << space << "spacer" << spacer; for (i = start; i < start + count; ++i) { - qDebug() << i << ":" << chain[i].minimumSize << chain[i].smartSizeHint() + qDebug() << i << ':' << chain[i].minimumSize << chain[i].smartSizeHint() << chain[i].maximumSize << "stretch" << chain[i].stretch << "empty" << chain[i].empty << "expansive" << chain[i].expansive << "spacing" << chain[i].spacing; diff --git a/src/gui/kernel/qlayoutitem.cpp b/src/gui/kernel/qlayoutitem.cpp index 0fd73b8..c70ab2d 100644 --- a/src/gui/kernel/qlayoutitem.cpp +++ b/src/gui/kernel/qlayoutitem.cpp @@ -54,7 +54,8 @@ QT_BEGIN_NAMESPACE inline static QRect fromLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) { - return priv->fromOrToLayoutItemRect(rect, -1); + return rect.adjusted(priv->leftLayoutItemMargin, priv->topLayoutItemMargin, + -priv->rightLayoutItemMargin, -priv->bottomLayoutItemMargin); } inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size) @@ -64,7 +65,8 @@ inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size) inline static QRect toLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) { - return priv->fromOrToLayoutItemRect(rect, +1); + return rect.adjusted(-priv->leftLayoutItemMargin, -priv->topLayoutItemMargin, + priv->rightLayoutItemMargin, priv->bottomLayoutItemMargin); } inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size) diff --git a/src/gui/kernel/qmime_mac.cpp b/src/gui/kernel/qmime_mac.cpp index b2eeb5c..9cb8b61 100644 --- a/src/gui/kernel/qmime_mac.cpp +++ b/src/gui/kernel/qmime_mac.cpp @@ -218,7 +218,7 @@ QString QMacPasteboardMimeAny::flavorFor(const QString &mime) if(mime == QLatin1String("application/x-qt-mime-type-name")) return QString(); QString ret = QLatin1String("com.trolltech.anymime.") + mime; - return ret.replace(QLatin1String("/"), QLatin1String("--")); + return ret.replace(QLatin1Char('/'), QLatin1String("--")); } QString QMacPasteboardMimeAny::mimeFor(QString flav) @@ -394,7 +394,7 @@ QString QMacPasteboardMimeUnicodeText::flavorFor(const QString &mime) int i = mime.indexOf(QLatin1String("charset=")); if (i >= 0) { QString cs(mime.mid(i+8).toLower()); - i = cs.indexOf(QLatin1String(";")); + i = cs.indexOf(QLatin1Char(';')); if (i>=0) cs = cs.left(i); if (cs == QLatin1String("system")) diff --git a/src/gui/kernel/qmime_win.cpp b/src/gui/kernel/qmime_win.cpp index cd0aae6..ad2dec1 100644 --- a/src/gui/kernel/qmime_win.cpp +++ b/src/gui/kernel/qmime_win.cpp @@ -852,7 +852,7 @@ QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pData if (end > start && start > 0) { html = "<!--StartFragment-->" + html.mid(start, end - start); html += "<!--EndFragment-->"; - html.replace("\r", ""); + html.replace('\r', ""); result = QString::fromUtf8(html); } } @@ -1262,16 +1262,16 @@ QVector<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, con } return formatetcs; } -static const char *x_qt_windows_mime = "application/x-qt-windows-mime;value=\""; +static const char x_qt_windows_mime[] = "application/x-qt-windows-mime;value=\""; -bool isCustomMimeType(const QString &mimeType) +static bool isCustomMimeType(const QString &mimeType) { return mimeType.startsWith(QLatin1String(x_qt_windows_mime), Qt::CaseInsensitive); } -QString customMimeType(const QString &mimeType) +static QString customMimeType(const QString &mimeType) { - int len = QString(QLatin1String(x_qt_windows_mime)).length(); + int len = sizeof(x_qt_windows_mime) - 1; int n = mimeType.lastIndexOf(QLatin1Char('\"'))-len; return mimeType.mid(len, n); } diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index b6703e2..3c2fcdd 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -109,7 +109,7 @@ QDebug &operator<<(QDebug &dbg, const QShortcutEntry *se) { dbg.nospace() << "QShortcutEntry(" << se->keyseq << "), id(" << se->id << "), enabled(" << se->enabled << "), autorepeat(" << se->autorepeat - << "), owner(" << se->owner << ")"; + << "), owner(" << se->owner << ')'; return dbg.space(); } #endif // QT_NO_DEBUGSTREAM @@ -751,6 +751,7 @@ bool QShortcutMap::correctGraphicsWidgetContext(Qt::ShortcutContext context, QGr tw = tw->parentWidget(); return tw == w; } + return false; } // Below is Qt::WindowShortcut context @@ -875,7 +876,7 @@ void QShortcutMap::dispatchEvent(QKeyEvent *e) qDebug().nospace() << "QShortcutMap::dispatchEvent(): Sending QShortcutEvent(\"" << (QString)next->keyseq << "\", " << next->id << ", " - << (bool)(enabledShortcuts>1) << ") to object(" << next->owner << ")"; + << (bool)(enabledShortcuts>1) << ") to object(" << next->owner << ')'; #endif QShortcutEvent se(next->keyseq, next->id, enabledShortcuts>1); QApplication::sendEvent(const_cast<QObject *>(next->owner), &se); diff --git a/src/gui/kernel/qsound_qws.cpp b/src/gui/kernel/qsound_qws.cpp index e83935f..661544f 100644 --- a/src/gui/kernel/qsound_qws.cpp +++ b/src/gui/kernel/qsound_qws.cpp @@ -279,7 +279,7 @@ QAuBucketQWS::QAuBucketQWS( QAuServerQWS *server, QSound *sound, QObject* parent sound->setObjectName( m_id.toString() ); - m_channel = new QCopChannel(QString( QLatin1String("QPE/QSound/") ).append( m_id ), this ); + m_channel = new QCopChannel(QLatin1String("QPE/QSound/") + m_id ), this ); connect( m_channel, SIGNAL(received(QString,QByteArray)), this, SLOT(processMessage(QString,QByteArray)) ); diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm index f000292..9165836 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac.mm +++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm @@ -826,13 +826,28 @@ bool qt_mac_handleMouseEvent(void * /* NSView * */view, void * /* NSEvent * */ev QWidget *qwidget = [theView qt_qwidget]; QWidget *widgetToGetMouse = qwidget; QWidget *popup = qAppInstance()->activePopupWidget(); - if (popup && popup != qwidget->window()) - widgetToGetMouse = popup; NSView *tmpView = theView; - if (widgetToGetMouse != qwidget) { - tmpView = qt_mac_nativeview_for(widgetToGetMouse); + + if (popup && popup != qwidget->window()) { + widgetToGetMouse = popup; + tmpView = qt_mac_nativeview_for(popup); windowPoint = [[tmpView window] convertScreenToBase:globalPoint]; + + QPoint qWindowPoint(windowPoint.x, windowPoint.y); + if (widgetToGetMouse->rect().contains(qWindowPoint)) { + // Keeping the mouse pressed on a combobox button will make + // the popup pop in front of the mouse. But all mouse events + // will be sendt to the button. Since we want mouse events + // to be sendt to widgets inside the popup, we search for the + // widget in front of the mouse: + tmpView = [tmpView hitTest:windowPoint]; + if (!tmpView) + return false; + widgetToGetMouse = + [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(tmpView) qt_qwidget]; + } } + NSPoint localPoint = [tmpView convertPoint:windowPoint fromView:nil]; QPoint qlocalPoint(localPoint.x, localPoint.y); diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index dd95053..5538c11 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -167,39 +167,48 @@ static inline bool bypassGraphicsProxyWidget(QWidget *p) extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // qapplication.cpp extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp -QWidgetPrivate::QWidgetPrivate(int version) : - QObjectPrivate(version), extra(0), focus_child(0) - ,layout(0), widgetItem(0) - ,leftmargin(0), topmargin(0), rightmargin(0), bottommargin(0) - ,leftLayoutItemMargin(0), topLayoutItemMargin(0), rightLayoutItemMargin(0) - ,bottomLayoutItemMargin(0) - ,fg_role(QPalette::NoRole) - ,bg_role(QPalette::NoRole) - ,hd(0) - ,dirty(0) - ,needsFlush(0) - ,dirtyOpaqueChildren(1) - ,isOpaque(0) - ,inDirtyList(0) - ,isScrolled(0) - ,isMoved(0) - ,usesDoubleBufferedGLContext(0) -#ifdef Q_WS_WIN - ,noPaintOnScreen(0) -#endif - ,inheritedFontResolveMask(0) - ,inheritedPaletteResolveMask(0) +QWidgetPrivate::QWidgetPrivate(int version) + : QObjectPrivate(version) + , extra(0) + , focus_next(0) + , focus_prev(0) + , focus_child(0) + , layout(0) + , needsFlush(0) + , redirectDev(0) + , widgetItem(0) + , extraPaintEngine(0) + , polished(0) + , inheritedFontResolveMask(0) + , inheritedPaletteResolveMask(0) + , leftmargin(0) + , topmargin(0) + , rightmargin(0) + , bottommargin(0) + , leftLayoutItemMargin(0) + , topLayoutItemMargin(0) + , rightLayoutItemMargin(0) + , bottomLayoutItemMargin(0) + , hd(0) + , size_policy(QSizePolicy::Preferred, QSizePolicy::Preferred) + , fg_role(QPalette::NoRole) + , bg_role(QPalette::NoRole) + , dirtyOpaqueChildren(1) + , isOpaque(0) + , inDirtyList(0) + , isScrolled(0) + , isMoved(0) + , usesDoubleBufferedGLContext(0) #if defined(Q_WS_X11) - ,picture(0) -#endif -#ifdef Q_WS_MAC - ,needWindowChange(0) - ,isGLWidget(0) + , picture(0) +#elif defined(Q_WS_WIN) + , noPaintOnScreen(0) +#elif defined(Q_WS_MAC) + , needWindowChange(0) + , isGLWidget(0) + , window_event(0) + , qd_hd(0) #endif - ,polished(0) - - , size_policy(QSizePolicy::Preferred, QSizePolicy::Preferred) - , redirectDev(0) { if (!qApp) { qFatal("QWidget: Must construct a QApplication before a QPaintDevice"); @@ -1345,7 +1354,7 @@ QWidget::~QWidget() d->setDirtyOpaqueRegion(); if (isWindow() && isVisible() && internalWinId()) - hide(); + d->close_helper(QWidgetPrivate::CloseNoEvent); #if defined(Q_WS_WIN) || defined(Q_WS_X11) else if (!internalWinId() && isVisible()) qApp->d_func()->sendSyntheticEnterLeave(this); @@ -1412,36 +1421,26 @@ void QWidgetPrivate::createTLExtra() createExtra(); if (!extra->topextra) { QTLWExtra* x = extra->topextra = new QTLWExtra; + x->icon = 0; + x->iconPixmap = 0; + x->backingStore = 0; x->windowSurface = 0; + x->sharedPainter = 0; + x->incw = x->inch = 0; + x->basew = x->baseh = 0; + x->frameStrut.setCoords(0, 0, 0, 0); + x->normalGeometry = QRect(0,0,-1,-1); + x->savedFlags = 0; x->opacity = 255; x->posFromMove = false; x->sizeAdjusted = false; x->inTopLevelResize = false; x->inRepaint = false; - x->backingStore = 0; - x->icon = 0; - x->iconPixmap = 0; - x->frameStrut.setCoords(0, 0, 0, 0); - x->incw = x->inch = 0; - x->basew = x->baseh = 0; - x->normalGeometry = QRect(0,0,-1,-1); -#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_MAC) x->embedded = 0; -#endif -#if defined(Q_WS_X11) - x->parentWinId = 0; - x->spont_unmapped = 0; - x->dnd = 0; -#endif - x->savedFlags = 0; -#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) - x->qwsManager = 0; -#endif - x->sharedPainter = 0; createTLSysExtra(); #ifdef QWIDGET_EXTRA_DEBUG - static int count = 0; - qDebug() << "tlextra" << ++count; + static int count = 0; + qDebug() << "tlextra" << ++count; #endif } } @@ -1455,27 +1454,28 @@ void QWidgetPrivate::createExtra() { if (!extra) { // if not exists extra = new QWExtra; - extra->minw = extra->minh = 0; - extra->maxw = extra->maxh = QWIDGETSIZE_MAX; + extra->glContext = 0; + extra->topextra = 0; + extra->proxyWidget = 0; +#ifndef QT_NO_CURSOR + extra->curs = 0; +#endif + extra->minw = 0; + extra->minh = 0; + extra->maxw = QWIDGETSIZE_MAX; + extra->maxh = QWIDGETSIZE_MAX; + extra->customDpiX = 0; + extra->customDpiY = 0; extra->explicitMinSize = 0; extra->explicitMaxSize = 0; extra->autoFillBackground = 0; extra->nativeChildrenForced = 0; extra->inRenderWithPainter = 0; extra->hasMask = 0; -#ifndef QT_NO_CURSOR - extra->curs = 0; -#endif - extra->style = 0; - extra->topextra = 0; - extra->proxyWidget = 0; - extra->glContext = 0; - extra->customDpiX = 0; - extra->customDpiY = 0; createSysExtra(); #ifdef QWIDGET_EXTRA_DEBUG - static int count = 0; - qDebug() << "extra" << ++count; + static int count = 0; + qDebug() << "extra" << ++count; #endif } } @@ -1516,45 +1516,6 @@ void QWidgetPrivate::deleteExtra() } /* - Returns true if the background is inherited; otherwise returns - false. - - Mainly used in the paintOnScreen case. -*/ - -bool QWidgetPrivate::isBackgroundInherited() const -{ - Q_Q(const QWidget); - - // windows do not inherit their background - if (q->isWindow() || q->windowType() == Qt::SubWindow) - return false; - - if (q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_OpaquePaintEvent)) - return false; - - const QPalette &pal = q->palette(); - QPalette::ColorRole bg = q->backgroundRole(); - QBrush brush = pal.brush(bg); - - // non opaque brushes leaves us no choice, we must inherit - if (!q->autoFillBackground() || !brush.isOpaque()) - return true; - - if (brush.style() == Qt::SolidPattern) { - // the background is just a solid color. If there is no - // propagated contents, then we claim as performance - // optimization that it was not inheritet. This is the normal - // case in standard Windows or Motif style. - const QWidget *w = q->parentWidget(); - if (!w->d_func()->isBackgroundInherited()) - return false; - } - - return true; -} - -/* Returns true if there are widgets above this which overlap with \a rect, which is in parent's coordinate system (same as crect). */ @@ -1900,24 +1861,6 @@ void QWidgetPrivate::clipToEffectiveMask(QRegion ®ion) const } } -bool QWidgetPrivate::hasBackground() const -{ - Q_Q(const QWidget); - if (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_PaintOnScreen)) - return true; - if (q->testAttribute(Qt::WA_PaintOnScreen)) - return true; - if (!q->testAttribute(Qt::WA_OpaquePaintEvent) && !q->testAttribute(Qt::WA_NoSystemBackground)) { - const QPalette &pal = q->palette(); - QPalette::ColorRole bg = q->backgroundRole(); - QBrush bgBrush = pal.brush(bg); - return (bgBrush.style() != Qt::NoBrush && - ((q->isWindow() || q->windowType() == Qt::SubWindow) - || (QPalette::ColorRole(bg_role) != QPalette::NoRole || (pal.resolve() & (1<<bg))))); - } - return false; -} - bool QWidgetPrivate::paintOnScreen() const { #if defined(Q_WS_QWS) @@ -2343,13 +2286,26 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool ) { Q_Q(QWidget); - createExtra(); - QStyle *oldStyle = q->style(); #ifndef QT_NO_STYLE_STYLESHEET - QStyle *origStyle = extra->style; + QStyle *origStyle = 0; +#endif + +#ifdef Q_WS_MAC + // the metalhack boolean allows Qt/Mac to do a proper re-polish depending + // on how the Qt::WA_MacBrushedMetal attribute is set. It is only ever + // set when changing that attribute and passes the widget's CURRENT style. + // therefore no need to do a reassignment. + if (!metalHack) +#endif + { + createExtra(); + +#ifndef QT_NO_STYLE_STYLESHEET + origStyle = extra->style; #endif - extra->style = newStyle; + extra->style = newStyle; + } // repolish if (q->windowType() != Qt::Desktop) { @@ -4810,7 +4766,7 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, Q_ASSERT(engine); QPaintEnginePrivate *enginePriv = engine->d_func(); Q_ASSERT(enginePriv); - QPaintDevice *target = painter->worldMatrixEnabled() ? engine->paintDevice() : painter->device(); + QPaintDevice *target = engine->paintDevice(); Q_ASSERT(target); // Render via a pixmap when dealing with non-opaque painters or printers. @@ -5280,7 +5236,7 @@ static QString constructWindowTitleFromFilePath(const QString &filePath) #ifndef Q_WS_MAC QString appName = QApplication::applicationName(); if (!appName.isEmpty()) - windowTitle += QLatin1String(" ") + QChar(0x2014) + QLatin1String(" ") + appName; + windowTitle += QLatin1Char(' ') + QChar(0x2014) + QLatin1Char(' ') + appName; #endif return windowTitle; } @@ -5344,7 +5300,7 @@ QString qt_setWindowTitle_helperHelper(const QString &title, const QWidget *widg && widget->style()->styleHint(QStyle::SH_TitleBar_ModifyNotification, 0, widget)) cap.replace(lastIndex, 3, QWidget::tr("*")); else - cap.replace(lastIndex, 3, QLatin1String("")); + cap.remove(lastIndex, 3); } index = cap.indexOf(placeHolder, index); @@ -6157,14 +6113,6 @@ int QWidgetPrivate::pointToRect(const QPoint &p, const QRect &r) return dx + dy; } -QRect QWidgetPrivate::fromOrToLayoutItemRect(const QRect &rect, int sign) const -{ - QRect r = rect; - r.adjust(-sign * leftLayoutItemMargin, -sign * topLayoutItemMargin, - +sign * rightLayoutItemMargin, +sign * bottomLayoutItemMargin); - return r; -} - /*! \property QWidget::frameSize \brief the size of the widget including any window frame @@ -6288,7 +6236,7 @@ QByteArray QWidget::saveGeometry() const returns false. If the restored geometry is off-screen, it will be modified to be - inside the the available screen geometry. + inside the available screen geometry. To restore geometry saved using QSettings, you can use code like this: @@ -9255,11 +9203,12 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) d->resolveLayoutDirection(); d->resolveLocale(); - // Note: GL widgets under Windows will always need a ParentChange - // event to handle recreation/rebinding of the GL context, hence - // the (f & Qt::MSWindowsOwnDC) clause + // Note: GL widgets under WGL or EGL will always need a ParentChange + // event to handle recreation/rebinding of the GL context, hence the + // (f & Qt::MSWindowsOwnDC) clause (which is set on QGLWidgets on all + // platforms). if (newParent -#ifdef Q_WS_WIN +#if defined(Q_WS_WIN) || defined(QT_OPENGL_ES) || (f & Qt::MSWindowsOwnDC) #endif ) { @@ -11420,3 +11369,17 @@ void QWidget::clearMask() setMask(QRegion()); } +/*! \fn const QX11Info &QWidget::x11Info() const + Returns information about the configuration of the X display used to display + the widget. + + \warning This function is only available on X11. +*/ + +/*! \fn Qt::HANDLE QWidget::x11PictureHandle() const + Returns the X11 Picture handle of the widget for XRender + support. Use of this function is not portable. This function will + return 0 if XRender support is not compiled into Qt, if the + XRender extension is not supported on the X11 display, or if the + handle could not be created. +*/ diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 9da0b6b..8243f32 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -728,6 +728,7 @@ static OSWindowRef qt_mac_create_window(QWidget *, WindowClass wclass, WindowAtt static EventTypeSpec window_events[] = { { kEventClassWindow, kEventWindowClose }, { kEventClassWindow, kEventWindowExpanded }, + { kEventClassWindow, kEventWindowHidden }, { kEventClassWindow, kEventWindowZoomed }, { kEventClassWindow, kEventWindowCollapsed }, { kEventClassWindow, kEventWindowToolbarSwitchMode }, @@ -780,16 +781,6 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, // By also setting the current modal window back into the event, we // help Carbon determining which window is supposed to be raised. handled_event = qApp->activePopupWidget() ? true : false; - QWidget *top = 0; - if (!QApplicationPrivate::tryModalHelper(widget, &top) && top && top != widget){ - if(!qt_mac_is_macsheet(top) || top->parentWidget() != widget) { - handled_event = true; - WindowPtr topWindowRef = qt_mac_window_for(top); - SetEventParameter(event, kEventParamModalWindow, typeWindowRef, sizeof(topWindowRef), &topWindowRef); - HIModalClickResult clickResult = kHIModalClickIsModal; - SetEventParameter(event, kEventParamModalClickResult, typeModalClickResult, sizeof(clickResult), &clickResult); - } - } #endif } else if(ekind == kEventWindowClose) { widget->d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent); @@ -997,6 +988,19 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, } } } + } else if (ekind == kEventWindowHidden) { + // Make sure that we also hide any visible sheets on our window. + // Cocoa does the right thing for us. + const QObjectList children = widget->children(); + const int childCount = children.count(); + for (int i = 0; i < childCount; ++i) { + QObject *obj = children.at(i); + if (obj->isWidgetType()) { + QWidget *widget = static_cast<QWidget *>(obj); + if (qt_mac_is_macsheet(widget) && widget->isVisible()) + widget->hide(); + } + } } else { handled_event = false; } @@ -1599,24 +1603,6 @@ bool QWidgetPrivate::qt_create_root_win() return true; } -bool QWidgetPrivate::qt_recreate_root_win() -{ - if(!qt_root_win) //sanity check - return false; - //store old - OSWindowRef old_root_win = qt_root_win; - //recreate - qt_root_win = 0; - qt_create_root_win(); - //cleanup old window -#ifdef QT_MAC_USE_COCOA - [old_root_win release]; -#else - CFRelease(old_root_win); -#endif - return true; -} - bool QWidgetPrivate::qt_widget_rgn(QWidget *widget, short wcode, RgnHandle rgn, bool force = false) { bool ret = false; @@ -4039,8 +4025,8 @@ void QWidgetPrivate::applyMaxAndMinSizeOnWindow() NSSize max = NSMakeSize(SF(extra->maxw), SF(extra->maxh)); NSSize min = NSMakeSize(SF(extra->minw), SF(extra->minh)); #undef SF - [qt_mac_window_for(q) setMinSize:min]; - [qt_mac_window_for(q) setMaxSize:max]; + [qt_mac_window_for(q) setContentMinSize:min]; + [qt_mac_window_for(q) setContentMaxSize:max]; #endif } @@ -4438,11 +4424,13 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { + extra->topextra->resizer = 0; + extra->topextra->isSetGeometry = 0; + extra->topextra->isMove = 0; + extra->topextra->wattr = 0; extra->topextra->wclass = 0; extra->topextra->group = 0; extra->topextra->windowIcon = 0; - extra->topextra->resizer = 0; - extra->topextra->isSetGeometry = 0; extra->topextra->savedWindowAttributesFromMaximized = 0; } @@ -4491,8 +4479,8 @@ void QWidgetPrivate::registerDropSite(bool on) SetControlDragTrackingEnabled(qt_mac_nativeview_for(q), on); #else NSView *view = qt_mac_nativeview_for(q); - if ([view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) { - [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view) registerDragTypes:on]; + if (on && [view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) { + [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view) registerDragTypes]; } #endif } diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 8c6a234..bf4f091 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -99,88 +99,92 @@ class QWidgetItemV2; class QStyle; struct QTLWExtra { + // *************************** Cross-platform variables ***************************** + + // Regular pointers (keep them together to avoid gaps on 64 bits architectures). + QIcon *icon; // widget icon + QPixmap *iconPixmap; + QWidgetBackingStore *backingStore; + QWindowSurface *windowSurface; + QPainter *sharedPainter; + + // Implicit pointers (shared_null). QString caption; // widget caption QString iconText; // widget icon text QString role; // widget role QString filePath; // widget file path - QIcon *icon; // widget icon - QPixmap *iconPixmap; + + // Other variables. short incw, inch; // size increments + short basew, baseh; // base sizes // frame strut, don't use these directly, use QWidgetPrivate::frameStrut() instead. QRect frameStrut; + QRect normalGeometry; // used by showMin/maximized/FullScreen + Qt::WindowFlags savedFlags; // Save widget flags while showing fullscreen + + // *************************** Cross-platform bit fields **************************** uint opacity : 8; uint posFromMove : 1; uint sizeAdjusted : 1; uint inTopLevelResize : 1; uint inRepaint : 1; - QWidgetBackingStore *backingStore; -#if defined(Q_WS_WIN) - ulong savedFlags; // Save window flags while showing fullscreen - uint embedded : 1; // window is embedded in another application -#else - Qt::WindowFlags savedFlags; // Save widget flags while showing fullscreen -#endif - short basew, baseh; // base sizes -#if defined(Q_WS_X11) - WId parentWinId; // parent window Id (valid after reparenting) - uint embedded : 1; // window is embedded in another Qt application + uint embedded : 1; + + // *************************** Platform specific values (bit fields first) ********** +#if defined(Q_WS_X11) // <----------------------------------------------------------- X11 uint spont_unmapped: 1; // window was spontaneously unmapped uint dnd : 1; // DND properties installed uint validWMState : 1; // is WM_STATE valid? uint waitingForMapNotify : 1; // show() has been called, haven't got the MapNotify yet + WId parentWinId; // parent window Id (valid after reparenting) WId userTimeWindow; // window id that contains user-time timestamp when WM supports a _NET_WM_USER_TIME_WINDOW atom QPoint fullScreenOffset; -#endif -#if defined(Q_WS_MAC) +#elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN + HICON winIconBig; // internal big Windows icon + HICON winIconSmall; // internal small Windows icon +#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC + uint resizer : 4; + uint isSetGeometry : 1; + uint isMove : 1; quint32 wattr; quint32 wclass; WindowGroupRef group; IconRef windowIcon; // the current window icon, if set with setWindowIcon_sys. quint32 savedWindowAttributesFromMaximized; // Saved attributes from when the calling updateMaximizeButton_sys() - uint resizer : 4; - uint isSetGeometry : 1; - uint isMove : 1; - uint embedded : 1; -#endif -#if defined(Q_WS_QWS) && !defined (QT_NO_QWS_MANAGER) +#elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS +#ifndef QT_NO_QWS_MANAGER QWSManager *qwsManager; #endif -#if defined(Q_WS_WIN) - HICON winIconBig; // internal big Windows icon - HICON winIconSmall; // internal small Windows icon #endif - QRect normalGeometry; // used by showMin/maximized/FullScreen - QWindowSurface *windowSurface; - QPainter *sharedPainter; }; struct QWExtra { - qint32 minw, minh; // minimum size - qint32 maxw, maxh; // maximum size - QPointer<QWidget> focus_proxy; -#ifndef QT_NO_CURSOR - QCursor *curs; -#endif + // *************************** Cross-platform variables ***************************** + + // Regular pointers (keep them together to avoid gaps on 64 bits architectures). + void *glContext; // if the widget is hijacked by QGLWindowSurface QTLWExtra *topextra; // only useful for TLWs QGraphicsProxyWidget *proxyWidget; // if the widget is embedded - void *glContext; // if the widget is hijacked by QGLWindowSurface -#if defined(Q_WS_WIN) && !defined(QT_NO_DRAGANDDROP) - QOleDropTarget *dropTarget; // drop target - QList<QPointer<QWidget> > oleDropWidgets; -#endif -#if defined(Q_WS_X11) - WId xDndProxy; // XDND forwarding to embedded windows +#ifndef QT_NO_CURSOR + QCursor *curs; #endif + QPointer<QStyle> style; + QPointer<QWidget> focus_proxy; + + // Implicit pointers (shared_empty/shared_null). QRegion mask; // widget mask + QString styleSheet; + + // Other variables. + qint32 minw; + qint32 minh; // minimum size + qint32 maxw; + qint32 maxh; // maximum size + quint16 customDpiX; + quint16 customDpiY; QSize staticContentsSize; -//bit flags at the end to improve packing -#if defined(Q_WS_WIN) - uint shown_mode : 8; // widget show mode -#endif -#if defined(Q_WS_X11) - uint compress_events : 1; -#endif + // *************************** Cross-platform bit fields **************************** uint explicitMinSize : 2; uint explicitMaxSize : 2; uint autoFillBackground : 1; @@ -188,16 +192,22 @@ struct QWExtra { uint inRenderWithPainter : 1; uint hasMask : 1; - QPointer<QStyle> style; - QString styleSheet; - - quint16 customDpiX; - quint16 customDpiY; -#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + // *************************** Platform specific values (bit fields first) ********** +#if defined(Q_WS_WIN) // <----------------------------------------------------------- WIN +#ifndef QT_NO_DRAGANDDROP + QOleDropTarget *dropTarget; // drop target + QList<QPointer<QWidget> > oleDropWidgets; +#endif +#elif defined(Q_WS_X11) // <--------------------------------------------------------- X11 + uint compress_events : 1; + WId xDndProxy; // XDND forwarding to embedded windows +#elif defined(Q_WS_MAC) // <------------------------------------------------------ MAC +#ifdef QT_MAC_USE_COCOA // Cocoa Mask stuff QImage maskBits; CGImageRef imageMask; #endif +#endif }; class Q_GUI_EXPORT QWidgetPrivate : public QObjectPrivate @@ -205,6 +215,24 @@ class Q_GUI_EXPORT QWidgetPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QWidget) public: + // *************************** Cross-platform *************************************** + enum DrawWidgetFlags { + DrawAsRoot = 0x01, + DrawPaintOnScreen = 0x02, + DrawRecursive = 0x04, + DrawInvisible = 0x08, + DontSubtractOpaqueChildren = 0x10, + DontSetCompositionMode = 0x20, + DontDrawOpaqueChildren = 0x40 + }; + + enum CloseMode { + CloseNoEvent, + CloseWithEvent, + CloseWithSpontaneousEvent + }; + + // Functions. explicit QWidgetPrivate(int version = QObjectPrivateVersion); ~QWidgetPrivate(); @@ -214,10 +242,6 @@ public: QPainter *sharedPainter() const; void setSharedPainter(QPainter *painter); QWidgetBackingStore *maybeBackingStore() const; -#ifdef Q_WS_QWS - void setMaxWindowState_helper(); - void setFullScreenSize_helper(); -#endif void init(QWidget *desktopWidget, Qt::WindowFlags f); void create_sys(WId window, bool initializeWindow, bool destroyOldWindow); void createRecursively(); @@ -238,24 +262,6 @@ public: QPalette naturalWidgetPalette(uint inheritedMask) const; void setMask_sys(const QRegion &); -#ifdef Q_WS_WIN - bool shouldShowMaximizeButton(); - void winUpdateIsOpaque(); -#endif - -#ifdef Q_WS_MAC - void macUpdateSizeAttribute(); - void macUpdateHideOnSuspend(); - void macUpdateOpaqueSizeGrip(); - void macUpdateIgnoreMouseEvents(); - void macUpdateMetalAttribute(); - void macUpdateIsOpaque(); - void setEnabled_helper_sys(bool enable); - bool isRealWindow() const; - void adjustWithinMaxAndMinSize(int &w, int &h); - void applyMaxAndMinSizeOnWindow(); -#endif - void raise_sys(); void lower_sys(); void stackUnder_sys(QWidget *); @@ -280,20 +286,9 @@ public: void setStyle_helper(QStyle *newStyle, bool propagate, bool metalHack = false); void inheritStyle(); - bool isBackgroundInherited() const; - void setUpdatesEnabled_helper(bool ); void paintBackground(QPainter *, const QRegion &, const QPoint & = QPoint(), int flags = DrawAsRoot) const; - enum DrawWidgetFlags { - DrawAsRoot = 0x01, - DrawPaintOnScreen = 0x02, - DrawRecursive = 0x04, - DrawInvisible = 0x08, - DontSubtractOpaqueChildren = 0x10, - DontSetCompositionMode = 0x20, - DontDrawOpaqueChildren = 0x40 - }; bool isAboutToShow() const; QRegion prepareToRender(const QRegion ®ion, QWidget::RenderFlags renderFlags); void render_helper(QPainter *painter, const QPoint &targetOffset, const QRegion &sourceRegion, @@ -316,10 +311,6 @@ public: QWindowSurface *createDefaultWindowSurface(); QWindowSurface *createDefaultWindowSurface_sys(); void repaint_sys(const QRegion &rgn); -#ifdef Q_WS_MAC - void update_sys(const QRect &rect); - void update_sys(const QRegion &rgn); -#endif QRect clipRect() const; QRegion clipRegion() const; @@ -330,42 +321,20 @@ public: void updateIsOpaque(); void setOpaque(bool opaque); void updateIsTranslucent(); - bool hasBackground() const; bool paintOnScreen() const; QRegion getOpaqueRegion() const; const QRegion &getOpaqueChildren() const; void setDirtyOpaqueRegion(); - QRegion opaqueChildren; - - enum CloseMode { - CloseNoEvent, - CloseWithEvent, - CloseWithSpontaneousEvent - }; bool close_helper(CloseMode mode); - bool compositeEvent(QEvent *e); void setWindowIcon_helper(); void setWindowIcon_sys(bool forceReset = false); void setWindowOpacity_sys(qreal opacity); - void adjustQuitOnCloseAttribute(); -#if defined(Q_WS_X11) - void setWindowRole(); - void sendStartupMessage(const char *message) const; - void setNetWmWindowTypes(); - void x11UpdateIsOpaque(); -#endif - -#if defined (Q_WS_WIN) - void reparentChildren(); -#endif - void scrollChildren(int dx, int dy); - void moveRect(const QRect &, int dx, int dy); void scrollRect(const QRect &, int dx, int dy); void invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize); @@ -379,7 +348,6 @@ public: void reparentFocusWidgets(QWidget *oldtlw); static int pointToRect(const QPoint &p, const QRect &r); - QRect fromOrToLayoutItemRect(const QRect &rect, int sign) const; void setWinId(WId); void showChildren(bool spontaneous); @@ -389,9 +357,6 @@ public: void scroll_sys(int dx, int dy, const QRect &r); void deactivateWidgetCleanup(); void setGeometry_sys(int, int, int, int, bool); -#ifdef Q_WS_MAC - void setGeometry_sys_helper(int, int, int, int, bool); -#endif void sendPendingMoveAndResizeEvents(bool recursive = false, bool disableUpdates = false); void activateChildLayoutsRecursively(); void show_recursive(); @@ -403,10 +368,6 @@ public: void setEnabled_helper(bool); void registerDropSite(bool); -#if defined(Q_WS_WIN) && !defined(QT_NO_DRAGANDDROP) - QOleDropTarget *registerOleDnd(QWidget *widget); - void unregisterOleDnd(QWidget *widget, QOleDropTarget *target); -#endif static void adjustFlags(Qt::WindowFlags &flags, QWidget *w = 0); void updateFrameStrut(); @@ -416,32 +377,11 @@ public: void setWindowIconText_helper(const QString &cap); void setWindowTitle_sys(const QString &cap); -#ifdef Q_OS_WIN - void grabMouseWhileInWindow(); -#endif - #ifndef QT_NO_CURSOR void setCursor_sys(const QCursor &cursor); void unsetCursor_sys(); #endif -#ifdef Q_WS_MAC - void setWindowModified_sys(bool b); - void updateMaximizeButton_sys(); - void setWindowFilePath_sys(const QString &filePath); - void createWindow_sys(); - void recreateMacWindow(); -#ifndef QT_MAC_USE_COCOA - void initWindowPtr(); - void finishCreateWindow_sys_Carbon(OSWindowRef windowRef); -#else - void finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ windowRef); - void syncCocoaMask(); - void finishCocoaMaskSetup(); -#endif - void determineWindowClass(); - void transferChildren(); -#endif void setWindowTitle_helper(const QString &cap); void setWindowFilePath_helper(const QString &filePath); @@ -457,59 +397,89 @@ public: QInputContext *inputContext() const; -#if defined(Q_WS_QWS) - void moveSurface(QWindowSurface *surface, const QPoint &offset); + void setModal_sys(); - QRegion localRequestedRegion() const; - QRegion localAllocatedRegion() const; + inline void setRedirected(QPaintDevice *replacement, const QPoint &offset) + { + Q_ASSERT(q_func()->testAttribute(Qt::WA_WState_InPaintEvent)); + redirectDev = replacement; + redirectOffset = offset; + } - void blitToScreen(const QRegion &globalrgn); -#ifndef QT_NO_CURSOR - void updateCursor() const; -#endif + inline QPaintDevice *redirected(QPoint *offset) const + { + if (offset) + *offset = redirectDev ? redirectOffset : QPoint(); + return redirectDev; + } - QScreen* getScreen() const; + inline void restoreRedirected() + { redirectDev = 0; } - friend class QWSManager; - friend class QWSManagerPrivate; - friend class QDecoration; -#endif + inline void enforceNativeChildren() + { + if (!extra) + createExtra(); - static int instanceCounter; // Current number of widget instances - static int maxInstances; // Maximum number of widget instances + if (extra->nativeChildrenForced) + return; + extra->nativeChildrenForced = 1; -#ifdef QT_KEYPAD_NAVIGATION - static QPointer<QWidget> editingWidget; -#endif + for (int i = 0; i < children.size(); ++i) { + if (QWidget *child = qobject_cast<QWidget *>(children.at(i))) + child->setAttribute(Qt::WA_NativeWindow); + } + } - QWidgetData data; + inline bool nativeChildrenForced() const + { + return extra ? extra->nativeChildrenForced : false; + } + + QSize adjustedSize() const; + +#ifndef Q_WS_QWS // Almost cross-platform :-) + void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect()); + + inline QPoint mapToWS(const QPoint &p) const + { return p - data.wrect.topLeft(); } + + inline QPoint mapFromWS(const QPoint &p) const + { return p + data.wrect.topLeft(); } + + inline QRect mapToWS(const QRect &r) const + { QRect rr(r); rr.translate(-data.wrect.topLeft()); return rr; } + + inline QRect mapFromWS(const QRect &r) const + { QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; } +#endif + // Variables. + // Regular pointers (keep them together to avoid gaps on 64 bit architectures). QWExtra *extra; QWidget *focus_next; QWidget *focus_prev; QWidget *focus_child; -#ifndef QT_NO_ACTION - QList<QAction*> actions; -#endif QLayout *layout; + QRegion *needsFlush; + QPaintDevice *redirectDev; QWidgetItemV2 *widgetItem; -#if !defined(QT_NO_IM) - QPointer<QInputContext> ic; -#endif + QPaintEngine *extraPaintEngine; + mutable const QMetaObject *polished; // All widgets are initially added into the uncreatedWidgets set. Once // they receive a window id they are removed and added to the mapper static QWidgetMapper *mapper; static QWidgetSet *uncreatedWidgets; +#if !defined(QT_NO_IM) + QPointer<QInputContext> ic; +#endif +#ifdef QT_KEYPAD_NAVIGATION + static QPointer<QWidget> editingWidget; +#endif - short leftmargin, topmargin, rightmargin, bottommargin; - - signed char leftLayoutItemMargin; - signed char topLayoutItemMargin; - signed char rightLayoutItemMargin; - signed char bottomLayoutItemMargin; - - // ### TODO: reorganize private/extra/topextra to save memory - QPointer<QWidget> compositeChildGrab; + // Implicit pointers (shared_null/shared_empty). + QRegion opaqueChildren; + QRegion dirty; #ifndef QT_NO_TOOLTIP QString toolTip; #endif @@ -519,14 +489,37 @@ public: #ifndef QT_NO_WHATSTHIS QString whatsThis; #endif - QString accessibleName, accessibleDescription; +#ifndef QT_NO_ACCESSIBILITY + QString accessibleName; + QString accessibleDescription; +#endif + + // Other variables. + uint inheritedFontResolveMask; + uint inheritedPaletteResolveMask; + short leftmargin; + short topmargin; + short rightmargin; + short bottommargin; + signed char leftLayoutItemMargin; + signed char topLayoutItemMargin; + signed char rightLayoutItemMargin; + signed char bottomLayoutItemMargin; + static int instanceCounter; // Current number of widget instances + static int maxInstances; // Maximum number of widget instances + Qt::HANDLE hd; + QWidgetData data; + QSizePolicy size_policy; + QLocale locale; + QPoint redirectOffset; +#ifndef QT_NO_ACTION + QList<QAction*> actions; +#endif + // Bit fields. + uint high_attributes[3]; // the low ones are in QWidget::widget_attributes QPalette::ColorRole fg_role : 8; QPalette::ColorRole bg_role : 8; - uint high_attributes[3]; // the low ones are in QWidget::widget_attributes - Qt::HANDLE hd; - QRegion dirty; - QRegion *needsFlush; uint dirtyOpaqueChildren : 1; uint isOpaque : 1; uint inDirtyList : 1; @@ -534,35 +527,33 @@ public: uint isMoved : 1; uint usesDoubleBufferedGLContext : 1; -#ifdef Q_WS_WIN - uint noPaintOnScreen : 1; // see qwidget_win.cpp ::paintEngine() -#endif - - uint inheritedFontResolveMask; - uint inheritedPaletteResolveMask; -#if defined(Q_WS_X11) + // *************************** Platform specific ************************************ +#if defined(Q_WS_X11) // <----------------------------------------------------------- X11 QX11Info xinfo; Qt::HANDLE picture; + static QWidget *mouseGrabber; + static QWidget *keyboardGrabber; + + void setWindowRole(); + void sendStartupMessage(const char *message) const; + void setNetWmWindowTypes(); + void x11UpdateIsOpaque(); + bool isBackgroundInherited() const; +#elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN + uint noPaintOnScreen : 1; // see qwidget_win.cpp ::paintEngine() + + bool shouldShowMaximizeButton(); + void winUpdateIsOpaque(); + void reparentChildren(); +#ifndef QT_NO_DRAGANDDROP + QOleDropTarget *registerOleDnd(QWidget *widget); + void unregisterOleDnd(QWidget *widget, QOleDropTarget *target); #endif -#if defined(Q_WS_MAC) - enum PaintChildrenOPs { - PC_None = 0x00, - PC_Now = 0x01, - PC_NoPaint = 0x04, - PC_Later = 0x10 - }; - EventHandlerRef window_event; - bool qt_mac_dnd_event(uint, DragRef); - void toggleDrawers(bool); - //mac event functions - static bool qt_create_root_win(); - static void qt_clean_root_win(); - static bool qt_recreate_root_win(); - static bool qt_mac_update_sizer(QWidget *, int up = 0); - static OSStatus qt_window_event(EventHandlerCallRef er, EventRef event, void *); - static OSStatus qt_widget_event(EventHandlerCallRef er, EventRef event, void *); - static bool qt_widget_rgn(QWidget *, short, RgnHandle, bool); - static bool qt_widget_shape(QWidget *, short, HIMutableShapeRef, bool); + void grabMouseWhileInWindow(); +#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC + // This is new stuff + uint needWindowChange : 1; + uint isGLWidget : 1; // Each wiget keeps a list of all its child and grandchild OpenGL widgets. // This list is used to update the gl context whenever a parent and a granparent @@ -575,95 +566,70 @@ public: QWidget * widget; QWidget * lastUpdateWidget; }; - QList<GlWidgetInfo> glWidgets; // dirtyOnWidget contains the areas in the widget that needs to be repained, // in the same way as dirtyOnScreen does for the window. Areas are added in // dirtyWidget_sys and cleared in the paint event. In scroll_sys we then use // this information repaint invalid areas when widgets are scrolled. QRegion dirtyOnWidget; + EventHandlerRef window_event; + QList<GlWidgetInfo> glWidgets; //these are here just for code compat (HIViews) Qt::HANDLE qd_hd; - // This is new stuff - uint needWindowChange : 1; - uint isGLWidget : 1; -#endif - -#if defined(Q_WS_X11) || defined (Q_WS_WIN) || defined(Q_WS_MAC) -#ifdef Q_WS_MAC - void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect()); + void macUpdateSizeAttribute(); + void macUpdateHideOnSuspend(); + void macUpdateOpaqueSizeGrip(); + void macUpdateIgnoreMouseEvents(); + void macUpdateMetalAttribute(); + void macUpdateIsOpaque(); + void setEnabled_helper_sys(bool enable); + bool isRealWindow() const; + void adjustWithinMaxAndMinSize(int &w, int &h); + void applyMaxAndMinSizeOnWindow(); + void update_sys(const QRect &rect); + void update_sys(const QRegion &rgn); + void setGeometry_sys_helper(int, int, int, int, bool); + void setWindowModified_sys(bool b); + void updateMaximizeButton_sys(); + void setWindowFilePath_sys(const QString &filePath); + void createWindow_sys(); + void recreateMacWindow(); +#ifndef QT_MAC_USE_COCOA + void initWindowPtr(); + void finishCreateWindow_sys_Carbon(OSWindowRef windowRef); #else - void setWSGeometry(bool dontShow=false); + void finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ windowRef); + void syncCocoaMask(); + void finishCocoaMaskSetup(); #endif + void determineWindowClass(); + void transferChildren(); + bool qt_mac_dnd_event(uint, DragRef); + void toggleDrawers(bool); + //mac event functions + static bool qt_create_root_win(); + static void qt_clean_root_win(); + static bool qt_mac_update_sizer(QWidget *, int up = 0); + static OSStatus qt_window_event(EventHandlerCallRef er, EventRef event, void *); + static OSStatus qt_widget_event(EventHandlerCallRef er, EventRef event, void *); + static bool qt_widget_rgn(QWidget *, short, RgnHandle, bool); +#elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS + void setMaxWindowState_helper(); + void setFullScreenSize_helper(); + void moveSurface(QWindowSurface *surface, const QPoint &offset); + QRegion localRequestedRegion() const; + QRegion localAllocatedRegion() const; - inline QPoint mapToWS(const QPoint &p) const - { return p - data.wrect.topLeft(); } - - inline QPoint mapFromWS(const QPoint &p) const - { return p + data.wrect.topLeft(); } - - inline QRect mapToWS(const QRect &r) const - { QRect rr(r); rr.translate(-data.wrect.topLeft()); return rr; } - - inline QRect mapFromWS(const QRect &r) const - { QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; } + friend class QWSManager; + friend class QWSManagerPrivate; + friend class QDecoration; +#ifndef QT_NO_CURSOR + void updateCursor() const; #endif - - QPaintEngine *extraPaintEngine; - - mutable const QMetaObject *polished; - - void setModal_sys(); - QSizePolicy size_policy; - QLocale locale; - -#ifdef Q_WS_X11 - static QWidget *mouseGrabber; - static QWidget *keyboardGrabber; + QScreen* getScreen() const; #endif - QPaintDevice *redirectDev; - QPoint redirectOffset; - - inline void setRedirected(QPaintDevice *replacement, const QPoint &offset) - { - Q_ASSERT(q_func()->testAttribute(Qt::WA_WState_InPaintEvent)); - redirectDev = replacement; - redirectOffset = offset; - } - - inline QPaintDevice *redirected(QPoint *offset) const - { - if (offset) - *offset = redirectDev ? redirectOffset : QPoint(); - return redirectDev; - } - - inline void restoreRedirected() - { redirectDev = 0; } - - inline void enforceNativeChildren() - { - if (!extra) - createExtra(); - - if (extra->nativeChildrenForced) - return; - extra->nativeChildrenForced = 1; - - for (int i = 0; i < children.size(); ++i) { - if (QWidget *child = qobject_cast<QWidget *>(children.at(i))) - child->setAttribute(Qt::WA_NativeWindow); - } - } - - inline bool nativeChildrenForced() const - { - return extra ? extra->nativeChildrenForced : false; - } - - QSize adjustedSize() const; }; inline QWExtra *QWidgetPrivate::extraData() const diff --git a/src/gui/kernel/qwidget_qws.cpp b/src/gui/kernel/qwidget_qws.cpp index 1445f57..94bdb85 100644 --- a/src/gui/kernel/qwidget_qws.cpp +++ b/src/gui/kernel/qwidget_qws.cpp @@ -565,20 +565,6 @@ void QWidget::activateWindow() } } -/* - Should we require that q is a toplevel window ??? - - Used by QWSManager - */ -void QWidgetPrivate::blitToScreen(const QRegion &globalrgn) -{ - Q_Q(QWidget); - QWidget *win = q->window(); - QBrush bgBrush = win->palette().brush(win->backgroundRole()); - bool opaque = bgBrush.style() == Qt::NoBrush || bgBrush.isOpaque(); - QWidget::qwsDisplay()->repaintRegion(win->data->winid, win->windowFlags(), opaque, globalrgn); -} - void QWidgetPrivate::show_sys() { Q_Q(QWidget); @@ -1037,6 +1023,9 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { +#ifndef QT_NO_QWS_MANAGER + extra->topextra->qwsManager = 0; +#endif } void QWidgetPrivate::deleteTLSysExtra() diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index cfdabaf..0f341fd 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -1025,13 +1025,13 @@ void QWidget::setWindowState(Qt::WindowStates newstate) if (newstate & Qt::WindowFullScreen) { if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized)) d->topData()->normalGeometry = geometry(); - d->topData()->savedFlags = GetWindowLongA(internalWinId(), GWL_STYLE); + d->topData()->savedFlags = Qt::WindowFlags(GetWindowLongA(internalWinId(), GWL_STYLE)); #ifndef Q_FLATTEN_EXPOSE UINT style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP; #else UINT style = WS_POPUP; #endif - if (d->topData()->savedFlags & WS_SYSMENU) + if (ulong(d->topData()->savedFlags) & WS_SYSMENU) style |= WS_SYSMENU; if (isVisible()) style |= WS_VISIBLE; @@ -1234,7 +1234,7 @@ void QWidgetPrivate::stackUnder_sys(QWidget* w) (In all comments below: s/X/Windows/g) */ -void QWidgetPrivate::setWSGeometry(bool dontShow) +void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); @@ -1704,7 +1704,6 @@ int QWidget::metric(PaintDeviceMetric m) const return val; } -#ifndef Q_WS_WINCE void QWidgetPrivate::createSysExtra() { #ifndef QT_NO_DRAGANDDROP @@ -1712,6 +1711,7 @@ void QWidgetPrivate::createSysExtra() #endif } +#ifndef Q_WS_WINCE void QWidgetPrivate::deleteSysExtra() { } @@ -1719,8 +1719,9 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { - extra->topextra->winIconSmall = 0; + extra->topextra->savedFlags = 0; extra->topextra->winIconBig = 0; + extra->topextra->winIconSmall = 0; } void QWidgetPrivate::deleteTLSysExtra() diff --git a/src/gui/kernel/qwidget_wince.cpp b/src/gui/kernel/qwidget_wince.cpp index cca928e..435fd31 100644 --- a/src/gui/kernel/qwidget_wince.cpp +++ b/src/gui/kernel/qwidget_wince.cpp @@ -535,7 +535,7 @@ void QWidget::setWindowState(Qt::WindowStates newstate) if (newstate & Qt::WindowFullScreen) { if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized)) d->topData()->normalGeometry = geometry(); - d->topData()->savedFlags = GetWindowLongA(internalWinId(), GWL_STYLE); + d->topData()->savedFlags = (Qt::WindowFlags) GetWindowLongA(internalWinId(), GWL_STYLE); UINT style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP; if (isVisible()) style |= WS_VISIBLE; @@ -598,13 +598,6 @@ void QWidget::setWindowState(Qt::WindowStates newstate) QApplication::sendEvent(this, &e); } - -void QWidgetPrivate::createSysExtra() { -#ifndef QT_NO_DRAGANDDROP - extra->dropTarget = 0; -#endif -} - void QWidgetPrivate::deleteSysExtra() { Q_Q(QWidget); diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp index 76734d4..7e41ea1 100644 --- a/src/gui/kernel/qwidget_x11.cpp +++ b/src/gui/kernel/qwidget_x11.cpp @@ -893,19 +893,70 @@ void QWidgetPrivate::x11UpdateIsOpaque() int screen = xinfo.screen(); if (topLevel && X11->use_xrender && X11->argbVisuals[screen] && xinfo.depth() != 32) { - // recreate widget - QPoint pos = q->pos(); - bool visible = q->isVisible(); - if (visible) - q->hide(); - q->setParent(q->parentWidget(), q->windowFlags()); - q->move(pos); - if (visible) - q->show(); + + if (q->inherits("QGLWidget")) { + // We send QGLWidgets a ParentChange event which causes them to + // recreate their GL context, which in turn causes them to choose + // their visual again. Now that WA_TranslucentBackground is set, + // QGLContext::chooseVisual will select an ARGB visual. + QEvent e(QEvent::ParentChange); + QApplication::sendEvent(q, &e); + } + else { + // For regular widgets, reparent them with their parent which + // also triggers a recreation of the native window + QPoint pos = q->pos(); + bool visible = q->isVisible(); + if (visible) + q->hide(); + + q->setParent(q->parentWidget(), q->windowFlags()); + q->move(pos); + if (visible) + q->show(); + } } #endif } +/* + Returns true if the background is inherited; otherwise returns + false. + + Mainly used in the paintOnScreen case. +*/ +bool QWidgetPrivate::isBackgroundInherited() const +{ + Q_Q(const QWidget); + + // windows do not inherit their background + if (q->isWindow() || q->windowType() == Qt::SubWindow) + return false; + + if (q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_OpaquePaintEvent)) + return false; + + const QPalette &pal = q->palette(); + QPalette::ColorRole bg = q->backgroundRole(); + QBrush brush = pal.brush(bg); + + // non opaque brushes leaves us no choice, we must inherit + if (!q->autoFillBackground() || !brush.isOpaque()) + return true; + + if (brush.style() == Qt::SolidPattern) { + // the background is just a solid color. If there is no + // propagated contents, then we claim as performance + // optimization that it was not inheritet. This is the normal + // case in standard Windows or Motif style. + const QWidget *w = q->parentWidget(); + if (!w->d_func()->isBackgroundInherited()) + return false; + } + + return true; +} + void QWidget::destroy(bool destroyWindow, bool destroySubWindows) { Q_D(QWidget); @@ -2152,7 +2203,7 @@ static void do_size_hints(QWidget* widget, QWExtra *x) parentWRect is the geometry of the parent's X rect, measured in parent's coord sys */ -void QWidgetPrivate::setWSGeometry(bool dontShow) +void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); @@ -2610,8 +2661,8 @@ int QWidget::metric(PaintDeviceMetric m) const void QWidgetPrivate::createSysExtra() { - extra->xDndProxy = 0; extra->compress_events = true; + extra->xDndProxy = 0; } void QWidgetPrivate::deleteSysExtra() @@ -2620,8 +2671,11 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { + extra->topextra->spont_unmapped = 0; + extra->topextra->dnd = 0; extra->topextra->validWMState = 0; extra->topextra->waitingForMapNotify = 0; + extra->topextra->parentWinId = 0; extra->topextra->userTimeWindow = 0; } @@ -2747,12 +2801,6 @@ void QWidgetPrivate::setWindowOpacity_sys(qreal opacity) 32, PropModeReplace, (uchar*)&value, 1); } -/*! - Returns information about the configuration of the X display used to display - the widget. - - \warning This function is only available on X11. -*/ const QX11Info &QWidget::x11Info() const { Q_D(const QWidget); @@ -2789,13 +2837,6 @@ QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys() return new QX11WindowSurface(q_func()); } -/*! - Returns the X11 Picture handle of the widget for XRender - support. Use of this function is not portable. This function will - return 0 if XRender support is not compiled into Qt, if the - XRender extension is not supported on the X11 display, or if the - handle could not be created. -*/ Qt::HANDLE QWidget::x11PictureHandle() const { #ifndef QT_NO_XRENDER diff --git a/src/gui/kernel/qwindowdefs_win.h b/src/gui/kernel/qwindowdefs_win.h index 3899c23..a24afd4 100644 --- a/src/gui/kernel/qwindowdefs_win.h +++ b/src/gui/kernel/qwindowdefs_win.h @@ -122,7 +122,7 @@ QT_BEGIN_NAMESPACE Q_CORE_EXPORT HINSTANCE qWinAppInst(); Q_CORE_EXPORT HINSTANCE qWinAppPrevInst(); -Q_GUI_EXPORT int qWinAppCmdShow(); +Q_CORE_EXPORT int qWinAppCmdShow(); Q_GUI_EXPORT HDC qt_win_display_dc(); QT_END_NAMESPACE diff --git a/src/gui/kernel/qx11embed_x11.cpp b/src/gui/kernel/qx11embed_x11.cpp index 6329135..ae93efe 100644 --- a/src/gui/kernel/qx11embed_x11.cpp +++ b/src/gui/kernel/qx11embed_x11.cpp @@ -1297,9 +1297,6 @@ bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event) // focus is set to our focus proxy. We want to intercept all // keypresses. if (o == window() && d->client) { - if (!d->isEmbedded() && d->activeContainer == this) - d->moveInputToProxy(); - if (d->clientIsXEmbed) { sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_ACTIVATE); } else { @@ -1307,6 +1304,8 @@ bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event) if (hasFocus()) XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time()); } + if (!d->isEmbedded()) + d->moveInputToProxy(); } break; case QEvent::WindowDeactivate: @@ -1729,10 +1728,10 @@ void QX11EmbedContainerPrivate::acceptClient(WId window) checkGrab(); if (q->hasFocus()) { XSetInputFocus(q->x11Info().display(), client, XRevertToParent, x11Time()); - } else { - if (!isEmbedded()) - moveInputToProxy(); } + } else { + if (!isEmbedded()) + moveInputToProxy(); } emit q->clientIsEmbedded(); @@ -1749,11 +1748,9 @@ void QX11EmbedContainerPrivate::acceptClient(WId window) void QX11EmbedContainerPrivate::moveInputToProxy() { Q_Q(QX11EmbedContainer); - WId focus; - int revert_to; - XGetInputFocus(q->x11Info().display(), &focus, &revert_to); - if (focus != focusProxy->internalWinId()) - XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, x11Time()); + // Following Owen Taylor's advice from the XEmbed specification to + // always use CurrentTime when no explicit user action is involved. + XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, CurrentTime); } /*! \internal diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index 341331b..0a3a8dd 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -491,8 +491,9 @@ static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately) if (!widget) return; -#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE) - if (QApplicationPrivate::inSizeMove && widget->internalWinId() && !updateImmediately) { +#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE) + if (QApplicationPrivate::inSizeMove && widget->internalWinId() && !updateImmediately + && !widget->testAttribute(Qt::WA_DontShowOnScreen)) { // Tell Windows to send us a paint event if we're in WM_SIZE/WM_MOVE; posted events // are blocked until the mouse button is released. See task 146849. const QRegion rgn(qt_dirtyRegion(widget)); diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp index 7ed521e..6a206ee 100644 --- a/src/gui/painting/qbezier.cpp +++ b/src/gui/painting/qbezier.cpp @@ -673,10 +673,10 @@ static int IntersectBB(const QBezier &a, const QBezier &b) #ifdef QDEBUG_BEZIER static QDebug operator<<(QDebug dbg, const QBezier &bz) { - dbg <<"["<<bz.x1<<", "<<bz.y1<<"], " - <<"["<<bz.x2<<", "<<bz.y2<<"], " - <<"["<<bz.x3<<", "<<bz.y3<<"], " - <<"["<<bz.x4<<", "<<bz.y4<<"]"; + dbg << '[' << bz.x1<< ", " << bz.y1 << "], " + << '[' << bz.x2 <<", " << bz.y2 << "], " + << '[' << bz.x3 <<", " << bz.y3 << "], " + << '[' << bz.x4 <<", " << bz.y4 << ']'; return dbg; } #endif diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index 16dd617..4bdaf0b 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -44,8 +44,6 @@ QT_BEGIN_NAMESPACE -static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; - struct SourceOnlyAlpha { inline uchar alpha(uchar src) const { return src; } @@ -106,6 +104,37 @@ struct Blend_RGB16_on_RGB16_ConstAlpha { quint32 m_ialpha; }; +struct Blend_ARGB24_on_RGB16_SourceAlpha { + inline void write(quint16 *dst, const qargb8565 &src) { + const uint alpha = src.alpha(); + if (alpha) { + quint16 s = src.rawValue16(); + if (alpha < 255) + s += BYTE_MUL_RGB16(*dst, 255 - alpha); + *dst = s; + } + } +}; + +struct Blend_ARGB24_on_RGB16_SourceAndConstAlpha { + inline Blend_ARGB24_on_RGB16_SourceAndConstAlpha(quint32 alpha) { + m_alpha = (alpha * 255) >> 8; + } + + inline void write(quint16 *dst, qargb8565 src) { + src = src.byte_mul(src.alpha(m_alpha)); + const uint alpha = src.alpha(); + if (alpha) { + quint16 s = src.rawValue16(); + if (alpha < 255) + s += BYTE_MUL_RGB16(*dst, 255 - alpha); + *dst = s; + } + } + + quint32 m_alpha; +}; + struct Blend_ARGB32_on_RGB16_SourceAlpha { inline void write(quint16 *dst, quint32 src) { const quint8 alpha = qAlpha(src); @@ -140,14 +169,11 @@ struct Blend_ARGB32_on_RGB16_SourceAndConstAlpha { template <typename SRC, typename T> void qt_scale_image_16bit(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, - const QRectF &target, + const QRectF &targetRect, const QRectF &srcRect, const QRect &clip, T blender) { - const QRectF targetRect = target.translated(aliasedCoordinateDelta, - aliasedCoordinateDelta); - qreal sx = targetRect.width() / (qreal) srcRect.width(); qreal sy = targetRect.height() / (qreal) srcRect.height(); @@ -242,6 +268,32 @@ void qt_scale_image_rgb16_on_rgb16(uchar *destPixels, int dbpl, } } +void qt_scale_image_argb24_on_rgb16(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + int const_alpha) +{ +#ifdef QT_DEBUG_DRAW + printf("qt_scale_argb24_on_rgb16: dst=(%p, %d), src=(%p, %d), target=(%d, %d), [%d x %d], src=(%d, %d) [%d x %d] alpha=%d\n", + destPixels, dbpl, srcPixels, sbpl, + targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), + sourceRect.x(), sourceRect.y(), sourceRect.width(), sourceRect.height(), + const_alpha); +#endif + if (const_alpha == 256) { + Blend_ARGB24_on_RGB16_SourceAlpha noAlpha; + qt_scale_image_16bit<qargb8565>(destPixels, dbpl, srcPixels, sbpl, + targetRect, sourceRect, clip, noAlpha); + } else { + Blend_ARGB24_on_RGB16_SourceAndConstAlpha constAlpha(const_alpha); + qt_scale_image_16bit<qargb8565>(destPixels, dbpl, srcPixels, sbpl, + targetRect, sourceRect, clip, constAlpha); + } +} + + void qt_scale_image_argb32_on_rgb16(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, const QRectF &targetRect, @@ -617,14 +669,11 @@ struct Blend_ARGB32_on_ARGB32_SourceAndConstAlpha { template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, - const QRectF &target, + const QRectF &targetRect, const QRectF &srcRect, const QRect &clip, T blender) { - const QRectF targetRect = target.translated(aliasedCoordinateDelta, - aliasedCoordinateDelta); - qreal sx = targetRect.width() / (qreal) srcRect.width(); qreal sy = targetRect.height() / (qreal) srcRect.height(); @@ -882,7 +931,7 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB32, qt_scale_image_argb32_on_rgb16, // Format_ARGB32_Premultiplied, qt_scale_image_rgb16_on_rgb16, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, + qt_scale_image_argb24_on_rgb16, // Format_ARGB8565_Premultiplied, 0, // Format_RGB666, 0, // Format_ARGB6666_Premultiplied, 0, // Format_RGB555, diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 24d167e..b1fe3aa 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -1369,7 +1369,7 @@ QColor QColor::toRgb() const */ QColor QColor::toHsv() const { - if (!isValid()) + if (!isValid() || cspec == Hsv) return *this; if (cspec != Rgb) @@ -1421,7 +1421,7 @@ QColor QColor::toHsv() const */ QColor QColor::toCmyk() const { - if (!isValid()) + if (!isValid() || cspec == Cmyk) return *this; if (cspec != Rgb) return toRgb().toCmyk(); @@ -2022,12 +2022,12 @@ QDebug operator<<(QDebug dbg, const QColor &c) if (!c.isValid()) dbg.nospace() << "QColor(Invalid)"; else if (c.spec() == QColor::Rgb) - dbg.nospace() << "QColor(ARGB " << c.alphaF() << ", " << c.redF() << ", " << c.greenF() << ", " << c.blueF() << ")"; + dbg.nospace() << "QColor(ARGB " << c.alphaF() << ", " << c.redF() << ", " << c.greenF() << ", " << c.blueF() << ')'; else if (c.spec() == QColor::Hsv) - dbg.nospace() << "QColor(AHSV " << c.alphaF() << ", " << c.hueF() << ", " << c.saturationF() << ", " << c.valueF() << ")"; + dbg.nospace() << "QColor(AHSV " << c.alphaF() << ", " << c.hueF() << ", " << c.saturationF() << ", " << c.valueF() << ')'; else if (c.spec() == QColor::Cmyk) dbg.nospace() << "QColor(ACMYK " << c.alphaF() << ", " << c.cyanF() << ", " << c.magentaF() << ", " << c.yellowF() << ", " - << c.blackF()<< ")"; + << c.blackF()<< ')'; return dbg.space(); #else @@ -2241,4 +2241,12 @@ QDataStream &operator>>(QDataStream &stream, QColor &color) \sa QColor::rgb(), QColor::rgba() */ +/*! \fn void QColormap::initialize() + \internal +*/ + +/*! \fn void QColormap::cleanup() + \internal +*/ + QT_END_NAMESPACE diff --git a/src/gui/painting/qcolormap_x11.cpp b/src/gui/painting/qcolormap_x11.cpp index ccf6955..c9186b1 100644 --- a/src/gui/painting/qcolormap_x11.cpp +++ b/src/gui/painting/qcolormap_x11.cpp @@ -337,8 +337,6 @@ static void init_direct(QColormapPrivate *d, bool ownColormap) static QColormap **cmaps = 0; -/*! \internal -*/ void QColormap::initialize() { Display *display = QX11Info::display(); @@ -578,8 +576,6 @@ void QColormap::initialize() } } -/*! \internal -*/ void QColormap::cleanup() { Display *display = QX11Info::display(); diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index ec4737c..bbe1a76 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -2106,8 +2106,7 @@ static inline int color_burn_op(int dst, int src, int da, int sa) if (src == 0 || src_da + dst_sa <= sa_da) return qt_div_255(temp); - else - return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp); + return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp); } template <typename T> @@ -6931,7 +6930,7 @@ static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer, } void qt_build_pow_tables() { - qreal smoothing = 1.7; + qreal smoothing = qreal(1.7); #ifdef Q_WS_MAC // decided by testing a few things on an iMac, should probably get this from the @@ -6953,15 +6952,15 @@ void qt_build_pow_tables() { } #else for (int i=0; i<256; ++i) { - qt_pow_rgb_gamma[i] = uchar(qRound(pow(i / 255.0, smoothing) * 255)); - qt_pow_rgb_invgamma[i] = uchar(qRound(pow(i / 255.0, 1 / smoothing) * 255)); + qt_pow_rgb_gamma[i] = uchar(qRound(pow(i / qreal(255.0), smoothing) * 255)); + qt_pow_rgb_invgamma[i] = uchar(qRound(pow(i / qreal(255.), 1 / smoothing) * 255)); } #endif #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) const qreal gray_gamma = 2.31; for (int i=0; i<256; ++i) - qt_pow_gamma[i] = uint(qRound(pow(i / 255.0, gray_gamma) * 2047)); + qt_pow_gamma[i] = uint(qRound(pow(i / qreal(255.), gray_gamma) * 2047)); for (int i=0; i<2048; ++i) qt_pow_invgamma[i] = uchar(qRound(pow(i / 2047.0, 1 / gray_gamma) * 255)); #endif diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index de97683..38fee8d 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -110,6 +110,7 @@ struct QSpanData; class QGradient; class QRasterBuffer; class QClipData; +class QRasterPaintEngineState; typedef QT_FT_SpanFunc ProcessSpans; typedef void (*BitmapBlitFunc)(QRasterBuffer *rasterBuffer, @@ -293,7 +294,7 @@ struct QSpanData }; void init(QRasterBuffer *rb, const QRasterPaintEngine *pe); - void setup(const QBrush &brush, int alpha); + void setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode); void setupMatrix(const QTransform &matrix, int bilinear); void initTexture(const QImage *image, int alpha, QTextureData::Type = QTextureData::Plain, const QRect &sourceRect = QRect()); void adjustSpanMethods(); @@ -446,6 +447,7 @@ public: inline bool operator==(const qargb8565 &v) const; inline quint32 rawValue() const; + inline quint16 rawValue16() const; private: friend class qrgb565; @@ -462,7 +464,7 @@ public: inline explicit qrgb565(quint32p v); inline explicit qrgb565(quint32 v); - inline explicit qrgb565(qargb8565 v); + inline explicit qrgb565(const qargb8565 &v); inline operator quint32() const; inline operator quint16() const; @@ -568,6 +570,11 @@ quint32 qargb8565::rawValue() const return (data[2] << 16) | (data[1] << 8) | data[0]; } +quint16 qargb8565::rawValue16() const +{ + return (data[2] << 8) | data[1]; +} + qrgb565::qrgb565(quint32p v) { *this = qrgb565(quint32(v)); @@ -582,7 +589,7 @@ qrgb565::qrgb565(quint32 v) data = (r & 0xf800) | (g & 0x07e0)| (b & 0x001f); } -qrgb565::qrgb565(qargb8565 v) +qrgb565::qrgb565(const qargb8565 &v) { data = (v.data[2] << 8) | v.data[1]; } diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp index 3397c45..175f1ab 100644 --- a/src/gui/painting/qemulationpaintengine.cpp +++ b/src/gui/painting/qemulationpaintengine.cpp @@ -123,14 +123,30 @@ void QEmulationPaintEngine::stroke(const QVectorPath &path, const QPen &pen) real_engine->stroke(path, bgPen); } - QBrush brush = pen.brush(); + QPen copy = pen; Qt::BrushStyle style = qbrush_style(brush); if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { const QGradient *g = brush.gradient(); + if (g->coordinateMode() > QGradient::LogicalMode) { - QPaintEngineEx::stroke(path, pen); - return; + if (g->coordinateMode() == QGradient::StretchToDeviceMode) { + QTransform mat = brush.transform(); + mat.scale(real_engine->painter()->device()->width(), real_engine->painter()->device()->height()); + brush.setTransform(mat); + copy.setBrush(brush); + real_engine->stroke(path, copy); + return; + } else if (g->coordinateMode() == QGradient::ObjectBoundingMode) { + QTransform mat = brush.transform(); + QRealRect r = path.controlPointRect(); + mat.translate(r.x1, r.y1); + mat.scale(r.x2 - r.x1, r.y2 - r.y1); + brush.setTransform(mat); + copy.setBrush(brush); + real_engine->stroke(path, copy); + return; + } } } diff --git a/src/gui/painting/qgraphicssystemfactory_p.h b/src/gui/painting/qgraphicssystemfactory_p.h index 9e95324..523b908 100644 --- a/src/gui/painting/qgraphicssystemfactory_p.h +++ b/src/gui/painting/qgraphicssystemfactory_p.h @@ -63,7 +63,7 @@ QT_MODULE(Gui) class QGraphicsSystem; -class Q_GUI_EXPORT QGraphicsSystemFactory +class QGraphicsSystemFactory { public: static QStringList keys(); diff --git a/src/gui/painting/qgraphicssystemplugin_p.h b/src/gui/painting/qgraphicssystemplugin_p.h index 2e70333..ea7aa2d 100644 --- a/src/gui/painting/qgraphicssystemplugin_p.h +++ b/src/gui/painting/qgraphicssystemplugin_p.h @@ -64,7 +64,7 @@ QT_MODULE(Gui) class QGraphicsSystem; -struct Q_GUI_EXPORT QGraphicsSystemFactoryInterface : public QFactoryInterface +struct QGraphicsSystemFactoryInterface : public QFactoryInterface { virtual QGraphicsSystem *create(const QString &key) = 0; }; diff --git a/src/gui/painting/qmatrix.cpp b/src/gui/painting/qmatrix.cpp index 31abcad..030415d 100644 --- a/src/gui/painting/qmatrix.cpp +++ b/src/gui/painting/qmatrix.cpp @@ -1178,7 +1178,7 @@ QDebug operator<<(QDebug dbg, const QMatrix &m) << " 22=" << m.m22() << " dx=" << m.dx() << " dy=" << m.dy() - << ")"; + << ')'; return dbg.space(); } #endif diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp index 4058143..471f544 100644 --- a/src/gui/painting/qmemrotate.cpp +++ b/src/gui/painting/qmemrotate.cpp @@ -528,6 +528,26 @@ void qt_memrotate270(const srctype *src, int w, int h, int sstride, \ qt_memrotate270_template(src, w, h, sstride, dest, dstride); \ } +#define QT_IMPL_SIMPLE_MEMROTATE(srctype, desttype) \ +void qt_memrotate90(const srctype *src, int w, int h, int sstride, \ + desttype *dest, int dstride) \ +{ \ + qt_memrotate90_tiled_unpacked<desttype,srctype>(src, w, h, sstride, dest, dstride); \ +} \ +void qt_memrotate180(const srctype *src, int w, int h, int sstride, \ + desttype *dest, int dstride) \ +{ \ + qt_memrotate180_template(src, w, h, sstride, dest, dstride); \ +} \ +void qt_memrotate270(const srctype *src, int w, int h, int sstride, \ + desttype *dest, int dstride) \ +{ \ + qt_memrotate270_tiled_unpacked<desttype,srctype>(src, w, h, sstride, dest, dstride); \ +} + + + + QT_IMPL_MEMROTATE(quint32, quint32) QT_IMPL_MEMROTATE(quint32, quint16) QT_IMPL_MEMROTATE(quint16, quint32) @@ -539,6 +559,14 @@ QT_IMPL_MEMROTATE(quint32, quint8) QT_IMPL_MEMROTATE(quint16, quint8) QT_IMPL_MEMROTATE(qrgb444, quint8) QT_IMPL_MEMROTATE(quint8, quint8) + +#if defined(QT_QWS_ROTATE_BGR) +QT_IMPL_SIMPLE_MEMROTATE(quint16, qbgr565) +QT_IMPL_SIMPLE_MEMROTATE(quint32, qbgr565) +QT_IMPL_SIMPLE_MEMROTATE(qrgb555, qbgr555) +QT_IMPL_SIMPLE_MEMROTATE(quint32, qbgr555) +#endif + #ifdef QT_QWS_DEPTH_GENERIC QT_IMPL_MEMROTATE(quint32, qrgb_generic16) QT_IMPL_MEMROTATE(quint16, qrgb_generic16) diff --git a/src/gui/painting/qmemrotate_p.h b/src/gui/painting/qmemrotate_p.h index c1eb93e..87cfb1a 100644 --- a/src/gui/painting/qmemrotate_p.h +++ b/src/gui/painting/qmemrotate_p.h @@ -92,6 +92,14 @@ QT_DECL_MEMROTATE(quint32, quint8); QT_DECL_MEMROTATE(quint16, quint8); QT_DECL_MEMROTATE(qrgb444, quint8); QT_DECL_MEMROTATE(quint8, quint8); + +#ifdef QT_QWS_ROTATE_BGR +QT_DECL_MEMROTATE(quint16, qbgr565); +QT_DECL_MEMROTATE(quint32, qbgr565); +QT_DECL_MEMROTATE(qrgb555, qbgr555); +QT_DECL_MEMROTATE(quint32, qbgr555); +#endif + #ifdef QT_QWS_DEPTH_GENERIC QT_DECL_MEMROTATE(quint32, qrgb_generic16); QT_DECL_MEMROTATE(quint16, qrgb_generic16); diff --git a/src/gui/painting/qpaintdevice_qws.cpp b/src/gui/painting/qpaintdevice_qws.cpp index 6a68d28..c67be86 100644 --- a/src/gui/painting/qpaintdevice_qws.cpp +++ b/src/gui/painting/qpaintdevice_qws.cpp @@ -81,9 +81,6 @@ int QPaintDevice::metric(PaintDeviceMetric m) const } } -/*! - \internal -*/ QWSDisplay *QPaintDevice::qwsDisplay() { return qt_fbdpy; diff --git a/src/gui/painting/qpaintdevice_win.cpp b/src/gui/painting/qpaintdevice_win.cpp index 6cae744..7cd3392 100644 --- a/src/gui/painting/qpaintdevice_win.cpp +++ b/src/gui/painting/qpaintdevice_win.cpp @@ -71,16 +71,11 @@ int QPaintDevice::metric(PaintDeviceMetric) const return 0; } - -/*! \internal -*/ HDC QPaintDevice::getDC() const { return 0; } -/*! \internal -*/ void QPaintDevice::releaseDC(HDC) const { } diff --git a/src/gui/painting/qpaintdevice_x11.cpp b/src/gui/painting/qpaintdevice_x11.cpp index 4ea9f57..95cb115 100644 --- a/src/gui/painting/qpaintdevice_x11.cpp +++ b/src/gui/painting/qpaintdevice_x11.cpp @@ -106,33 +106,11 @@ int QPaintDevice::metric(PaintDeviceMetric) const #ifdef QT3_SUPPORT -/*! - Use QX11Info::display() instead. - - \oldcode - Display *display = widget->x11Display(); - \newcode - Display *display = QX11Info::display(); - \endcode - - \sa QWidget::x11Info(), QX11Info::display() -*/ Display *QPaintDevice::x11Display() const { return X11->display; } -/*! - Use QX11Info::screen() instead. - - \oldcode - int screen = widget->x11Screen(); - \newcode - int screen = widget->x11Info().screen(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ int QPaintDevice::x11Screen() const { const QX11Info *info = qt_x11Info(this); @@ -141,17 +119,6 @@ int QPaintDevice::x11Screen() const return QX11Info::appScreen(); } -/*! - Use QX11Info::visual() instead. - - \oldcode - void *visual = widget->x11Visual(); - \newcode - void *visual = widget->x11Info().visual(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ void *QPaintDevice::x11Visual() const { const QX11Info *info = qt_x11Info(this); @@ -160,17 +127,6 @@ void *QPaintDevice::x11Visual() const return QX11Info::appVisual(); } -/*! - Use QX11Info::depth() instead. - - \oldcode - int depth = widget->x11Depth(); - \newcode - int depth = widget->x11Info().depth(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ int QPaintDevice::x11Depth() const { const QX11Info *info = qt_x11Info(this); @@ -179,17 +135,6 @@ int QPaintDevice::x11Depth() const return QX11Info::appDepth(); } -/*! - Use QX11Info::cells() instead. - - \oldcode - int cells = widget->x11Cells(); - \newcode - int cells = widget->x11Info().cells(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ int QPaintDevice::x11Cells() const { const QX11Info *info = qt_x11Info(this); @@ -198,17 +143,6 @@ int QPaintDevice::x11Cells() const return QX11Info::appCells(); } -/*! - Use QX11Info::colormap() instead. - - \oldcode - unsigned long screen = widget->x11Colormap(); - \newcode - unsigned long screen = widget->x11Info().colormap(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ Qt::HANDLE QPaintDevice::x11Colormap() const { const QX11Info *info = qt_x11Info(this); @@ -217,17 +151,6 @@ Qt::HANDLE QPaintDevice::x11Colormap() const return QX11Info::appColormap(); } -/*! - Use QX11Info::defaultColormap() instead. - - \oldcode - bool isDefault = widget->x11DefaultColormap(); - \newcode - bool isDefault = widget->x11Info().defaultColormap(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ bool QPaintDevice::x11DefaultColormap() const { const QX11Info *info = qt_x11Info(this); @@ -236,17 +159,6 @@ bool QPaintDevice::x11DefaultColormap() const return QX11Info::appDefaultColormap(); } -/*! - Use QX11Info::defaultVisual() instead. - - \oldcode - bool isDefault = widget->x11DefaultVisual(); - \newcode - bool isDefault = widget->x11Info().defaultVisual(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ bool QPaintDevice::x11DefaultVisual() const { const QX11Info *info = qt_x11Info(this); @@ -255,176 +167,48 @@ bool QPaintDevice::x11DefaultVisual() const return QX11Info::appDefaultVisual(); } -/*! - Use QX11Info::visual() instead. - - \oldcode - void *visual = QPaintDevice::x11AppVisual(screen); - \newcode - void *visual = qApp->x11Info(screen).visual(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ void *QPaintDevice::x11AppVisual(int screen) { return QX11Info::appVisual(screen); } -/*! - Use QX11Info::colormap() instead. - - \oldcode - unsigned long colormap = QPaintDevice::x11AppColormap(screen); - \newcode - unsigned long colormap = qApp->x11Info(screen).colormap(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ Qt::HANDLE QPaintDevice::x11AppColormap(int screen) { return QX11Info::appColormap(screen); } -/*! - Use QX11Info::display() instead. - - \oldcode - Display *display = QPaintDevice::x11AppDisplay(); - \newcode - Display *display = qApp->x11Info().display(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ Display *QPaintDevice::x11AppDisplay() { return QX11Info::display(); } -/*! - Use QX11Info::screen() instead. - - \oldcode - int screen = QPaintDevice::x11AppScreen(); - \newcode - int screen = qApp->x11Info().screen(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ int QPaintDevice::x11AppScreen() { return QX11Info::appScreen(); } -/*! - Use QX11Info::depth() instead. - - \oldcode - int depth = QPaintDevice::x11AppDepth(screen); - \newcode - int depth = qApp->x11Info(screen).depth(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ int QPaintDevice::x11AppDepth(int screen) { return QX11Info::appDepth(screen); } -/*! - Use QX11Info::cells() instead. - - \oldcode - int cells = QPaintDevice::x11AppCells(screen); - \newcode - int cells = qApp->x11Info(screen).cells(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ int QPaintDevice::x11AppCells(int screen) { return QX11Info::appCells(screen); } -/*! - Use QX11Info::appRootWindow() instead. - - \oldcode - unsigned long window = QPaintDevice::x11AppRootWindow(screen); - \newcode - unsigned long window = qApp->x11Info(screen).appRootWindow(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ Qt::HANDLE QPaintDevice::x11AppRootWindow(int screen) { return QX11Info::appRootWindow(screen); } -/*! - Use QX11Info::defaultColormap() instead. - - \oldcode - bool isDefault = QPaintDevice::x11AppDefaultColormap(screen); - \newcode - bool isDefault = qApp->x11Info(screen).defaultColormap(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ bool QPaintDevice::x11AppDefaultColormap(int screen) { return QX11Info::appDefaultColormap(screen); } -/*! - Use QX11Info::defaultVisual() instead. - - \oldcode - bool isDefault = QPaintDevice::x11AppDefaultVisual(screen); - \newcode - bool isDefault = qApp->x11Info(screen).defaultVisual(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ bool QPaintDevice::x11AppDefaultVisual(int screen) { return QX11Info::appDefaultVisual(screen); } -/*! - Use QX11Info::setAppDpiX() instead. -*/ void QPaintDevice::x11SetAppDpiX(int dpi, int screen) { QX11Info::setAppDpiX(dpi, screen); } -/*! - Use QX11Info::setAppDpiY() instead. -*/ void QPaintDevice::x11SetAppDpiY(int dpi, int screen) { QX11Info::setAppDpiY(dpi, screen); } - -/*! - Use QX11Info::appDpiX() instead. - - \oldcode - bool isDefault = QPaintDevice::x11AppDpiX(screen); - \newcode - bool isDefault = qApp->x11Info(screen).appDpiX(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ int QPaintDevice::x11AppDpiX(int screen) { return QX11Info::appDpiX(screen); } -/*! - Use QX11Info::appDpiY() instead. - - \oldcode - bool isDefault = QPaintDevice::x11AppDpiY(screen); - \newcode - bool isDefault = qApp->x11Info(screen).appDpiY(); - \endcode - - \sa QWidget::x11Info(), QPixmap::x11Info() -*/ int QPaintDevice::x11AppDpiY(int screen) { return QX11Info::appDpiY(screen); diff --git a/src/gui/painting/qpaintengine_mac.cpp b/src/gui/painting/qpaintengine_mac.cpp index 0644a02..5889388 100644 --- a/src/gui/painting/qpaintengine_mac.cpp +++ b/src/gui/painting/qpaintengine_mac.cpp @@ -996,15 +996,14 @@ void QCoreGraphicsPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, co } else if (differentSize) { #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { - CGImageRef img = (CGImageRef)pm.macCGHandle(); + QCFType<CGImageRef> img = pm.toMacCGImageRef(); image = CGImageCreateWithImageInRect(img, CGRectMake(qRound(sr.x()), qRound(sr.y()), qRound(sr.width()), qRound(sr.height()))); - CGImageRelease(img); } else #endif { const int sx = qRound(sr.x()), sy = qRound(sr.y()), sw = qRound(sr.width()), sh = qRound(sr.height()); const QMacPixmapData *pmData = static_cast<const QMacPixmapData*>(pm.data); - quint32 *pantherData = pmData->pixels + (sy * pm.width() + sx); + quint32 *pantherData = pmData->pixels + sy * (pmData->bytesPerRow / 4) + sx; QCFType<CGDataProviderRef> provider = CGDataProviderCreateWithData(0, pantherData, sw*sh*pmData->bytesPerRow, 0); image = CGImageCreate(sw, sh, 8, 32, pmData->bytesPerRow, macGenericColorSpace(), diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 9b13352..3f85095 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -139,7 +139,6 @@ extern bool qt_cleartype_enabled; * Span functions */ static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData); -static void qt_span_fill_clipRegion(int count, const QSpan *spans, void *userData); static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData); static void qt_span_clip(int count, const QSpan *spans, void *userData); static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result); @@ -363,7 +362,8 @@ void QRasterPaintEngine::init() d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to); d->dashStroker = 0; - d->baseClip = 0; + d->baseClip = new QClipData(d->device->height()); + d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height())); d->image_filler.init(d->rasterBuffer, this); d->image_filler.type = QSpanData::Texture; @@ -447,6 +447,8 @@ QRasterPaintEngine::~QRasterPaintEngine() delete d->outlineMapper; delete d->rasterizer; delete d->dashStroker; + + delete d->baseClip; } /*! @@ -483,12 +485,12 @@ bool QRasterPaintEngine::begin(QPaintDevice *device) d->rasterizer->setClipRect(d->deviceRect); s->penData.init(d->rasterBuffer, this); - s->penData.setup(s->pen.brush(), s->intOpacity); + s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode); s->stroker = &d->basicStroker; d->basicStroker.setClipRect(d->deviceRect); s->brushData.init(d->rasterBuffer, this); - s->brushData.setup(s->brush, s->intOpacity); + s->brushData.setup(s->brush, s->intOpacity, s->composition_mode); d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver; @@ -534,19 +536,14 @@ bool QRasterPaintEngine::begin(QPaintDevice *device) */ bool QRasterPaintEngine::end() { - Q_D(QRasterPaintEngine); #ifdef QT_DEBUG_DRAW + Q_D(QRasterPaintEngine); qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect; if (d->baseClip) { dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), d->baseClip); } #endif - if (d->baseClip) { - delete d->baseClip; - d->baseClip = 0; - } - return true; } @@ -773,7 +770,7 @@ void QRasterPaintEngine::updatePen(const QPen &pen) s->strokeFlags = 0; s->penData.clip = d->clip(); - s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity); + s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode); if (s->strokeFlags & QRasterPaintEngine::DirtyTransform || pen.brush().transform().type() >= QTransform::TxNone) { @@ -873,7 +870,7 @@ void QRasterPaintEngine::updateBrush(const QBrush &brush) QRasterPaintEngineState *s = state(); // must set clip prior to setup, as setup uses it... s->brushData.clip = d->clip(); - s->brushData.setup(brush, s->intOpacity); + s->brushData.setup(brush, s->intOpacity, s->composition_mode); if (s->fillFlags & DirtyTransform || brush.transform().type() >= QTransform::TxNone) d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix()); @@ -1026,8 +1023,12 @@ void QRasterPaintEnginePrivate::drawImage(const QPointF &pt, int alpha, const QRect &sr) { - if (!clip.isValid()) + if (alpha == 0 || !clip.isValid()) + return; + + if (alpha ==0) return; + Q_ASSERT(img.depth() >= 8); int srcBPL = img.bytesPerLine(); @@ -1096,11 +1097,10 @@ void QRasterPaintEnginePrivate::systemStateChanged() if (!systemClip.isEmpty()) { QRegion clippedDeviceRgn = systemClip & clipRect; deviceRect = clippedDeviceRgn.boundingRect(); - delete baseClip; - baseClip = new QClipData(device->height()); baseClip->setClipRegion(clippedDeviceRgn); } else { deviceRect = clipRect; + baseClip->setClipRect(deviceRect); } #ifdef QT_DEBUG_DRAW qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << clipRect << systemClip; @@ -1172,6 +1172,25 @@ static void checkClipRatios(QRasterPaintEnginePrivate *d) } #endif +static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s) +{ + if (s->flags.has_clip_ownership) + delete s->clip; + s->clip = 0; + s->flags.has_clip_ownership = false; +} + +static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s) +{ + s->fillFlags |= QPaintEngine::DirtyClipPath; + s->strokeFlags |= QPaintEngine::DirtyClipPath; + s->pixmapFlags |= QPaintEngine::DirtyClipPath; + + d->solid_color_filler.clip = d->clip(); + d->solid_color_filler.adjustSpanMethods(); +} + + /*! \internal */ @@ -1183,12 +1202,12 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) if (path.elements()) { for (int i=0; i<path.elementCount(); ++i) { qDebug() << " - " << path.elements()[i] - << "(" << path.points()[i*2] << ", " << path.points()[i*2+1] << ")"; + << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')'; } } else { for (int i=0; i<path.elementCount(); ++i) { qDebug() << " ---- " - << "(" << path.points()[i*2] << ", " << path.points()[i*2+1] << ")"; + << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')'; } } #endif @@ -1220,10 +1239,7 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) } if (op == Qt::NoClip) { - if (s->flags.has_clip_ownership) - delete s->clip; - s->clip = 0; - s->flags.has_clip_ownership = false; + qrasterpaintengine_state_setNoClip(s); } else { QClipData *base = d->baseClip; @@ -1265,17 +1281,7 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) s->clip = newClip; s->flags.has_clip_ownership = true; } - - s->fillFlags |= DirtyClipPath; - s->strokeFlags |= DirtyClipPath; - s->pixmapFlags |= DirtyClipPath; - - d->solid_color_filler.clip = d->clip(); - d->solid_color_filler.adjustSpanMethods(); - -#ifdef QT_CLIPPING_RATIOS - checkClipRatios(d); -#endif + qrasterpaintengine_dirty_clip(d, s); } @@ -1293,10 +1299,7 @@ void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) QRasterPaintEngineState *s = state(); if (op == Qt::NoClip) { - if (s->flags.has_clip_ownership) - delete s->clip; - s->clip = d->baseClip; - s->flags.has_clip_ownership = false; + qrasterpaintengine_state_setNoClip(s); } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) { QPaintEngineEx::clip(rect, op); @@ -1340,37 +1343,63 @@ void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) return; } } - - s->brushData.clip = d->clip(); - s->penData.clip = d->clip(); - - s->fillFlags |= DirtyClipPath; - s->strokeFlags |= DirtyClipPath; - s->pixmapFlags |= DirtyClipPath; - - d->solid_color_filler.clip = d->clip(); - d->solid_color_filler.adjustSpanMethods(); - - -#ifdef QT_CLIPPING_RATIOS - checkClipRatios(d); -#endif + qrasterpaintengine_dirty_clip(d, s); } + /*! \internal */ void QRasterPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) { - QPaintEngineEx::clip(region, op); -} +#ifdef QT_DEBUG_DRAW + qDebug() << "QRasterPaintEngine::clip(): " << region << op; +#endif -/*! - \internal -*/ -void QRasterPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op) -{ - QPaintEngineEx::clip(path, op); + Q_D(QRasterPaintEngine); + + if (region.numRects() == 1) { + clip(region.boundingRect(), op); + return; + } + + QRasterPaintEngineState *s = state(); + const QClipData *clip = d->clip(); + const QClipData *baseClip = d->baseClip; + + if (op == Qt::NoClip) { + qrasterpaintengine_state_setNoClip(s); + } else if (s->matrix.type() > QTransform::TxScale + || op == Qt::UniteClip + || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip) + || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) { + QPaintEngineEx::clip(region, op); + } else { + const QClipData *curClip; + QClipData *newClip; + + if (op == Qt::IntersectClip) + curClip = clip; + else + curClip = baseClip; + + if (s->flags.has_clip_ownership) { + newClip = s->clip; + Q_ASSERT(newClip); + } else { + newClip = new QClipData(d->rasterBuffer->height()); + s->clip = newClip; + s->flags.has_clip_ownership = true; + } + + QRegion r = s->matrix.map(region); + if (curClip->hasRectClip) + newClip->setClipRegion(r & curClip->clipRect); + else if (curClip->hasRegionClip) + newClip->setClipRegion(r & clip->clipRegion); + + qrasterpaintengine_dirty_clip(d, s); + } } /*! @@ -1412,7 +1441,7 @@ static void fillRect_normalized(const QRect &r, QSpanData *data, { int x1, x2, y1, y2; - bool rectClipped = false; + bool rectClipped = true; if (data->clip) { x1 = qMax(r.x(), data->clip->xmin); @@ -1742,12 +1771,17 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) static inline QRect toNormalizedFillRect(const QRectF &rect) { - const int x1 = qRound(rect.x() + aliasedCoordinateDelta); - const int y1 = qRound(rect.y() + aliasedCoordinateDelta); - const int x2 = qRound(rect.right() + aliasedCoordinateDelta); - const int y2 = qRound(rect.bottom() + aliasedCoordinateDelta); + int x1 = int(rect.x() + aliasedCoordinateDelta); + int y1 = int(rect.y() + aliasedCoordinateDelta); + int x2 = int(rect.right() + aliasedCoordinateDelta); + int y2 = int(rect.bottom() + aliasedCoordinateDelta); - return QRect(x1, y1, x2 - x1, y2 - y1).normalized(); + if (x2 < x1) + qSwap(x1, x2); + if (y2 < y1) + qSwap(y1, y2); + + return QRect(x1, y1, x2 - x1, y2 - y1); } /*! @@ -1907,9 +1941,12 @@ void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color) QRasterPaintEngineState *s = state(); d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity)); + if ((d->solid_color_filler.solid.color & 0xff000000) == 0 + && s->composition_mode == QPainter::CompositionMode_SourceOver) { + return; + } d->solid_color_filler.clip = d->clip(); d->solid_color_filler.adjustSpanMethods(); - fillRect(r, &d->solid_color_filler); } @@ -2577,7 +2614,12 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe QRasterPaintEngineState *s = state(); const bool aa = s->flags.antialiased || s->flags.bilinear; if (!aa && sr.size() == QSize(1, 1)) { + // as fillRect will apply the aliased coordinate delta we need to + // subtract it here as we don't use it for image drawing + QTransform old = s->matrix; + s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta); fillRect(r, QColor::fromRgba(img.pixel(sr.x(), sr.y()))); + s->matrix = old; return; } @@ -2611,6 +2653,18 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe return; d->image_filler_xform.setupMatrix(copy, s->flags.bilinear); + if (!aa && s->matrix.type() == QTransform::TxScale) { + QRectF rr = s->matrix.mapRect(r); + + const int x1 = qRound(rr.x()); + const int y1 = qRound(rr.y()); + const int x2 = qRound(rr.right()); + const int y2 = qRound(rr.bottom()); + + fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d); + return; + } + #ifdef QT_FAST_SPANS ensureState(); if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) { @@ -2668,7 +2722,13 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe QRectF rr = r; rr.translate(s->matrix.dx(), s->matrix.dy()); - fillRect_normalized(toRect_normalized(rr), &d->image_filler, d); + + const int x1 = qRound(rr.x()); + const int y1 = qRound(rr.y()); + const int x2 = qRound(rr.right()); + const int y2 = qRound(rr.bottom()); + + fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d); } } @@ -3053,7 +3113,7 @@ bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const if (cl->clipRect == deviceRect) return true; - if (cl->hasRegionClip) { + if (cl->hasRectClip) { // inline contains() for performance (we know the rects are normalized) const QRect &r1 = cl->clipRect; return (r.left() >= r1.left() && r.right() <= r1.right() @@ -4284,6 +4344,7 @@ void QClipData::initialize() m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight); m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan)); + allocated = clipSpanHeight; if (hasRectClip) { int y = 0; @@ -4328,6 +4389,7 @@ void QClipData::initialize() int y = 0; int firstInBand = 0; + count = 0; while (firstInBand < numRects) { const int currMinY = rects.at(firstInBand).y(); const int currMaxY = currMinY + rects.at(firstInBand).height(); @@ -4388,20 +4450,39 @@ void QClipData::fixup() ymax = m_spans[count-1].y + 1; xmin = INT_MAX; xmax = 0; + + bool isRect = true; + int left = m_spans[0].x; + int right = m_spans[0].x + m_spans[0].len; + for (int i = 0; i < count; ++i) { -// qDebug() << " " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage; if (m_spans[i].y != y) { + if (m_spans[i].y != y + 1 && y != -1) { + isRect = false; + } y = m_spans[i].y; m_clipLines[y].spans = m_spans+i; m_clipLines[y].count = 0; // qDebug() << " new line: y=" << y; } ++m_clipLines[y].count; + int sl = (int) m_spans[i].x; + int sr = sl + m_spans[i].len; + xmin = qMin(xmin, (int)m_spans[i].x); xmax = qMax(xmax, (int)m_spans[i].x + m_spans[i].len); + + if (sl != left || sr != right) + isRect = false; } ++xmax; -// qDebug("xmin=%d,xmax=%d,ymin=%d,ymax=%d", xmin, xmax, ymin, ymax); +// qDebug("xmin=%d,xmax=%d,ymin=%d,ymax=%d %s", xmin, xmax, ymin, ymax, isRect ? "rectangular" : ""); + + if (isRect) { + hasRectClip = true; + clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin); + } + } /* @@ -4414,6 +4495,7 @@ void QClipData::setClipRect(const QRect &rect) // qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect; hasRectClip = true; + hasRegionClip = false; clipRect = rect; xmin = rect.x(); @@ -4422,7 +4504,7 @@ void QClipData::setClipRect(const QRect &rect) ymax = qMin(rect.y() + rect.height(), clipSpanHeight); if (m_spans) { - delete m_spans; + free(m_spans); m_spans = 0; } @@ -4440,6 +4522,7 @@ void QClipData::setClipRegion(const QRegion ®ion) } hasRegionClip = true; + hasRectClip = false; clipRegion = region; { // set bounding rect @@ -4451,7 +4534,7 @@ void QClipData::setClipRegion(const QRegion ®ion) } if (m_spans) { - delete m_spans; + free(m_spans); m_spans = 0; } @@ -4699,29 +4782,6 @@ static void qt_span_fill_clipRect(int count, const QSpan *spans, fillData->unclipped_blend(count, spans, fillData); } -static void qt_span_fill_clipRegion(int count, const QSpan *spans, - void *userData) -{ - QSpanData *fillData = reinterpret_cast<QSpanData *>(userData); - Q_ASSERT(fillData->blend && fillData->unclipped_blend); - - Q_ASSERT(fillData->clip); - Q_ASSERT(!fillData->clip->clipRegion.isEmpty()); - - const int NSPANS = 256; - QSpan cspans[NSPANS]; - int currentClip = 0; - while (currentClip < count) { - const int unclipped = qt_intersect_spans(const_cast<QSpan*>(spans), - count, ¤tClip, - &cspans[0], NSPANS, - fillData->clip->clipRegion); - if (unclipped > 0) - fillData->unclipped_blend(unclipped, cspans, fillData); - } - -} - static void qt_span_clip(int count, const QSpan *spans, void *userData) { ClipData *clipData = reinterpret_cast<ClipData *>(userData); @@ -4994,7 +5054,7 @@ void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe) extern QImage qt_imageForBrush(int brushStyle, bool invert); -void QSpanData::setup(const QBrush &brush, int alpha) +void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode) { Qt::BrushStyle brushStyle = qbrush_style(brush); switch (brushStyle) { @@ -5002,6 +5062,10 @@ void QSpanData::setup(const QBrush &brush, int alpha) type = Solid; QColor c = qbrush_color(brush); solid.color = PREMUL(ARGB_COMBINE_ALPHA(c.rgba(), alpha)); + if ((solid.color & 0xff000000) == 0 + && compositionMode == QPainter::CompositionMode_SourceOver) { + type = None; + } break; } @@ -5142,8 +5206,6 @@ void QSpanData::adjustSpanMethods() blend = unclipped_blend; } else if (clip->hasRectClip) { blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect; - } else if (clip->hasRegionClip) { - blend = clip->clipRegion.isEmpty() ? 0 : qt_span_fill_clipRegion; } else { blend = qt_span_fill_clipped; } @@ -5151,7 +5213,11 @@ void QSpanData::adjustSpanMethods() void QSpanData::setupMatrix(const QTransform &matrix, int bilin) { - QTransform inv = matrix.inverted(); + QTransform delta; + // make sure we round off correctly in qdrawhelper.cpp + delta.translate(1.0 / 65536, 1.0 / 65536); + + QTransform inv = (delta * matrix).inverted(); m11 = inv.m11(); m12 = inv.m12(); m13 = inv.m13(); @@ -6120,7 +6186,7 @@ void dumpClip(int width, int height, QClipData *clip) int y1 = 0; for (int i = 0; i < clip->count; ++i) { - QSpan *span = clip->spans + i; + QSpan *span = clip->spans() + i; for (int j = 0; j < span->len; ++j) clipImg.setPixel(span->x + j, span->y, 0xffffff00); x0 = qMin(x0, int(span->x)); @@ -6138,7 +6204,7 @@ void dumpClip(int width, int height, QClipData *clip) Q_ASSERT(x1 >= 0); fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1); - clipImg.save(QString(QLatin1String("clip-%0.png")).arg(counter++)); + clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++)); } #endif diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 26a2b3f..1f3f006 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -202,7 +202,6 @@ public: void clip(const QVectorPath &path, Qt::ClipOperation op); void clip(const QRect &rect, Qt::ClipOperation op); void clip(const QRegion ®ion, Qt::ClipOperation op); - void clip(const QPainterPath &path, Qt::ClipOperation op); enum ClipType { RectClip, diff --git a/src/gui/painting/qpaintengine_x11.cpp b/src/gui/painting/qpaintengine_x11.cpp index 4b2fbca..9cc9683 100644 --- a/src/gui/painting/qpaintengine_x11.cpp +++ b/src/gui/painting/qpaintengine_x11.cpp @@ -1543,6 +1543,8 @@ void QX11PaintEnginePrivate::fillPolygon_dev(const QPointF *polygonPoints, int p QX11PaintEnginePrivate::GCMode gcMode, QPaintEngine::PolygonDrawMode mode) { + Q_Q(QX11PaintEngine); + int clippedCount = 0; qt_float_point *clippedPoints = 0; @@ -1617,7 +1619,29 @@ void QX11PaintEnginePrivate::fillPolygon_dev(const QPointF *polygonPoints, int p } else #endif if (fill.style() != Qt::NoBrush) { - if (clippedCount > 0) { + if (clippedCount > 200000) { + QPolygon poly; + for (int i = 0; i < clippedCount; ++i) + poly << QPoint(qFloor(clippedPoints[i].x), qFloor(clippedPoints[i].y)); + + const QRect bounds = poly.boundingRect(); + const QRect aligned = bounds + & QRect(QPoint(), QSize(pdev->width(), pdev->height())); + + QImage img(aligned.size(), QImage::Format_ARGB32_Premultiplied); + img.fill(0); + + QPainter painter(&img); + painter.translate(-aligned.x(), -aligned.y()); + painter.setPen(Qt::NoPen); + painter.setBrush(fill); + if (gcMode == BrushGC) + painter.setBrushOrigin(q->painter()->brushOrigin()); + painter.drawPolygon(poly); + painter.end(); + + q->drawImage(aligned, img, img.rect(), Qt::AutoColor); + } else if (clippedCount > 0) { QVarLengthArray<XPoint> xpoints(clippedCount); for (int i = 0; i < clippedCount; ++i) { xpoints[i].x = qFloor(clippedPoints[i].x); diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 8eaad60..28f9220 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -105,7 +105,7 @@ QDebug Q_GUI_EXPORT &operator<<(QDebug &s, const QVectorPath &path) vectorPathBounds.x2 - vectorPathBounds.x1, vectorPathBounds.y2 - vectorPathBounds.y1); s << "QVectorPath(size:" << path.elementCount() << " hints:" << hex << path.hints() - << rf << ")"; + << rf << ')'; return s; } #endif @@ -778,7 +778,7 @@ void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, con { QBrush brush(state()->pen.color(), pixmap); QTransform xform; - xform.translate(-s.x(), -s.y()); + xform.translate(r.x() - s.x(), r.y() - s.y()); brush.setTransform(xform); qreal pts[] = { r.x(), r.y(), diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index b158392..4744f14 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5142,6 +5142,11 @@ void QPainter::drawConvexPolygon(const QPointF *points, int pointCount) d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode); } +static inline QPointF roundInDeviceCoordinates(const QPointF &p, const QTransform &m) +{ + return m.inverted().map(QPointF(m.map(p).toPoint())); +} + /*! \fn void QPainter::drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source) @@ -5210,11 +5215,12 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm) || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))) { save(); - // If there is no scaling or transformation involved we have to make sure we use the + // If there is no rotation involved we have to make sure we use the // antialiased and not the aliased coordinate system by rounding the coordinates. - if (d->state->matrix.type() <= QTransform::TxTranslate) { - x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx(); - y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy(); + if (d->state->matrix.type() <= QTransform::TxScale) { + const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix); + x = p.x(); + y = p.y(); } translate(x, y); setBackgroundMode(Qt::TransparentMode); @@ -5324,16 +5330,21 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform))) { save(); - // If there is no scaling or transformation involved we have to make sure we use the + // If there is no rotation involved we have to make sure we use the // antialiased and not the aliased coordinate system by rounding the coordinates. + if (d->state->matrix.type() <= QTransform::TxScale) { + const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix); + x = p.x(); + y = p.y(); + } + if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) { - x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx(); - y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy(); sx = qRound(sx); sy = qRound(sy); sw = qRound(sw); sh = qRound(sh); } + translate(x, y); scale(w / sw, h / sh); setBackgroundMode(Qt::TransparentMode); @@ -5483,11 +5494,12 @@ void QPainter::drawImage(const QPointF &p, const QImage &image) || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))) { save(); - // If there is no scaling or transformation involved we have to make sure we use the + // If there is no rotation involved we have to make sure we use the // antialiased and not the aliased coordinate system by rounding the coordinates. - if (d->state->matrix.type() <= QTransform::TxTranslate) { - x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx(); - y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy(); + if (d->state->matrix.type() <= QTransform::TxScale) { + const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix); + x = p.x(); + y = p.y(); } translate(x, y); setBackgroundMode(Qt::TransparentMode); @@ -5586,11 +5598,15 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))) { save(); - // If there is no scaling or transformation involved we have to make sure we use the + // If there is no rotation involved we have to make sure we use the // antialiased and not the aliased coordinate system by rounding the coordinates. + if (d->state->matrix.type() <= QTransform::TxScale) { + const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix); + x = p.x(); + y = p.y(); + } + if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) { - x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx(); - y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy(); sx = qRound(sx); sy = qRound(sy); sw = qRound(sw); @@ -6333,17 +6349,18 @@ void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPo setBrush(QBrush(d->state->pen.color(), pixmap)); setPen(Qt::NoPen); - // If there is no scaling or transformation involved we have to make sure we use the + // If there is no rotation involved we have to make sure we use the // antialiased and not the aliased coordinate system by rounding the coordinates. - if (d->state->matrix.type() <= QTransform::TxTranslate) { - qreal x = qRound(r.x() + d->state->matrix.dx()) - d->state->matrix.dx(); - qreal y = qRound(r.y() + d->state->matrix.dy()) - d->state->matrix.dy(); - qreal w = qRound(r.width()); - qreal h = qRound(r.height()); - sx = qRound(sx); - sy = qRound(sy); + if (d->state->matrix.type() <= QTransform::TxScale) { + const QPointF p = roundInDeviceCoordinates(r.topLeft(), d->state->matrix); + + if (d->state->matrix.type() <= QTransform::TxTranslate) { + sx = qRound(sx); + sy = qRound(sy); + } + setBrushOrigin(QPointF(r.x()-sx, r.y()-sy)); - drawRect(QRectF(x, y, w, h)); + drawRect(QRectF(p, r.size())); } else { setBrushOrigin(QPointF(r.x()-sx, r.y()-sy)); drawRect(r); @@ -7142,14 +7159,14 @@ QPoint QPainter::xFormDev(const QPoint &p) const \fn QRect QPainter::xFormDev(const QRect &rectangle) const \overload - Use combineMatrix() combined with QMatrix::inverted() instead. + Use mapRect() combined with QMatrix::inverted() instead. \oldcode QPainter painter(this); QRect transformed = painter.xFormDev(rectangle); \newcode QPainter painter(this); - QRect transformed = rectangle * painter.combinedMatrix().inverted(); + QRect transformed = painter.combinedMatrix().inverted(rectangle); \endcode */ @@ -8554,4 +8571,252 @@ void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivat p->draw_helper(path, operation); } +/*! \fn Display *QPaintDevice::x11Display() const + Use QX11Info::display() instead. + + \oldcode + Display *display = widget->x11Display(); + \newcode + Display *display = QX11Info::display(); + \endcode + + \sa QWidget::x11Info(), QX11Info::display() +*/ + +/*! \fn int QPaintDevice::x11Screen() const + Use QX11Info::screen() instead. + + \oldcode + int screen = widget->x11Screen(); + \newcode + int screen = widget->x11Info().screen(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn void *QPaintDevice::x11Visual() const + Use QX11Info::visual() instead. + + \oldcode + void *visual = widget->x11Visual(); + \newcode + void *visual = widget->x11Info().visual(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn int QPaintDevice::x11Depth() const + Use QX11Info::depth() instead. + + \oldcode + int depth = widget->x11Depth(); + \newcode + int depth = widget->x11Info().depth(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn int QPaintDevice::x11Cells() const + Use QX11Info::cells() instead. + + \oldcode + int cells = widget->x11Cells(); + \newcode + int cells = widget->x11Info().cells(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn Qt::HANDLE QPaintDevice::x11Colormap() const + Use QX11Info::colormap() instead. + + \oldcode + unsigned long screen = widget->x11Colormap(); + \newcode + unsigned long screen = widget->x11Info().colormap(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn bool QPaintDevice::x11DefaultColormap() const + Use QX11Info::defaultColormap() instead. + + \oldcode + bool isDefault = widget->x11DefaultColormap(); + \newcode + bool isDefault = widget->x11Info().defaultColormap(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn bool QPaintDevice::x11DefaultVisual() const + Use QX11Info::defaultVisual() instead. + + \oldcode + bool isDefault = widget->x11DefaultVisual(); + \newcode + bool isDefault = widget->x11Info().defaultVisual(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn void *QPaintDevice::x11AppVisual(int screen) + Use QX11Info::visual() instead. + + \oldcode + void *visual = QPaintDevice::x11AppVisual(screen); + \newcode + void *visual = qApp->x11Info(screen).visual(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn Qt::HANDLE QPaintDevice::x11AppColormap(int screen) + Use QX11Info::colormap() instead. + + \oldcode + unsigned long colormap = QPaintDevice::x11AppColormap(screen); + \newcode + unsigned long colormap = qApp->x11Info(screen).colormap(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn Display *QPaintDevice::x11AppDisplay() + Use QX11Info::display() instead. + + \oldcode + Display *display = QPaintDevice::x11AppDisplay(); + \newcode + Display *display = qApp->x11Info().display(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn int QPaintDevice::x11AppScreen() + Use QX11Info::screen() instead. + + \oldcode + int screen = QPaintDevice::x11AppScreen(); + \newcode + int screen = qApp->x11Info().screen(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn int QPaintDevice::x11AppDepth(int screen) + Use QX11Info::depth() instead. + + \oldcode + int depth = QPaintDevice::x11AppDepth(screen); + \newcode + int depth = qApp->x11Info(screen).depth(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn int QPaintDevice::x11AppCells(int screen) + Use QX11Info::cells() instead. + + \oldcode + int cells = QPaintDevice::x11AppCells(screen); + \newcode + int cells = qApp->x11Info(screen).cells(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn Qt::HANDLE QPaintDevice::x11AppRootWindow(int screen) + Use QX11Info::appRootWindow() instead. + + \oldcode + unsigned long window = QPaintDevice::x11AppRootWindow(screen); + \newcode + unsigned long window = qApp->x11Info(screen).appRootWindow(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn bool QPaintDevice::x11AppDefaultColormap(int screen) + Use QX11Info::defaultColormap() instead. + + \oldcode + bool isDefault = QPaintDevice::x11AppDefaultColormap(screen); + \newcode + bool isDefault = qApp->x11Info(screen).defaultColormap(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn bool QPaintDevice::x11AppDefaultVisual(int screen) + Use QX11Info::defaultVisual() instead. + + \oldcode + bool isDefault = QPaintDevice::x11AppDefaultVisual(screen); + \newcode + bool isDefault = qApp->x11Info(screen).defaultVisual(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn void QPaintDevice::x11SetAppDpiX(int dpi, int screen) + Use QX11Info::setAppDpiX() instead. +*/ + +/*! \fn void QPaintDevice::x11SetAppDpiY(int dpi, int screen) + Use QX11Info::setAppDpiY() instead. +*/ + +/*! \fn int QPaintDevice::x11AppDpiX(int screen) + Use QX11Info::appDpiX() instead. + + \oldcode + bool isDefault = QPaintDevice::x11AppDpiX(screen); + \newcode + bool isDefault = qApp->x11Info(screen).appDpiX(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn int QPaintDevice::x11AppDpiY(int screen) + Use QX11Info::appDpiY() instead. + + \oldcode + bool isDefault = QPaintDevice::x11AppDpiY(screen); + \newcode + bool isDefault = qApp->x11Info(screen).appDpiY(); + \endcode + + \sa QWidget::x11Info(), QPixmap::x11Info() +*/ + +/*! \fn HDC QPaintDevice::getDC() const + \internal +*/ + +/*! \fn void QPaintDevice::releaseDC(HDC) const + \internal +*/ + +/*! \fn QWSDisplay *QPaintDevice::qwsDisplay() + \internal +*/ + QT_END_NAMESPACE diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 9b10f3c..bd91dfc 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -1006,7 +1006,7 @@ void QPainterPath::addPolygon(const QPolygonF &polygon) /*! \fn void QPainterPath::addEllipse(const QRectF &boundingRectangle) - Creates an ellipse within the the specified \a boundingRectangle + Creates an ellipse within the specified \a boundingRectangle and adds it to the painter path as a closed subpath. The ellipse is composed of a clockwise curve, starting and @@ -2751,7 +2751,7 @@ qreal QPainterPath::length() const /*! Returns percentage of the whole path at the specified length \a len. - Note that similarly to other percent methods, the percentage measurment + Note that similarly to other percent methods, the percentage measurement is not linear with regards to the length, if curves are present in the path. When curves are present the percentage argument is mapped to the t parameter of the Bezier equations. @@ -2868,7 +2868,7 @@ static inline QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *starti Returns the point at at the percentage \a t of the current path. The argument \a t has to be between 0 and 1. - Note that similarly to other percent methods, the percentage measurment + Note that similarly to other percent methods, the percentage measurement is not linear with regards to the length, if curves are present in the path. When curves are present the percentage argument is mapped to the t parameter of the Bezier equations. @@ -2899,7 +2899,7 @@ QPointF QPainterPath::pointAtPercent(qreal t) const Positive values for the angles mean counter-clockwise while negative values mean the clockwise direction. Zero degrees is at the 3 o'clock position. - Note that similarly to the other percent methods, the percentage measurment + Note that similarly to the other percent methods, the percentage measurement is not linear with regards to the length if curves are present in the path. When curves are present the percentage argument is mapped to the t parameter of the Bezier equations. @@ -2931,7 +2931,7 @@ qreal QPainterPath::angleAtPercent(qreal t) const Returns the slope of the path at the percentage \a t. The argument \a t has to be between 0 and 1. - Note that similarly to other percent methods, the percentage measurment + Note that similarly to other percent methods, the percentage measurement is not linear with regards to the length, if curves are present in the path. When curves are present the percentage argument is mapped to the t parameter of the Bezier equations. @@ -3348,7 +3348,7 @@ QDebug operator<<(QDebug s, const QPainterPath &p) s.nospace() << "QPainterPath: Element count=" << p.elementCount() << endl; const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"}; for (int i=0; i<p.elementCount(); ++i) { - s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ")" << endl; + s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << endl; } return s; diff --git a/src/gui/painting/qpainterpath_p.h b/src/gui/painting/qpainterpath_p.h index 29c48df..6fb439d 100644 --- a/src/gui/painting/qpainterpath_p.h +++ b/src/gui/painting/qpainterpath_p.h @@ -124,7 +124,7 @@ private: Q_DISABLE_COPY(QVectorPathConverter) }; -class Q_GUI_EXPORT QPainterPathData : public QPainterPathPrivate +class QPainterPathData : public QPainterPathPrivate { public: QPainterPathData() : diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 55006f6..0b2db8c 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -346,7 +346,7 @@ QByteArray QPdf::generateDashes(const QPen &pen) { QByteArray result; ByteStream s(&result); - s << "["; + s << '['; QVector<qreal> dasharray = pen.dashPattern(); qreal w = pen.widthF(); @@ -357,7 +357,7 @@ QByteArray QPdf::generateDashes(const QPen &pen) if (dw < 0.0001) dw = 0.0001; s << dw; } - s << "]"; + s << ']'; //qDebug() << "dasharray: pen has" << dasharray; //qDebug() << " => " << result; return result; @@ -915,17 +915,17 @@ const char *QPdf::paperSizeToString(QPrinter::PaperSize paperSize) QByteArray QPdf::stripSpecialCharacters(const QByteArray &string) { QByteArray s = string; - s.replace(" ", ""); - s.replace("(", ""); - s.replace(")", ""); - s.replace("<", ""); - s.replace(">", ""); - s.replace("[", ""); - s.replace("]", ""); - s.replace("{", ""); - s.replace("}", ""); - s.replace("/", ""); - s.replace("%", ""); + s.replace(' ', ""); + s.replace('(', ""); + s.replace(')', ""); + s.replace('<', ""); + s.replace('>', ""); + s.replace('[', ""); + s.replace(']', ""); + s.replace('{', ""); + s.replace('}', ""); + s.replace('/', ""); + s.replace('%', ""); return s; } diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp index 1d68520..ab60861 100644 --- a/src/gui/painting/qpen.cpp +++ b/src/gui/painting/qpen.cpp @@ -978,7 +978,7 @@ QDebug operator<<(QDebug dbg, const QPen &p) dbg.nospace() << "QPen(" << p.width() << ',' << p.brush() << ',' << int(p.style()) << ',' << int(p.capStyle()) << ',' << int(p.joinStyle()) << ',' << p.dashPattern() - << "," << p.dashOffset() + << ',' << p.dashOffset() << ',' << p.miterLimit() << ')'; return dbg.space(); #else diff --git a/src/gui/painting/qprintengine_pdf.cpp b/src/gui/painting/qprintengine_pdf.cpp index 2e063b7..e504558 100644 --- a/src/gui/painting/qprintengine_pdf.cpp +++ b/src/gui/painting/qprintengine_pdf.cpp @@ -423,7 +423,7 @@ int QPdfEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha) object = addXrefEntry(-1); QByteArray alphaDef; QPdf::ByteStream s(&alphaDef); - s << "<<\n/ca " << (brushAlpha/qreal(255.)) << "\n"; + s << "<<\n/ca " << (brushAlpha/qreal(255.)) << '\n'; s << "/CA " << (penAlpha/qreal(255.)) << "\n>>"; xprintf("%s\nendobj\n", alphaDef.constData()); alphaCache.insert(QPair<uint, uint>(brushAlpha, penAlpha), object); @@ -1010,7 +1010,7 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font) s << (char)('A' + (tag % 26)); tag /= 26; } - s << "+" << properties.postscriptName << "\n" + s << '+' << properties.postscriptName << "\n" "/Flags " << 4 << "\n" "/FontBBox [" << properties.boundingBox.x()*scale diff --git a/src/gui/painting/qprintengine_ps.cpp b/src/gui/painting/qprintengine_ps.cpp index 97ec640..29f364e 100644 --- a/src/gui/painting/qprintengine_ps.cpp +++ b/src/gui/painting/qprintengine_ps.cpp @@ -167,7 +167,7 @@ static QByteArray wrapDSC(const QByteArray &str) } wrapped += "\n%%+" + tmp; } - return wrapped + "\n"; + return wrapped + '\n'; } // ----------------------------- Internal class declarations ----------------------------- @@ -422,7 +422,7 @@ void QPSPrintEnginePrivate::drawImageHelper(qreal x, qreal y, qreal w, qreal h, << size << " string readstring\n"; ps_r7(*currentPage, out, out.size()); *currentPage << " pop def\n"; - *currentPage << width << ' ' << height << "[" << scaleX << " 0 0 " << scaleY << " 0 0]sl " + *currentPage << width << ' ' << height << '[' << scaleX << " 0 0 " << scaleY << " 0 0]sl " << bits << (!mask.isNull() ? "mask " : "false ") << x << ' ' << y << " di\n"; } @@ -529,7 +529,7 @@ void QPSPrintEnginePrivate::emitHeader(bool finished) else s << "\n%%BoundingBox: 0 0 " << w << h; } - s << "\n" << wrapDSC("%%Creator: " + creator.toUtf8()); + s << '\n' << wrapDSC("%%Creator: " + creator.toUtf8()); if (!title.isEmpty()) s << wrapDSC("%%Title: " + title.toUtf8()); #ifndef QT_NO_DATESTRING @@ -549,7 +549,7 @@ void QPSPrintEnginePrivate::emitHeader(bool finished) "% Prolog copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).\n" "% You may copy this prolog in any way that is directly related to this document.\n" "% For other use of this prolog, see your licensing agreement for Qt.\n" - << ps_header << "\n"; + << ps_header << '\n'; s << "/pageinit {\n"; @@ -560,12 +560,12 @@ void QPSPrintEnginePrivate::emitHeader(bool finished) s << mtop*scale << mleft*scale << "translate\n"; } if (orientation == QPrinter::Portrait) { - s << "% " << printer->widthMM() << "*" << printer->heightMM() + s << "% " << printer->widthMM() << '*' << printer->heightMM() << "mm (portrait)\n0 " << height*scale - << "translate " << scale << "-" << scale << "scale } def\n"; + << "translate " << scale << '-' << scale << "scale } def\n"; } else { - s << "% " << printer->heightMM() << "*" << printer->widthMM() - << " mm (landscape)\n 90 rotate " << scale << "-" << scale << "scale } def\n"; + s << "% " << printer->heightMM() << '*' << printer->widthMM() + << " mm (landscape)\n 90 rotate " << scale << '-' << scale << "scale } def\n"; } s << "%%EndProlog\n"; @@ -619,8 +619,8 @@ void QPSPrintEnginePrivate::flushPage(bool last) QPdf::ByteStream e(&trailer); buffer << "%%Page: " << pageCount << pageCount << "\n" - << "%%BeginPageSetup\n" - << "QI\n"; + "%%BeginPageSetup\n" + "QI\n"; if (hugeDocument) { for (QHash<QFontEngine::FaceId, QFontSubset *>::const_iterator it = fonts.constBegin(); it != fonts.constEnd(); ++it) { @@ -776,8 +776,8 @@ bool QPSPrintEngine::end() d->flushPage(true); QByteArray trailer; QPdf::ByteStream s(&trailer); - s << "%%Trailer\n"; - s << "%%Pages: " << d->pageCount - 1 << "\n" << + s << "%%Trailer\n" + "%%Pages: " << d->pageCount - 1 << '\n' << wrapDSC("%%DocumentFonts: " + d->fontsUsed); s << "%%EOF\n"; d->outDevice->write(trailer); diff --git a/src/gui/painting/qprinter.cpp b/src/gui/painting/qprinter.cpp index 5161e32..ba208fd 100644 --- a/src/gui/painting/qprinter.cpp +++ b/src/gui/painting/qprinter.cpp @@ -284,8 +284,8 @@ void QPrinterPrivate::addToManualSetList(QPrintEngine::PrintEnginePropertyKey ke to send PostScript or PDF output to the printer. As an alternative, the printProgram() function can be used to specify the command or utility to use instead of the system default. - - Note that setting parameters like paper size and resolution on an + + Note that setting parameters like paper size and resolution on an invalid printer is undefined. You can use QPrinter::isValid() to verify this before changing any parameters. @@ -480,26 +480,26 @@ void QPrinterPrivate::addToManualSetList(QPrintEngine::PrintEnginePropertyKey ke \value A7 74 x 105 mm \value A8 52 x 74 mm \value A9 37 x 52 mm - \value B0 1030 x 1456 mm - \value B1 728 x 1030 mm - \value B10 32 x 45 mm - \value B2 515 x 728 mm - \value B3 364 x 515 mm - \value B4 257 x 364 mm - \value B5 182 x 257 mm, 7.17 x 10.13 inches - \value B6 128 x 182 mm - \value B7 91 x 128 mm - \value B8 64 x 91 mm - \value B9 45 x 64 mm + \value B0 1000 x 1414 mm + \value B1 707 x 1000 mm + \value B2 500 x 707 mm + \value B3 353 x 500 mm + \value B4 250 x 353 mm + \value B5 176 x 250 mm, 6.93 x 9.84 inches + \value B6 125 x 176 mm + \value B7 88 x 125 mm + \value B8 62 x 88 mm + \value B9 33 x 62 mm + \value B10 31 x 44 mm \value C5E 163 x 229 mm \value Comm10E 105 x 241 mm, U.S. Common 10 Envelope \value DLE 110 x 220 mm - \value Executive 7.5 x 10 inches, 191 x 254 mm + \value Executive 7.5 x 10 inches, 190.5 x 254 mm \value Folio 210 x 330 mm - \value Ledger 432 x 279 mm - \value Legal 8.5 x 14 inches, 216 x 356 mm - \value Letter 8.5 x 11 inches, 216 x 279 mm - \value Tabloid 279 x 432 mm + \value Ledger 431.8 x 279.4 mm + \value Legal 8.5 x 14 inches, 215.9 x 355.6 mm + \value Letter 8.5 x 11 inches, 215.9 x 279.4 mm + \value Tabloid 279.4 x 431.8 mm \value Custom Unknown, or a user defined size. With setFullPage(false) (the default), the metrics will be a bit @@ -744,7 +744,7 @@ void QPrinter::setOutputFormat(OutputFormat format) #ifndef QT_NO_PDF Q_D(QPrinter); - if (d->outputFormat == format) + if (d->validPrinter && d->outputFormat == format) return; d->outputFormat = format; @@ -773,8 +773,8 @@ void QPrinter::setOutputFormat(OutputFormat format) if (def_engine) delete oldPrintEngine; - d->validPrinter = d->outputFormat == QPrinter::PdfFormat || d->outputFormat == QPrinter::PostScriptFormat; - + if (d->outputFormat == QPrinter::PdfFormat || d->outputFormat == QPrinter::PostScriptFormat) + d->validPrinter = true; #else Q_UNUSED(format); #endif diff --git a/src/gui/painting/qprinterinfo_unix.cpp b/src/gui/painting/qprinterinfo_unix.cpp index 0f33ea7..5724173 100644 --- a/src/gui/painting/qprinterinfo_unix.cpp +++ b/src/gui/painting/qprinterinfo_unix.cpp @@ -822,7 +822,7 @@ QList<QPrinterInfo> QPrinterInfo::availablePrinters() for (int i = 0; i < cupsPrinterCount; ++i) { QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name)); if (cupsPrinters[i].instance) - printerName += QLatin1String("/") + QString::fromLocal8Bit(cupsPrinters[i].instance); + printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance); list.append(QPrinterInfo(printerName)); if (cupsPrinters[i].is_default) list[i].d_ptr->m_default = true; @@ -893,7 +893,7 @@ QPrinterInfo::QPrinterInfo(const QPrinter& printer) for (int i = 0; i < cupsPrinterCount; ++i) { QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name)); if (cupsPrinters[i].instance) - printerName += QLatin1String("/") + QString::fromLocal8Bit(cupsPrinters[i].instance); + printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance); if (printerName == printer.printerName()) { if (cupsPrinters[i].is_default) d->m_default = true; diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index c88af7c..c4cd77a 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -450,9 +450,9 @@ QDebug operator<<(QDebug s, const QRegion &r) { QVector<QRect> rects = r.rects(); s.nospace() << "QRegion(size=" << rects.size() << "), " - << "bounds = " << r.boundingRect() << "\n"; + << "bounds = " << r.boundingRect() << '\n'; for (int i=0; i<rects.size(); ++i) - s << "- " << i << rects.at(i) << "\n"; + s << "- " << i << rects.at(i) << '\n'; return s; } #endif @@ -1601,7 +1601,7 @@ void QRegionPrivate::selfTest() const for (int i = 0; i < numRects; ++i) { const QRect r = rects.at(i); if ((r.width() * r.height()) > innerArea) - qDebug() << "selfTest(): innerRect" << innerRect << "<" << r; + qDebug() << "selfTest(): innerRect" << innerRect << '<' << r; } QRect r = rects.first(); diff --git a/src/gui/painting/qstroker_p.h b/src/gui/painting/qstroker_p.h index 72141aa..ca1f270 100644 --- a/src/gui/painting/qstroker_p.h +++ b/src/gui/painting/qstroker_p.h @@ -179,7 +179,7 @@ private: }; -class Q_GUI_EXPORT QStroker : public QStrokerOps +class QStroker : public QStrokerOps { public: diff --git a/src/gui/painting/qtessellator.cpp b/src/gui/painting/qtessellator.cpp index ce5ab74..9b5efee 100644 --- a/src/gui/painting/qtessellator.cpp +++ b/src/gui/painting/qtessellator.cpp @@ -1081,7 +1081,7 @@ void QTessellatorPrivate::addIntersection(const Edge *e1, const Edge *e2) yi = y; } QDEBUG() << " between edges " << e1->edge << "and" << e2->edge << "at point (" - << Q27Dot5ToDouble(yi) << ")"; + << Q27Dot5ToDouble(yi) << ')'; Intersection i1; i1.y = yi; @@ -1174,7 +1174,7 @@ void QTessellatorPrivate::addIntersections() for (int i = 0; i < scanline.size; ++i) { Edge *e = scanline.edges[i]; QDEBUG() << " " << i << e->edge << "isect=(" << e->intersect_left << e->intersect_right - << ")"; + << ')'; } #endif @@ -1240,8 +1240,8 @@ QRectF QTessellator::tessellate(const QPointF *points, int nPoints) QDEBUG() << " " << i << ": " << "point=" << d->vertices.position(d->vertices.sorted[i]) << "flags=" << d->vertices.sorted[i]->flags - << "pos=(" << Q27Dot5ToDouble(d->vertices.sorted[i]->x) << "/" - << Q27Dot5ToDouble(d->vertices.sorted[i]->y) << ")"; + << "pos=(" << Q27Dot5ToDouble(d->vertices.sorted[i]->x) << '/' + << Q27Dot5ToDouble(d->vertices.sorted[i]->y) << ')'; } #endif @@ -1271,9 +1271,9 @@ QRectF QTessellator::tessellate(const QPointF *points, int nPoints) for (int i = 0; i < d->scanline.size; ++i) { QDEBUG() << " " << d->scanline.edges[i]->edge << "p0= (" << Q27Dot5ToDouble(d->scanline.edges[i]->v0->x) - << "/" << Q27Dot5ToDouble(d->scanline.edges[i]->v0->y) + << '/' << Q27Dot5ToDouble(d->scanline.edges[i]->v0->y) << ") p1= (" << Q27Dot5ToDouble(d->scanline.edges[i]->v1->x) - << "/" << Q27Dot5ToDouble(d->scanline.edges[i]->v1->y) << ")" + << '/' << Q27Dot5ToDouble(d->scanline.edges[i]->v1->y) << ')' << "x=" << Q27Dot5ToDouble(d->scanline.edges[i]->positionAt(d->y)) << "isLeftOfNext=" << ((i < d->scanline.size - 1) diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 1ea40ba..89df869 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -88,11 +88,12 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti, ti.ascent.toReal(), ti.descent.toReal()); #endif - int glyph_width = metrics.width.ceil().toInt() + margin * 2; - int glyph_height = metrics.height.ceil().toInt() + margin * 2; + int glyph_width = metrics.width.ceil().toInt(); + int glyph_height = metrics.height.ceil().toInt(); if (glyph_height == 0 || glyph_width == 0) continue; - + glyph_width += margin * 2 + 4; + glyph_height += margin * 2 + 4; // align to 8-bit boundary if (m_type == QFontEngineGlyphCache::Raster_Mono) glyph_width = (glyph_width+7)&~7; diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 4a33b92..c00012a 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1020,7 +1020,7 @@ QDebug operator<<(QDebug dbg, const QTransform &m) << " 31=" << m.m31() << " 32=" << m.m32() << " 33=" << m.m33() - << ")"; + << ')'; return dbg.space(); } #endif @@ -1425,7 +1425,8 @@ static inline QHomogeneousCoordinate mapHomogeneous(const QTransform &transform, return c; } -static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, bool needsMoveTo) +static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, + bool needsMoveTo, bool needsLineTo = true) { QHomogeneousCoordinate ha = mapHomogeneous(transform, a); QHomogeneousCoordinate hb = mapHomogeneous(transform, b); @@ -1458,7 +1459,8 @@ static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transfor if (needsMoveTo) path.moveTo(ha.toPoint()); - path.lineTo(hb.toPoint()); + if (needsLineTo) + path.lineTo(hb.toPoint()); return true; } @@ -1525,7 +1527,7 @@ static QPainterPath mapProjective(const QTransform &transform, const QPainterPat } if (path.elementCount() > 0 && lastMoveTo != last) - lineTo_clipped(result, transform, last, lastMoveTo, needsMoveTo); + lineTo_clipped(result, transform, last, lastMoveTo, needsMoveTo, false); return result; } diff --git a/src/gui/painting/qwindowsurface_raster.cpp b/src/gui/painting/qwindowsurface_raster.cpp index dd4f7fd..3e7b015 100644 --- a/src/gui/painting/qwindowsurface_raster.cpp +++ b/src/gui/painting/qwindowsurface_raster.cpp @@ -142,8 +142,7 @@ void QRasterWindowSurface::beginPaint(const QRegion &rgn) p.fillRect(*it, blank); } } -#endif -#if defined(Q_WS_WINCE) +#else Q_UNUSED(rgn); #endif } @@ -250,6 +249,7 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi // d->image->image.save("flush.png"); + Q_UNUSED(offset); // Get a context for the widget. #ifndef QT_MAC_USE_COCOA CGContextRef context; diff --git a/src/gui/painting/qwindowsurface_x11.cpp b/src/gui/painting/qwindowsurface_x11.cpp index 9e8b498..f29d627 100644 --- a/src/gui/painting/qwindowsurface_x11.cpp +++ b/src/gui/painting/qwindowsurface_x11.cpp @@ -128,7 +128,7 @@ void QX11WindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint return; // qDebug() << "XSetClipRectangles"; // for (int i = 0; i < num; ++i) -// qDebug() << " " << i << rects[i].x << rects[i].x << rects[i].y << rects[i].width << rects[i].height; +// qDebug() << ' ' << i << rects[i].x << rects[i].x << rects[i].y << rects[i].width << rects[i].height; XSetClipRectangles(X11->display, gc, 0, 0, rects, num, YXBanded); XCopyArea(X11->display, d_ptr->device.handle(), widget->handle(), gc, br.x() + offset.x(), br.y() + offset.y(), br.width(), br.height(), wbr.x(), wbr.y()); diff --git a/src/gui/statemachine/qbasickeyeventtransition.cpp b/src/gui/statemachine/qbasickeyeventtransition.cpp new file mode 100644 index 0000000..f7f1eb6 --- /dev/null +++ b/src/gui/statemachine/qbasickeyeventtransition.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qbasickeyeventtransition_p.h" +#include <QtGui/qevent.h> +#include <qdebug.h> +#include <private/qabstracttransition_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QBasicKeyEventTransition + \since 4.6 + \ingroup statemachine + + \brief The QBasicKeyEventTransition class provides a transition for Qt key events. +*/ + +class QBasicKeyEventTransitionPrivate : public QAbstractTransitionPrivate +{ + Q_DECLARE_PUBLIC(QBasicKeyEventTransition) +public: + QBasicKeyEventTransitionPrivate(); + + static QBasicKeyEventTransitionPrivate *get(QBasicKeyEventTransition *q); + + QEvent::Type eventType; + int key; + Qt::KeyboardModifiers modifiersMask; +}; + +QBasicKeyEventTransitionPrivate::QBasicKeyEventTransitionPrivate() +{ + eventType = QEvent::None; + key = 0; + modifiersMask = Qt::NoModifier; +} + +QBasicKeyEventTransitionPrivate *QBasicKeyEventTransitionPrivate::get(QBasicKeyEventTransition *q) +{ + return q->d_func(); +} + +/*! + Constructs a new key event transition with the given \a sourceState. +*/ +QBasicKeyEventTransition::QBasicKeyEventTransition(QState *sourceState) + : QAbstractTransition(*new QBasicKeyEventTransitionPrivate, sourceState) +{ +} + +/*! + Constructs a new event transition for events of the given \a type for the + given \a key, with the given \a sourceState. +*/ +QBasicKeyEventTransition::QBasicKeyEventTransition(QEvent::Type type, int key, + QState *sourceState) + : QAbstractTransition(*new QBasicKeyEventTransitionPrivate, sourceState) +{ + Q_D(QBasicKeyEventTransition); + d->eventType = type; + d->key = key; +} + +/*! + Constructs a new event transition for events of the given \a type for the + given \a key, with the given \a modifiersMask and \a sourceState. +*/ +QBasicKeyEventTransition::QBasicKeyEventTransition(QEvent::Type type, int key, + Qt::KeyboardModifiers modifiersMask, + QState *sourceState) + : QAbstractTransition(*new QBasicKeyEventTransitionPrivate, sourceState) +{ + Q_D(QBasicKeyEventTransition); + d->eventType = type; + d->key = key; + d->modifiersMask = modifiersMask; +} + +/*! + Destroys this event transition. +*/ +QBasicKeyEventTransition::~QBasicKeyEventTransition() +{ +} + +/*! + Returns the event type that this key event transition is associated with. +*/ +QEvent::Type QBasicKeyEventTransition::eventType() const +{ + Q_D(const QBasicKeyEventTransition); + return d->eventType; +} + +/*! + Sets the event \a type that this key event transition is associated with. +*/ +void QBasicKeyEventTransition::setEventType(QEvent::Type type) +{ + Q_D(QBasicKeyEventTransition); + d->eventType = type; +} + +/*! + Returns the key that this key event transition checks for. +*/ +int QBasicKeyEventTransition::key() const +{ + Q_D(const QBasicKeyEventTransition); + return d->key; +} + +/*! + Sets the key that this key event transition will check for. +*/ +void QBasicKeyEventTransition::setKey(int key) +{ + Q_D(QBasicKeyEventTransition); + d->key = key; +} + +/*! + Returns the keyboard modifiers mask that this key event transition checks + for. +*/ +Qt::KeyboardModifiers QBasicKeyEventTransition::modifiersMask() const +{ + Q_D(const QBasicKeyEventTransition); + return d->modifiersMask; +} + +/*! + Sets the keyboard modifiers mask that this key event transition will check + for. +*/ +void QBasicKeyEventTransition::setModifiersMask(Qt::KeyboardModifiers modifiersMask) +{ + Q_D(QBasicKeyEventTransition); + d->modifiersMask = modifiersMask; +} + +/*! + \reimp +*/ +bool QBasicKeyEventTransition::eventTest(QEvent *event) +{ + Q_D(const QBasicKeyEventTransition); + if (event->type() == d->eventType) { + QKeyEvent *ke = static_cast<QKeyEvent*>(event); + return (ke->key() == d->key) + && ((ke->modifiers() & d->modifiersMask) == d->modifiersMask); + } + return false; +} + +/*! + \reimp +*/ +void QBasicKeyEventTransition::onTransition(QEvent *) +{ +} + +QT_END_NAMESPACE diff --git a/src/gui/statemachine/qbasickeyeventtransition_p.h b/src/gui/statemachine/qbasickeyeventtransition_p.h new file mode 100644 index 0000000..39fa6ad --- /dev/null +++ b/src/gui/statemachine/qbasickeyeventtransition_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBASICKEYEVENTTRANSITION_P_H +#define QBASICKEYEVENTTRANSITION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qabstracttransition.h> +#include <QtGui/qevent.h> + +QT_BEGIN_NAMESPACE + +class QBasicKeyEventTransitionPrivate; +class Q_AUTOTEST_EXPORT QBasicKeyEventTransition : public QAbstractTransition +{ + Q_OBJECT +public: + QBasicKeyEventTransition(QState *sourceState = 0); + QBasicKeyEventTransition(QEvent::Type type, int key, QState *sourceState = 0); + QBasicKeyEventTransition(QEvent::Type type, int key, + Qt::KeyboardModifiers modifiersMask, + QState *sourceState = 0); + ~QBasicKeyEventTransition(); + + QEvent::Type eventType() const; + void setEventType(QEvent::Type type); + + int key() const; + void setKey(int key); + + Qt::KeyboardModifiers modifiersMask() const; + void setModifiersMask(Qt::KeyboardModifiers modifiers); + +protected: + bool eventTest(QEvent *event); + void onTransition(QEvent *); + +private: + Q_DISABLE_COPY(QBasicKeyEventTransition) + Q_DECLARE_PRIVATE(QBasicKeyEventTransition) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/statemachine/qbasicmouseeventtransition.cpp b/src/gui/statemachine/qbasicmouseeventtransition.cpp new file mode 100644 index 0000000..20dd792 --- /dev/null +++ b/src/gui/statemachine/qbasicmouseeventtransition.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qbasicmouseeventtransition_p.h" +#include <QtGui/qevent.h> +#include <QtGui/qpainterpath.h> +#include <qdebug.h> +#include <private/qabstracttransition_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QBasicMouseEventTransition + \since 4.6 + \ingroup statemachine + + \brief The QBasicMouseEventTransition class provides a transition for Qt mouse events. +*/ + +class QBasicMouseEventTransitionPrivate : public QAbstractTransitionPrivate +{ + Q_DECLARE_PUBLIC(QBasicMouseEventTransition) +public: + QBasicMouseEventTransitionPrivate(); + + static QBasicMouseEventTransitionPrivate *get(QBasicMouseEventTransition *q); + + QEvent::Type eventType; + Qt::MouseButton button; + Qt::KeyboardModifiers modifiersMask; + QPainterPath path; +}; + +QBasicMouseEventTransitionPrivate::QBasicMouseEventTransitionPrivate() +{ + eventType = QEvent::None; + button = Qt::NoButton; +} + +QBasicMouseEventTransitionPrivate *QBasicMouseEventTransitionPrivate::get(QBasicMouseEventTransition *q) +{ + return q->d_func(); +} + +/*! + Constructs a new mouse event transition with the given \a sourceState. +*/ +QBasicMouseEventTransition::QBasicMouseEventTransition(QState *sourceState) + : QAbstractTransition(*new QBasicMouseEventTransitionPrivate, sourceState) +{ +} + +/*! + Constructs a new mouse event transition for events of the given \a type. +*/ +QBasicMouseEventTransition::QBasicMouseEventTransition(QEvent::Type type, + Qt::MouseButton button, + QState *sourceState) + : QAbstractTransition(*new QBasicMouseEventTransitionPrivate, sourceState) +{ + Q_D(QBasicMouseEventTransition); + d->eventType = type; + d->button = button; +} + +/*! + Destroys this mouse event transition. +*/ +QBasicMouseEventTransition::~QBasicMouseEventTransition() +{ +} + +/*! + Returns the event type that this mouse event transition is associated with. +*/ +QEvent::Type QBasicMouseEventTransition::eventType() const +{ + Q_D(const QBasicMouseEventTransition); + return d->eventType; +} + +/*! + Sets the event \a type that this mouse event transition is associated with. +*/ +void QBasicMouseEventTransition::setEventType(QEvent::Type type) +{ + Q_D(QBasicMouseEventTransition); + d->eventType = type; +} + +/*! + Returns the button that this mouse event transition checks for. +*/ +Qt::MouseButton QBasicMouseEventTransition::button() const +{ + Q_D(const QBasicMouseEventTransition); + return d->button; +} + +/*! + Sets the button that this mouse event transition will check for. +*/ +void QBasicMouseEventTransition::setButton(Qt::MouseButton button) +{ + Q_D(QBasicMouseEventTransition); + d->button = button; +} + +/*! + Returns the keyboard modifiers mask that this mouse event transition checks + for. +*/ +Qt::KeyboardModifiers QBasicMouseEventTransition::modifiersMask() const +{ + Q_D(const QBasicMouseEventTransition); + return d->modifiersMask; +} + +/*! + Sets the keyboard modifiers mask that this mouse event transition will check + for. +*/ +void QBasicMouseEventTransition::setModifiersMask(Qt::KeyboardModifiers modifiersMask) +{ + Q_D(QBasicMouseEventTransition); + d->modifiersMask = modifiersMask; +} + +/*! + Returns the path for this mouse event transition. +*/ +QPainterPath QBasicMouseEventTransition::path() const +{ + Q_D(const QBasicMouseEventTransition); + return d->path; +} + +/*! + Sets the path for this mouse event transition. +*/ +void QBasicMouseEventTransition::setPath(const QPainterPath &path) +{ + Q_D(QBasicMouseEventTransition); + d->path = path; +} + +/*! + \reimp +*/ +bool QBasicMouseEventTransition::eventTest(QEvent *event) +{ + Q_D(const QBasicMouseEventTransition); + if (event->type() == d->eventType) { + QMouseEvent *me = static_cast<QMouseEvent*>(event); + return (me->button() == d->button) + && ((me->modifiers() & d->modifiersMask) == d->modifiersMask) + && (d->path.isEmpty() || d->path.contains(me->pos())); + } + return false; +} + +/*! + \reimp +*/ +void QBasicMouseEventTransition::onTransition(QEvent *) +{ +} + +QT_END_NAMESPACE diff --git a/src/gui/statemachine/qbasicmouseeventtransition_p.h b/src/gui/statemachine/qbasicmouseeventtransition_p.h new file mode 100644 index 0000000..6c0afe4 --- /dev/null +++ b/src/gui/statemachine/qbasicmouseeventtransition_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBASICMOUSEEVENTTRANSITION_P_H +#define QBASICMOUSEEVENTTRANSITION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qabstracttransition.h> +#include <QtGui/qevent.h> + +QT_BEGIN_NAMESPACE + +class QPainterPath; + +class QBasicMouseEventTransitionPrivate; +class Q_AUTOTEST_EXPORT QBasicMouseEventTransition : public QAbstractTransition +{ + Q_OBJECT +public: + QBasicMouseEventTransition(QState *sourceState = 0); + QBasicMouseEventTransition(QEvent::Type type, Qt::MouseButton button, + QState *sourceState = 0); + ~QBasicMouseEventTransition(); + + QEvent::Type eventType() const; + void setEventType(QEvent::Type type); + + Qt::MouseButton button() const; + void setButton(Qt::MouseButton button); + + Qt::KeyboardModifiers modifiersMask() const; + void setModifiersMask(Qt::KeyboardModifiers modifiers); + + QPainterPath path() const; + void setPath(const QPainterPath &path); + +protected: + bool eventTest(QEvent *event); + void onTransition(QEvent *); + +private: + Q_DISABLE_COPY(QBasicMouseEventTransition) + Q_DECLARE_PRIVATE(QBasicMouseEventTransition) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/gui/statemachine/qguistatemachine.cpp b/src/gui/statemachine/qguistatemachine.cpp new file mode 100644 index 0000000..612e43e --- /dev/null +++ b/src/gui/statemachine/qguistatemachine.cpp @@ -0,0 +1,559 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qstatemachine.h> +#include <private/qstatemachine_p.h> +#include <QtGui/qevent.h> +#include <QtGui/qgraphicssceneevent.h> + +QT_BEGIN_NAMESPACE + +Q_CORE_EXPORT const QStateMachinePrivate::Handler *qcoreStateMachineHandler(); + +static QEvent *cloneEvent(QEvent *e) +{ + switch (e->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + return new QMouseEvent(*static_cast<QMouseEvent*>(e)); + case QEvent::KeyPress: + case QEvent::KeyRelease: + return new QKeyEvent(*static_cast<QKeyEvent*>(e)); + case QEvent::FocusIn: + case QEvent::FocusOut: + return new QFocusEvent(*static_cast<QFocusEvent*>(e)); + case QEvent::Enter: + return new QEvent(*e); + case QEvent::Leave: + return new QEvent(*e); + break; + case QEvent::Paint: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::Move: + return new QMoveEvent(*static_cast<QMoveEvent*>(e)); + case QEvent::Resize: + return new QResizeEvent(*static_cast<QResizeEvent*>(e)); + case QEvent::Create: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::Destroy: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::Show: + return new QShowEvent(*static_cast<QShowEvent*>(e)); + case QEvent::Hide: + return new QHideEvent(*static_cast<QHideEvent*>(e)); + case QEvent::Close: + return new QCloseEvent(*static_cast<QCloseEvent*>(e)); + case QEvent::Quit: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ParentChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ParentAboutToChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ThreadChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::WindowActivate: + case QEvent::WindowDeactivate: + return new QEvent(*e); + + case QEvent::ShowToParent: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::HideToParent: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::Wheel: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::WindowTitleChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::WindowIconChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ApplicationWindowIconChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ApplicationFontChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ApplicationLayoutDirectionChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ApplicationPaletteChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::PaletteChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::Clipboard: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::Speech: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::MetaCall: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::SockAct: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::WinEventAct: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::DeferredDelete: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::DragEnter: + return new QDragEnterEvent(*static_cast<QDragEnterEvent*>(e)); + case QEvent::DragMove: + return new QDragMoveEvent(*static_cast<QDragMoveEvent*>(e)); + case QEvent::DragLeave: + return new QDragLeaveEvent(*static_cast<QDragLeaveEvent*>(e)); + case QEvent::Drop: + return new QDropEvent(*static_cast<QDragMoveEvent*>(e)); + case QEvent::DragResponse: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ChildAdded: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ChildPolished: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; +#ifdef QT3_SUPPORT + case QEvent::ChildInsertedRequest: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ChildInserted: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::LayoutHint: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; +#endif + case QEvent::ChildRemoved: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ShowWindowRequest: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::PolishRequest: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::Polish: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::LayoutRequest: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::UpdateRequest: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::UpdateLater: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::EmbeddingControl: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ActivateControl: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::DeactivateControl: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ContextMenu: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::InputMethod: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::AccessibilityPrepare: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::TabletMove: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::LocaleChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::LanguageChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::LayoutDirectionChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::Style: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::TabletPress: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::TabletRelease: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::OkRequest: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::HelpRequest: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::IconDrag: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::FontChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::EnabledChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ActivationChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::StyleChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::IconTextChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ModifiedChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::MouseTrackingChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::WindowBlocked: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::WindowUnblocked: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::WindowStateChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::ToolTip: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::WhatsThis: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::StatusTip: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::ActionChanged: + case QEvent::ActionAdded: + case QEvent::ActionRemoved: + return new QActionEvent(*static_cast<QActionEvent*>(e)); + + case QEvent::FileOpen: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::Shortcut: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ShortcutOverride: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + +#ifdef QT3_SUPPORT + case QEvent::Accel: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::AccelAvailable: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; +#endif + + case QEvent::WhatsThisClicked: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::ToolBarChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::ApplicationActivate: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ApplicationDeactivate: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::QueryWhatsThis: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::EnterWhatsThisMode: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::LeaveWhatsThisMode: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::ZOrderChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::HoverEnter: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::HoverLeave: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::HoverMove: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::AccessibilityHelp: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::AccessibilityDescription: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + +#ifdef QT_KEYPAD_NAVIGATION + case QEvent::EnterEditFocus: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::LeaveEditFocus: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; +#endif + case QEvent::AcceptDropsChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::MenubarUpdated: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::ZeroTimerEvent: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::GraphicsSceneMouseMove: + case QEvent::GraphicsSceneMousePress: + case QEvent::GraphicsSceneMouseRelease: + case QEvent::GraphicsSceneMouseDoubleClick: { + QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent*>(e); + QGraphicsSceneMouseEvent *me2 = new QGraphicsSceneMouseEvent(me->type()); + me2->setWidget(me->widget()); + me2->setPos(me->pos()); + me2->setScenePos(me->scenePos()); + me2->setScreenPos(me->screenPos()); +// ### for all buttons + me2->setButtonDownPos(Qt::LeftButton, me->buttonDownPos(Qt::LeftButton)); + me2->setButtonDownPos(Qt::RightButton, me->buttonDownPos(Qt::RightButton)); + me2->setButtonDownScreenPos(Qt::LeftButton, me->buttonDownScreenPos(Qt::LeftButton)); + me2->setButtonDownScreenPos(Qt::RightButton, me->buttonDownScreenPos(Qt::RightButton)); + me2->setLastPos(me->lastPos()); + me2->setLastScenePos(me->lastScenePos()); + me2->setLastScreenPos(me->lastScreenPos()); + me2->setButtons(me->buttons()); + me2->setButton(me->button()); + me2->setModifiers(me->modifiers()); + return me2; + } + + case QEvent::GraphicsSceneContextMenu: { + QGraphicsSceneContextMenuEvent *me = static_cast<QGraphicsSceneContextMenuEvent*>(e); + QGraphicsSceneContextMenuEvent *me2 = new QGraphicsSceneContextMenuEvent(me->type()); + me2->setWidget(me->widget()); + me2->setPos(me->pos()); + me2->setScenePos(me->scenePos()); + me2->setScreenPos(me->screenPos()); + me2->setModifiers(me->modifiers()); + me2->setReason(me->reason()); + return me2; + } + + case QEvent::GraphicsSceneHoverEnter: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::GraphicsSceneHoverMove: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::GraphicsSceneHoverLeave: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::GraphicsSceneHelp: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::GraphicsSceneDragEnter: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::GraphicsSceneDragMove: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::GraphicsSceneDragLeave: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::GraphicsSceneDrop: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::GraphicsSceneWheel: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::KeyboardLayoutChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::DynamicPropertyChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::TabletEnterProximity: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::TabletLeaveProximity: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::NonClientAreaMouseMove: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::NonClientAreaMouseButtonPress: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::NonClientAreaMouseButtonRelease: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::NonClientAreaMouseButtonDblClick: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::MacSizeChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::ContentsRectChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::MacGLWindowChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::FutureCallOut: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::GraphicsSceneResize: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::GraphicsSceneMove: { + QGraphicsSceneMoveEvent *me = static_cast<QGraphicsSceneMoveEvent*>(e); + QGraphicsSceneMoveEvent *me2 = new QGraphicsSceneMoveEvent(); + me2->setWidget(me->widget()); + me2->setNewPos(me->newPos()); + me2->setOldPos(me->oldPos()); + return me2; + } + + case QEvent::CursorChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + case QEvent::ToolTipChange: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::NetworkReplyUpdated: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + + case QEvent::GrabMouse: + case QEvent::UngrabMouse: + case QEvent::GrabKeyboard: + case QEvent::UngrabKeyboard: + return new QEvent(*e); + +#ifdef QT_MAC_USE_COCOA + case QEvent::CocoaRequestModal: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; +#endif + case QEvent::User: + case QEvent::MaxUser: + Q_ASSERT_X(false, "cloneEvent()", "not implemented"); + break; + default: + ; + } + return qcoreStateMachineHandler()->cloneEvent(e); +} + +const QStateMachinePrivate::Handler qt_gui_statemachine_handler = { + cloneEvent +}; + +static const QStateMachinePrivate::Handler *qt_guistatemachine_last_handler = 0; +int qRegisterGuiStateMachine() +{ + qt_guistatemachine_last_handler = QStateMachinePrivate::handler; + QStateMachinePrivate::handler = &qt_gui_statemachine_handler; + return 1; +} +Q_CONSTRUCTOR_FUNCTION(qRegisterGuiStateMachine) + +int qUnregisterGuiStateMachine() +{ + QStateMachinePrivate::handler = qt_guistatemachine_last_handler; + return 1; +} +Q_DESTRUCTOR_FUNCTION(qUnregisterGuiStateMachine) + +QT_END_NAMESPACE diff --git a/src/gui/statemachine/qkeyeventtransition.cpp b/src/gui/statemachine/qkeyeventtransition.cpp new file mode 100644 index 0000000..f803711 --- /dev/null +++ b/src/gui/statemachine/qkeyeventtransition.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qkeyeventtransition.h" +#include "qbasickeyeventtransition_p.h" +#include <QtCore/qwrappedevent.h> +#include <private/qeventtransition_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QKeyEventTransition + + \brief The QKeyEventTransition class provides a transition for key events. + + \since 4.6 + \ingroup statemachine + + QKeyEventTransition is part of \l{The State Machine Framework}. + + \sa QState::addTransition() +*/ + +/*! + \property QKeyEventTransition::key + + \brief the key that this key event transition is associated with +*/ + +/*! + \property QKeyEventTransition::modifiersMask + + \brief the keyboard modifiers mask that this key event transition checks for +*/ + +class QKeyEventTransitionPrivate : public QEventTransitionPrivate +{ + Q_DECLARE_PUBLIC(QKeyEventTransition) +public: + QKeyEventTransitionPrivate() {} + + QBasicKeyEventTransition *transition; +}; + +/*! + Constructs a new key event transition with the given \a sourceState. +*/ +QKeyEventTransition::QKeyEventTransition(QState *sourceState) + : QEventTransition(*new QKeyEventTransitionPrivate, sourceState) +{ + Q_D(QKeyEventTransition); + d->transition = new QBasicKeyEventTransition(); +} + +/*! + Constructs a new key event transition for events of the given \a type for + the given \a object, with the given \a key and \a sourceState. +*/ +QKeyEventTransition::QKeyEventTransition(QObject *object, QEvent::Type type, + int key, QState *sourceState) + : QEventTransition(*new QKeyEventTransitionPrivate, object, type, sourceState) +{ + Q_D(QKeyEventTransition); + d->transition = new QBasicKeyEventTransition(type, key); +} + +/*! + Constructs a new key event transition for events of the given \a type for + the given \a object, with the given \a key, \a targets and \a sourceState. +*/ +QKeyEventTransition::QKeyEventTransition(QObject *object, QEvent::Type type, + int key, const QList<QAbstractState*> &targets, + QState *sourceState) + : QEventTransition(*new QKeyEventTransitionPrivate, object, type, targets, sourceState) +{ + Q_D(QKeyEventTransition); + d->transition = new QBasicKeyEventTransition(type, key); +} + +/*! + Destroys this key event transition. +*/ +QKeyEventTransition::~QKeyEventTransition() +{ + Q_D(QKeyEventTransition); + delete d->transition; +} + +/*! + Returns the key that this key event transition checks for. +*/ +int QKeyEventTransition::key() const +{ + Q_D(const QKeyEventTransition); + return d->transition->key(); +} + +/*! + Sets the key that this key event transition will check for. +*/ +void QKeyEventTransition::setKey(int key) +{ + Q_D(QKeyEventTransition); + d->transition->setKey(key); +} + +/*! + Returns the keyboard modifiers mask that this key event transition checks + for. +*/ +Qt::KeyboardModifiers QKeyEventTransition::modifiersMask() const +{ + Q_D(const QKeyEventTransition); + return d->transition->modifiersMask(); +} + +/*! + Sets the keyboard \a modifiers mask that this key event transition will + check for. +*/ +void QKeyEventTransition::setModifiersMask(Qt::KeyboardModifiers modifiersMask) +{ + Q_D(QKeyEventTransition); + d->transition->setModifiersMask(modifiersMask); +} + +/*! + \reimp +*/ +bool QKeyEventTransition::eventTest(QEvent *event) +{ + Q_D(const QKeyEventTransition); + if (!QEventTransition::eventTest(event)) + return false; + QWrappedEvent *we = static_cast<QWrappedEvent*>(event); + d->transition->setEventType(we->event()->type()); + return QAbstractTransitionPrivate::get(d->transition)->callEventTest(we->event()); +} + +/*! + \reimp +*/ +void QKeyEventTransition::onTransition(QEvent *event) +{ + QEventTransition::onTransition(event); +} + +QT_END_NAMESPACE diff --git a/src/gui/statemachine/qkeyeventtransition.h b/src/gui/statemachine/qkeyeventtransition.h new file mode 100644 index 0000000..3c8295f --- /dev/null +++ b/src/gui/statemachine/qkeyeventtransition.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QKEYEVENTTRANSITION_H +#define QKEYEVENTTRANSITION_H + +#include <QtCore/qeventtransition.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QKeyEventTransitionPrivate; +class Q_GUI_EXPORT QKeyEventTransition : public QEventTransition +{ + Q_OBJECT + Q_PROPERTY(int key READ key WRITE setKey) + Q_PROPERTY(Qt::KeyboardModifiers modifiersMask READ modifiersMask WRITE setModifiersMask) +public: + QKeyEventTransition(QState *sourceState = 0); + QKeyEventTransition(QObject *object, QEvent::Type type, int key, + QState *sourceState = 0); + QKeyEventTransition(QObject *object, QEvent::Type type, int key, + const QList<QAbstractState*> &targets, + QState *sourceState = 0); + ~QKeyEventTransition(); + + int key() const; + void setKey(int key); + + Qt::KeyboardModifiers modifiersMask() const; + void setModifiersMask(Qt::KeyboardModifiers modifiers); + +protected: + void onTransition(QEvent *event); + bool eventTest(QEvent *event); + +private: + Q_DISABLE_COPY(QKeyEventTransition) + Q_DECLARE_PRIVATE(QKeyEventTransition) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/gui/statemachine/qmouseeventtransition.cpp b/src/gui/statemachine/qmouseeventtransition.cpp new file mode 100644 index 0000000..e4e18eb --- /dev/null +++ b/src/gui/statemachine/qmouseeventtransition.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmouseeventtransition.h" +#include "qbasicmouseeventtransition_p.h" +#include <QtCore/qwrappedevent.h> +#include <QtGui/qpainterpath.h> +#include <private/qeventtransition_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMouseEventTransition + + \brief The QMouseEventTransition class provides a transition for mouse events. + + \since 4.6 + \ingroup statemachine + + QMouseEventTransition is part of \l{The State Machine Framework}. + + \sa QState::addTransition() +*/ + +/*! + \property QMouseEventTransition::button + + \brief the button that this mouse event transition is associated with +*/ + +/*! + \property QMouseEventTransition::modifiersMask + + \brief the keyboard modifiers mask that this mouse event transition checks for +*/ + +class QMouseEventTransitionPrivate : public QEventTransitionPrivate +{ + Q_DECLARE_PUBLIC(QMouseEventTransition) +public: + QMouseEventTransitionPrivate(); + + QBasicMouseEventTransition *transition; +}; + +QMouseEventTransitionPrivate::QMouseEventTransitionPrivate() +{ +} + +/*! + Constructs a new mouse event transition with the given \a sourceState. +*/ +QMouseEventTransition::QMouseEventTransition(QState *sourceState) + : QEventTransition(*new QMouseEventTransitionPrivate, sourceState) +{ + Q_D(QMouseEventTransition); + d->transition = new QBasicMouseEventTransition(); +} + +/*! + Constructs a new mouse event transition for events of the given \a type for + the given \a object, with the given \a button and \a sourceState. +*/ +QMouseEventTransition::QMouseEventTransition(QObject *object, QEvent::Type type, + Qt::MouseButton button, + QState *sourceState) + : QEventTransition(*new QMouseEventTransitionPrivate, object, type, sourceState) +{ + Q_D(QMouseEventTransition); + d->transition = new QBasicMouseEventTransition(type, button); +} + +/*! + Constructs a new mouse event transition for events of the given \a type for + the given \a object, with the given \a button, \a targets and \a + sourceState. +*/ +QMouseEventTransition::QMouseEventTransition(QObject *object, QEvent::Type type, + Qt::MouseButton button, + const QList<QAbstractState*> &targets, + QState *sourceState) + : QEventTransition(*new QMouseEventTransitionPrivate, object, type, targets, sourceState) +{ + Q_D(QMouseEventTransition); + d->transition = new QBasicMouseEventTransition(type, button); +} + +/*! + Destroys this mouse event transition. +*/ +QMouseEventTransition::~QMouseEventTransition() +{ + Q_D(QMouseEventTransition); + delete d->transition; +} + +/*! + Returns the button that this mouse event transition checks for. +*/ +Qt::MouseButton QMouseEventTransition::button() const +{ + Q_D(const QMouseEventTransition); + return d->transition->button(); +} + +/*! + Sets the \a button that this mouse event transition will check for. +*/ +void QMouseEventTransition::setButton(Qt::MouseButton button) +{ + Q_D(QMouseEventTransition); + d->transition->setButton(button); +} + +/*! + Returns the keyboard modifiers mask that this mouse event transition checks + for. +*/ +Qt::KeyboardModifiers QMouseEventTransition::modifiersMask() const +{ + Q_D(const QMouseEventTransition); + return d->transition->modifiersMask(); +} + +/*! + Sets the keyboard \a modifiers mask that this mouse event transition will + check for. +*/ +void QMouseEventTransition::setModifiersMask(Qt::KeyboardModifiers modifiersMask) +{ + Q_D(QMouseEventTransition); + d->transition->setModifiersMask(modifiersMask); +} + +/*! + Returns the path for this mouse event transition. +*/ +QPainterPath QMouseEventTransition::path() const +{ + Q_D(const QMouseEventTransition); + return d->transition->path(); +} + +/*! + Sets the \a path for this mouse event transition. + If a valid path has been set, the transition will only trigger if the mouse + event position (QMouseEvent::pos()) is inside the path. + + \sa QPainterPath::contains() +*/ +void QMouseEventTransition::setPath(const QPainterPath &path) +{ + Q_D(QMouseEventTransition); + d->transition->setPath(path); +} + +/*! + \reimp +*/ +bool QMouseEventTransition::eventTest(QEvent *event) +{ + Q_D(const QMouseEventTransition); + if (!QEventTransition::eventTest(event)) + return false; + QWrappedEvent *we = static_cast<QWrappedEvent*>(event); + d->transition->setEventType(we->event()->type()); + return QAbstractTransitionPrivate::get(d->transition)->callEventTest(we->event()); +} + +/*! + \reimp +*/ +void QMouseEventTransition::onTransition(QEvent *event) +{ + QEventTransition::onTransition(event); +} + +QT_END_NAMESPACE diff --git a/src/gui/statemachine/qmouseeventtransition.h b/src/gui/statemachine/qmouseeventtransition.h new file mode 100644 index 0000000..3f5f3ac --- /dev/null +++ b/src/gui/statemachine/qmouseeventtransition.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMOUSEEVENTTRANSITION_H +#define QMOUSEEVENTTRANSITION_H + +#include <QtCore/qeventtransition.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QMouseEventTransitionPrivate; +class QPainterPath; +class Q_GUI_EXPORT QMouseEventTransition : public QEventTransition +{ + Q_OBJECT + Q_PROPERTY(Qt::MouseButton button READ button WRITE setButton) + Q_PROPERTY(Qt::KeyboardModifiers modifiersMask READ modifiersMask WRITE setModifiersMask) +public: + QMouseEventTransition(QState *sourceState = 0); + QMouseEventTransition(QObject *object, QEvent::Type type, + Qt::MouseButton button, QState *sourceState = 0); + QMouseEventTransition(QObject *object, QEvent::Type type, + Qt::MouseButton button, + const QList<QAbstractState*> &targets, + QState *sourceState = 0); + ~QMouseEventTransition(); + + Qt::MouseButton button() const; + void setButton(Qt::MouseButton button); + + Qt::KeyboardModifiers modifiersMask() const; + void setModifiersMask(Qt::KeyboardModifiers modifiers); + + QPainterPath path() const; + void setPath(const QPainterPath &path); + +protected: + void onTransition(QEvent *event); + bool eventTest(QEvent *event); + +private: + Q_DISABLE_COPY(QMouseEventTransition) + Q_DECLARE_PRIVATE(QMouseEventTransition) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/gui/statemachine/statemachine.pri b/src/gui/statemachine/statemachine.pri new file mode 100644 index 0000000..2eb1e05 --- /dev/null +++ b/src/gui/statemachine/statemachine.pri @@ -0,0 +1,13 @@ +SOURCES += $$PWD/qguistatemachine.cpp +!contains(DEFINES, QT_NO_STATEMACHINE_EVENTFILTER) { + HEADERS += \ + $$PWD/qkeyeventtransition.h \ + $$PWD/qmouseeventtransition.h \ + $$PWD/qbasickeyeventtransition_p.h \ + $$PWD/qbasicmouseeventtransition_p.h + SOURCES += \ + $$PWD/qkeyeventtransition.cpp \ + $$PWD/qmouseeventtransition.cpp \ + $$PWD/qbasickeyeventtransition.cpp \ + $$PWD/qbasicmouseeventtransition.cpp +} diff --git a/src/gui/styles/gtksymbols.cpp b/src/gui/styles/gtksymbols.cpp index 99d7261..f92fd0e 100644 --- a/src/gui/styles/gtksymbols.cpp +++ b/src/gui/styles/gtksymbols.cpp @@ -374,8 +374,8 @@ static QString getThemeName() while(!in.atEnd()) { QString line = in.readLine(); if (line.contains(QLS("gtk-theme-name"))) { - line = line.right(line.length() - line.indexOf(QLS("=")) - 1); - line.remove(QLS("\"")); + line = line.right(line.length() - line.indexOf(QLatin1Char('=')) - 1); + line.remove(QLatin1Char('\"')); line = line.trimmed(); themeName = line; break; @@ -633,31 +633,14 @@ GtkStyle* QGtk::gtkStyle(const QString &path) return 0; } -#ifdef Q_OS_LINUX -QT_END_NAMESPACE - -int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); -int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); - -QT_BEGIN_NAMESPACE -#endif - void QGtk::initGtkWidgets() { // From gtkmain.c - - uid_t ruid, rgid, euid, egid, suid, sgid; - -#ifdef Q_OS_LINUX - if (getresuid (&ruid, &euid, &suid) != 0 || getresgid (&rgid, &egid, &sgid) != 0) -#endif - { - suid = ruid = getuid (); - sgid = rgid = getgid (); - euid = geteuid (); - egid = getegid (); - } - if (ruid != euid || ruid != suid || rgid != egid || rgid != sgid) { + uid_t ruid = getuid (); + uid_t rgid = getgid (); + uid_t euid = geteuid (); + uid_t egid = getegid (); + if (ruid != euid || rgid != egid) { qWarning("\nThis process is currently running setuid or setgid.\nGTK+ does not allow this " "therefore Qt cannot use the GTK+ integration.\nTry launching your app using \'gksudo\', " "\'kdesudo\' or a similar tool.\n\n" @@ -712,7 +695,7 @@ void QGtk::initGtkWidgets() QHashIterator<QString, GtkWidget*> it(oldMap); while (it.hasNext()) { it.next(); - if (!it.key().contains(QLS("."))) { + if (!it.key().contains(QLatin1Char('.'))) { add_all_sub_widgets(it.value()); } } diff --git a/src/gui/styles/qcleanlooksstyle.cpp b/src/gui/styles/qcleanlooksstyle.cpp index 3fb63f2..5c37794 100644 --- a/src/gui/styles/qcleanlooksstyle.cpp +++ b/src/gui/styles/qcleanlooksstyle.cpp @@ -1646,8 +1646,8 @@ void QCleanlooksStyle::drawControl(ControlElement element, const QStyleOption *o if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { QPixmap cache; QString pixmapName = QStyleHelper::uniqueName(QLatin1String("headersection"), option, option->rect.size()); - pixmapName += QLatin1String("-") + QString::number(int(header->position)); - pixmapName += QLatin1String("-") + QString::number(int(header->orientation)); + pixmapName += QString::number(- int(header->position)); + pixmapName += QString::number(- int(header->orientation)); QRect r = option->rect; QColor gradientStopColor; QColor gradientStartColor = option->palette.button().color(); @@ -3858,7 +3858,7 @@ void QCleanlooksStyle::polish(QApplication *app) dataDirs = QLatin1String("/usr/local/share/:/usr/share/"); dataDirs.prepend(QDir::homePath() + QLatin1String("/:")); - d->iconDirs = dataDirs.split(QLatin1String(":")); + d->iconDirs = dataDirs.split(QLatin1Char(':')); #endif } diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index f8ae1a6..1285598 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -851,7 +851,7 @@ void QCommonStylePrivate::lookupIconTheme() const dataDirs.prepend(QDir::homePath() + QLatin1String("/:")); QStringList kdeDirs = QString::fromLocal8Bit(getenv("KDEDIRS")).split(QLatin1Char(':')); foreach (const QString &dirName, kdeDirs) - dataDirs.append(QLatin1String(":") + dirName + QLatin1String("/share")); + dataDirs.append(QLatin1Char(':') + dirName + QLatin1String("/share")); iconDirs = dataDirs.split(QLatin1Char(':')); QFileInfo fileInfo(QLatin1String("/usr/share/icons/default.kde")); @@ -893,7 +893,7 @@ QIconTheme QCommonStylePrivate::parseIndexFile(const QString &themeName) const parents = line.split(QLatin1Char(',')); } - if (line.startsWith(QLatin1String("["))) { + if (line.startsWith(QLatin1Char('['))) { line = line.trimmed(); line.chop(1); QString dirName = line.right(line.length() - 1); @@ -1664,6 +1664,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, if (!styleHint(SH_UnderlineShortcut, opt, widget)) alignment |= Qt::TextHideMnemonic; rect.translate(shiftX, shiftY); + p->setFont(toolbutton->font); drawItemText(p, rect, alignment, toolbutton->palette, opt->state & State_Enabled, toolbutton->text, QPalette::ButtonText); @@ -1694,7 +1695,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) { pr.setHeight(pmSize.height() + 6); - tr.adjust(0, pr.height(), 0, -3); + tr.adjust(0, pr.height() - 1, 0, -3); pr.translate(shiftX, shiftY); if (!hasArrow) { drawItemPixmap(p, pr, Qt::AlignCenter, pm); @@ -1780,46 +1781,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, case CE_TabBarTab: if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) { drawControl(CE_TabBarTabShape, tab, p, widget); - - QStyleOptionTabV3 tabV3(*tab); - QRect labelRect = tabV3.rect; - QSize &left= tabV3.leftButtonSize; - QSize &right = tabV3.rightButtonSize; - const int spacing = 6 + 2; - - // left widget - if (!left.isEmpty()) { - if (tabV3.shape == QTabBar::RoundedEast || tabV3.shape == QTabBar::TriangularEast ) - labelRect.setTop(labelRect.top() + spacing + left.height()); - else if (tabV3.shape == QTabBar::RoundedWest|| tabV3.shape == QTabBar::TriangularWest) - labelRect.setBottom(labelRect.bottom() - spacing - left.height()); - else - labelRect.setLeft(labelRect.left() + spacing + left.width()); - } - - // right widget - if (!right.isEmpty()) { - if (tabV3.shape == QTabBar::RoundedEast || tabV3.shape == QTabBar::TriangularEast ) - labelRect.setBottom(labelRect.bottom() - spacing - right.height()); - else if (tabV3.shape == QTabBar::RoundedWest|| tabV3.shape == QTabBar::TriangularWest) - labelRect.setTop(labelRect.top() + spacing + right.height()); - else - labelRect.setRight(labelRect.right() - spacing - right.width()); - } - - tabV3.rect = visualRect(opt->direction, opt->rect, labelRect); - drawControl(CE_TabBarTabLabel, &tabV3, p, widget); - if (tabV3.state & State_HasFocus) { - const int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth); - int x1, x2; - x1 = tab->rect.left(); - x2 = tab->rect.right() - 1; - QStyleOptionFocusRect fropt; - fropt.QStyleOption::operator=(*tab); - fropt.rect.setRect(x1 + 1 + OFFSET, tab->rect.y() + OFFSET, - x2 - x1 - 2*OFFSET, tab->rect.height() - 2*OFFSET); - drawPrimitive(PE_FrameFocusRect, &fropt, p, widget); - } + drawControl(CE_TabBarTabLabel, tab, p, widget); } break; case CE_TabBarTabShape: @@ -2023,8 +1985,12 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, (tabV2.state & State_Selected) ? QIcon::On : QIcon::Off); - int offset = 6; + int offset = 4; int left = opt->rect.left(); + if (tabV2.leftButtonSize.isEmpty()) + offset += 2; + else + left += tabV2.leftButtonSize.width() + (6 + 2) + 2; QRect iconRect = QRect(left + offset, tr.center().y() - tabIcon.height() / 2, tabIconSize.width(), tabIconSize.height()); if (!verticalTabs) @@ -2035,6 +2001,20 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, drawItemText(p, tr, alignment, tab->palette, tab->state & State_Enabled, tab->text, QPalette::WindowText); if (verticalTabs) p->restore(); + + if (tabV2.state & State_HasFocus) { + const int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth); + + int x1, x2; + x1 = tabV2.rect.left(); + x2 = tabV2.rect.right() - 1; + + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*tab); + fropt.rect.setRect(x1 + 1 + OFFSET, tabV2.rect.y() + OFFSET, + x2 - x1 - 2*OFFSET, tabV2.rect.height() - 2*OFFSET); + drawPrimitive(PE_FrameFocusRect, &fropt, p, widget); + } } break; #endif // QT_NO_TABBAR @@ -2873,15 +2853,23 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, tr.setRect(0, 0, tr.height(), tr.width()); int verticalShift = pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget); int horizontalShift = pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget); + int hpadding = pixelMetric(QStyle::PM_TabBarTabHSpace, opt, widget) / 2; + int vpadding = pixelMetric(QStyle::PM_TabBarTabVSpace, opt, widget) / 2; if (tabV2.shape == QTabBar::RoundedSouth || tabV2.shape == QTabBar::TriangularSouth) verticalShift = -verticalShift; - tr.adjust(0, 0, horizontalShift, verticalShift); + tr.adjust(hpadding, vpadding, horizontalShift - hpadding, verticalShift - vpadding); bool selected = tabV2.state & State_Selected; if (selected) { tr.setBottom(tr.bottom() - verticalShift); tr.setRight(tr.right() - horizontalShift); } + // left widget + if (!tabV2.leftButtonSize.isEmpty()) { + tr.setLeft(tr.left() + 6 + 2 + + (verticalTabs ? tabV2.leftButtonSize.height() : tabV2.leftButtonSize.width())); + } + // icon if (!tabV2.icon.isNull()) { QSize iconSize = tabV2.iconSize; @@ -2903,6 +2891,12 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, tr.setLeft(tr.left() + tabIconSize.width() + offset + 2); } + // right widget + if (!tabV2.rightButtonSize.isEmpty()) { + tr.setRight(tr.right() - 6 - 2 - + (verticalTabs ? tabV2.rightButtonSize.height() : tabV2.rightButtonSize.width())); + } + if (!verticalTabs) tr = visualRect(opt->direction, opt->rect, tr); r = tr; @@ -3194,6 +3188,25 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, } break; #endif //QT_NO_ITEMVIEWS +#ifndef QT_NO_TOOLBAR + case SE_ToolBarHandle: + if (const QStyleOptionToolBar *tbopt = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) { + if (tbopt->features & QStyleOptionToolBar::Movable) { + ///we need to access the widget here because the style option doesn't + //have all the information we need (ie. the layout's margin) + const QToolBar *tb = qobject_cast<const QToolBar*>(widget); + const int margin = tb && tb->layout() ? tb->layout()->margin() : 2; + const int handleExtent = pixelMetric(QStyle::PM_ToolBarExtensionExtent, opt, tb); + if (tbopt->state & QStyle::State_Horizontal) { + r = QRect(margin, margin, handleExtent, tbopt->rect.height() - 2*margin); + r = QStyle::visualRect(tbopt->direction, tbopt->rect, r); + } else { + r = QRect(margin, margin, tbopt->rect.width() - 2*margin, handleExtent); + } + } + } + break; +#endif //QT_NO_TOOLBAR default: break; } diff --git a/src/gui/styles/qgtkstyle.cpp b/src/gui/styles/qgtkstyle.cpp index ca71da2..151dab0 100644 --- a/src/gui/styles/qgtkstyle.cpp +++ b/src/gui/styles/qgtkstyle.cpp @@ -140,10 +140,7 @@ static const char * const dock_widget_restore_xpm[] = class QGtkStyleFilter : public QObject { public: - QGtkStyleFilter() { - qApp->installEventFilter(this); - } - + QGtkStyleFilter() {} private: bool eventFilter(QObject *obj, QEvent *e); }; @@ -167,7 +164,12 @@ class QGtkStylePrivate : public QCleanlooksStylePrivate public: QGtkStylePrivate() : QCleanlooksStylePrivate() - {} + { + QGtk::initGtkWidgets(); + if (QGtk::isThemeAvailable()) + qApp->installEventFilter(&filter); + + } QGtkStyleFilter filter; }; @@ -243,7 +245,6 @@ static QString uniqueName(const QString &key, const QStyleOption *option, const QGtkStyle::QGtkStyle() : QCleanlooksStyle(*new QGtkStylePrivate) { - QGtk::initGtkWidgets(); } /*! @@ -939,10 +940,6 @@ void QGtkStyle::drawPrimitive(PrimitiveElement element, case PE_FrameLineEdit: { GtkWidget *gtkEntry = QGtk::gtkWidget(QLS("GtkEntry")); - if (option->state & State_HasFocus) - GTK_WIDGET_SET_FLAGS(gtkEntry, GTK_HAS_FOCUS); - else - GTK_WIDGET_UNSET_FLAGS(gtkEntry, GTK_HAS_FOCUS); gboolean interior_focus; gint focus_line_width; @@ -956,6 +953,9 @@ void QGtkStyle::drawPrimitive(PrimitiveElement element, if (!interior_focus && option->state & State_HasFocus) rect.adjust(focus_line_width, focus_line_width, -focus_line_width, -focus_line_width); + + if (option->state & State_HasFocus) + GTK_WIDGET_SET_FLAGS(gtkEntry, GTK_HAS_FOCUS); gtkPainter.paintShadow(gtkEntry, "entry", rect, option->state & State_Enabled ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE, GTK_SHADOW_IN, gtkEntry->style, @@ -964,6 +964,9 @@ void QGtkStyle::drawPrimitive(PrimitiveElement element, gtkPainter.paintShadow(gtkEntry, "entry", option->rect, option->state & State_Enabled ? GTK_STATE_ACTIVE : GTK_STATE_INSENSITIVE, GTK_SHADOW_IN, gtkEntry->style, QLS("GtkEntryShadowIn")); + + if (option->state & State_HasFocus) + GTK_WIDGET_UNSET_FLAGS(gtkEntry, GTK_HAS_FOCUS); } break; @@ -1049,17 +1052,13 @@ void QGtkStyle::drawPrimitive(PrimitiveElement element, GTK_WIDGET_SET_FLAGS(gtkButton, GTK_HAS_DEFAULT); gtkPainter.paintBox(gtkButton, "buttondefault", buttonRect, state, GTK_SHADOW_IN, style, isDefault ? QLS("d") : QString()); - } else - GTK_WIDGET_UNSET_FLAGS(gtkButton, GTK_HAS_DEFAULT); + } bool hasFocus = option->state & State_HasFocus; if (hasFocus) { key += QLS("def"); GTK_WIDGET_SET_FLAGS(gtkButton, GTK_HAS_FOCUS); - - } else { - GTK_WIDGET_UNSET_FLAGS(gtkButton, GTK_HAS_FOCUS); } if (!interiorFocus) @@ -1070,6 +1069,10 @@ void QGtkStyle::drawPrimitive(PrimitiveElement element, gtkPainter.paintBox(gtkButton, "button", buttonRect, state, shadow, style, key); + if (isDefault) + GTK_WIDGET_UNSET_FLAGS(gtkButton, GTK_HAS_DEFAULT); + if (hasFocus) + GTK_WIDGET_UNSET_FLAGS(gtkButton, GTK_HAS_FOCUS); } break; @@ -1333,6 +1336,8 @@ void QGtkStyle::drawComplexControl(ComplexControl control, const QStyleOptionCom GtkWidget *gtkToggleButton = QGtk::gtkWidget(buttonPath); QGtk::gtk_widget_set_direction(gtkToggleButton, reverse ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR); if (gtkToggleButton && (appears_as_list || comboBox->editable)) { + if (focus) + GTK_WIDGET_SET_FLAGS(gtkToggleButton, GTK_HAS_FOCUS); // Draw the combo box as a line edit with a button next to it if (comboBox->editable || appears_as_list) { GtkStateType frameState = (state == GTK_STATE_PRELIGHT) ? GTK_STATE_NORMAL : state; @@ -1346,22 +1351,16 @@ void QGtkStyle::drawComplexControl(ComplexControl control, const QStyleOptionCom else frameRect.setRight(arrowButtonRect.left()); - // Required for inner blue highlight with clearlooks - if (focus) { - GTK_WIDGET_SET_FLAGS(gtkEntry, GTK_HAS_FOCUS); - GTK_WIDGET_SET_FLAGS(gtkToggleButton, GTK_HAS_FOCUS); - - } else { - GTK_WIDGET_UNSET_FLAGS(gtkEntry, GTK_HAS_FOCUS); - GTK_WIDGET_UNSET_FLAGS(gtkToggleButton, GTK_HAS_FOCUS); - } - // Fill the line edit background // We could have used flat_box with "entry_bg" but that is probably not worth the overhead uint resolve_mask = option->palette.resolve(); int xt = gtkEntry->style->xthickness; int yt = gtkEntry->style->ythickness; QRect contentRect = frameRect.adjusted(xt, yt, -xt, -yt); + // Required for inner blue highlight with clearlooks + if (focus) + GTK_WIDGET_SET_FLAGS(gtkEntry, GTK_HAS_FOCUS); + if (widget && widget->testAttribute(Qt::WA_SetPalette) && resolve_mask & (1 << QPalette::Base)) // Palette overridden by user p->fillRect(contentRect, option->palette.base().color()); @@ -1375,6 +1374,8 @@ void QGtkStyle::drawComplexControl(ComplexControl control, const QStyleOptionCom GTK_SHADOW_IN, gtkEntry->style, entryPath + QString::number(focus) + QString::number(comboBox->editable) + QString::number(option->direction)); + if (focus) + GTK_WIDGET_UNSET_FLAGS(gtkEntry, GTK_HAS_FOCUS); } GtkStateType buttonState = GTK_STATE_NORMAL; @@ -1393,22 +1394,21 @@ void QGtkStyle::drawComplexControl(ComplexControl control, const QStyleOptionCom gtkCachedPainter.paintBox( gtkToggleButton, "button", arrowButtonRect, buttonState, shadow, gtkToggleButton->style, buttonPath + QString::number(focus) + QString::number(option->direction)); - + if (focus) + GTK_WIDGET_UNSET_FLAGS(gtkToggleButton, GTK_HAS_FOCUS); } else { // Draw combo box as a button QRect buttonRect = option->rect; - if (focus) { // Clearlooks actually check the widget for the default state + if (focus) // Clearlooks actually check the widget for the default state GTK_WIDGET_SET_FLAGS(gtkToggleButton, GTK_HAS_FOCUS); - - } else { - GTK_WIDGET_UNSET_FLAGS(gtkToggleButton, GTK_HAS_FOCUS); - } - gtkCachedPainter.paintBox(gtkToggleButton, "button", buttonRect, state, shadow, gtkToggleButton->style, buttonPath + QString::number(focus)); + if (focus) + GTK_WIDGET_UNSET_FLAGS(gtkToggleButton, GTK_HAS_FOCUS); + // Draw the separator between label and arrows QString vSeparatorPath = buttonPath + QLS(".GtkHBox.GtkVSeparator"); @@ -1774,15 +1774,13 @@ void QGtkStyle::drawComplexControl(ComplexControl control, const QStyleOptionCom shadow = GTK_SHADOW_IN; style = gtkPainter.getStyle(gtkSpinButton); - if (option->state & State_HasFocus) - GTK_WIDGET_SET_FLAGS(gtkSpinButton, GTK_HAS_FOCUS); - else - GTK_WIDGET_UNSET_FLAGS(gtkSpinButton, GTK_HAS_FOCUS); QString key; - if (option->state & State_HasFocus) - key = QLS("f"); + if (option->state & State_HasFocus) { + key += QLatin1Char('f'); + GTK_WIDGET_SET_FLAGS(gtkSpinButton, GTK_HAS_FOCUS); + } uint resolve_mask = option->palette.resolve(); @@ -1815,6 +1813,9 @@ void QGtkStyle::drawComplexControl(ComplexControl control, const QStyleOptionCom gtkPainter.paintBox( gtkSpinButton, "spinbutton_down", downRect, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, style, key); else gtkPainter.paintBox( gtkSpinButton, "spinbutton_down", downRect, GTK_STATE_NORMAL, GTK_SHADOW_OUT, style, key); + + if (option->state & State_HasFocus) + GTK_WIDGET_UNSET_FLAGS(gtkSpinButton, GTK_HAS_FOCUS); } if (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) { @@ -2343,7 +2344,7 @@ void QGtkStyle::drawControl(ControlElement element, case CE_SizeGrip: { GtkWidget *gtkStatusbar = QGtk::gtkWidget(QLS("GtkStatusbar.GtkFrame")); QRect gripRect = option->rect.adjusted(0, 0, -gtkStatusbar->style->xthickness, -gtkStatusbar->style->ythickness); - gtkPainter.paintResizeGrip( gtkStatusbar, "window", gripRect, GTK_STATE_NORMAL, + gtkPainter.paintResizeGrip( gtkStatusbar, "statusbar", gripRect, GTK_STATE_NORMAL, GTK_SHADOW_OUT, QApplication::isRightToLeft() ? GDK_WINDOW_EDGE_SOUTH_WEST : GDK_WINDOW_EDGE_SOUTH_EAST, gtkStatusbar->style); diff --git a/src/gui/styles/qmacstyle_mac.mm b/src/gui/styles/qmacstyle_mac.mm index 2558625..2478f20 100644 --- a/src/gui/styles/qmacstyle_mac.mm +++ b/src/gui/styles/qmacstyle_mac.mm @@ -39,6 +39,11 @@ ** ****************************************************************************/ +/* + Note: The qdoc comments for QMacStyle are contained in + .../doc/src/qstyles.qdoc. +*/ + #include "qmacstyle_mac.h" #if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) @@ -564,7 +569,6 @@ extern QPaintDevice *qt_mac_safe_pdev; //qapplication_mac.cpp QMacCGStyle globals *****************************************************************************/ const int qt_mac_hitheme_version = 0; //the HITheme version we speak -const int macSpinBoxSep = 5; // distance between spinwidget and the lineedit const int macItemFrame = 2; // menu item frame width const int macItemHMargin = 3; // menu item hor text margin const int macItemVMargin = 2; // menu item ver text margin @@ -2004,87 +2008,12 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD p->drawPixmap(int(macRect.origin.x), int(macRect.origin.y) + finalyoff, width, height, pm); } -/*! - \class QMacStyle - \brief The QMacStyle class provides a Mac OS X style using the Apple Appearance Manager. - - \ingroup appearance - - This class is implemented as a wrapper to the HITheme - APIs, allowing applications to be styled according to the current - theme in use on Mac OS X. This is done by having primitives - in QStyle implemented in terms of what Mac OS X would normally theme. - - \warning This style is only available on Mac OS X because it relies on the - HITheme APIs. - - There are additional issues that should be taken - into consideration to make an application compatible with the - \link http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/index.html - Apple Human Interface Guidelines \endlink. Some of these issues are outlined - below. - - \list - - \i Layout - The restrictions on window layout are such that some - aspects of layout that are style-dependent cannot be achieved - using QLayout. Changes are being considered (and feedback would be - appreciated) to make layouts QStyle-able. Some of the restrictions - involve horizontal and vertical widget alignment and widget size - (covered below). - - \i Widget size - Mac OS X allows widgets to have specific fixed sizes. Qt - does not fully implement this behavior so as to maintain cross-platform - compatibility. As a result some widgets sizes may be inappropriate (and - subsequently not rendered correctly by the HITheme APIs).The - QWidget::sizeHint() will return the appropriate size for many - managed widgets (widgets enumerated in \l QStyle::ContentsType). - - \i Effects - QMacStyle uses HITheme for performing most of the drawing, but - also uses emulation in a few cases where HITheme does not provide the - required functionality (for example, tab bars on Panther, the toolbar - separator, etc). We tried to make the emulation as close to the original as - possible. Please report any issues you see in effects or non-standard - widgets. - - \endlist - - There are other issues that need to be considered in the feel of - your application (including the general color scheme to match the - Aqua colors). The Guidelines mentioned above will remain current - with new advances and design suggestions for Mac OS X. - - Note that the functions provided by QMacStyle are - reimplementations of QStyle functions; see QStyle for their - documentation. - - \img qmacstyle.png - \sa QWindowsXPStyle, QWindowsStyle, QPlastiqueStyle, QCDEStyle, QMotifStyle -*/ - - -/*! - \enum QMacStyle::WidgetSizePolicy - - \value SizeSmall - \value SizeLarge - \value SizeMini - \value SizeDefault - \omitvalue SizeNone -*/ - -/*! - Constructs a QMacStyle object. -*/ QMacStyle::QMacStyle() : QWindowsStyle() { d = new QMacStylePrivate(this); } -/*! - Destructs a QMacStyle object. -*/ QMacStyle::~QMacStyle() { delete qt_mac_backgroundPattern; @@ -2158,7 +2087,6 @@ void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QPoint } } -/*! \reimp */ void QMacStyle::polish(QPalette &pal) { if (!qt_mac_backgroundPattern) { @@ -2182,17 +2110,14 @@ void QMacStyle::polish(QPalette &pal) } } -/*! \reimp */ void QMacStyle::polish(QApplication *) { } -/*! \reimp */ void QMacStyle::unpolish(QApplication *) { } -/*! \reimp */ void QMacStyle::polish(QWidget* w) { d->addWidget(w); @@ -2256,7 +2181,6 @@ void QMacStyle::polish(QWidget* w) } } -/*! \reimp */ void QMacStyle::unpolish(QWidget* w) { d->removeWidget(w); @@ -2287,7 +2211,6 @@ void QMacStyle::unpolish(QWidget* w) QWindowsStyle::unpolish(w); } -/*! \reimp */ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const { int controlSize = getControlSize(opt, widget); @@ -2391,7 +2314,14 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW break; case PM_SpinBoxFrameWidth: GetThemeMetric(kThemeMetricEditTextFrameOutset, &ret); - ret += 2; + switch (d->aquaSizeConstrain(opt, widget)) { + default: + ret += 2; + break; + case QAquaSizeMini: + ret += 1; + break; + } break; case PM_ButtonShiftHorizontal: case PM_ButtonShiftVertical: @@ -2662,7 +2592,6 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW return ret; } -/*! \reimp */ QPalette QMacStyle::standardPalette() const { QPalette pal = QWindowsStyle::standardPalette(); @@ -2672,7 +2601,6 @@ QPalette QMacStyle::standardPalette() const return pal; } -/*! \reimp */ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w, QStyleHintReturn *hret) const { @@ -2967,7 +2895,6 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w return ret; } -/*! \reimp */ QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const { @@ -2993,7 +2920,6 @@ QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixm } -/*! \reimp */ QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget) const { @@ -3024,31 +2950,7 @@ QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOpt } return icon.pixmap(size, size); } -/*! - \enum QMacStyle::FocusRectPolicy - - This type is used to signify a widget's focus rectangle policy. - \value FocusEnabled show a focus rectangle when the widget has focus. - \value FocusDisabled never show a focus rectangle for the widget. - \value FocusDefault show a focus rectangle when the widget has - focus and the widget is a QSpinWidget, QDateTimeEdit, QLineEdit, - QListBox, QListView, editable QTextEdit, or one of their - subclasses. -*/ - -/*! - \obsolete - Sets the focus rectangle policy of \a w. The \a policy can be one of - \l{QMacStyle::FocusRectPolicy}. - - This is now simply an interface to the Qt::WA_MacShowFocusRect attribute and the - FocusDefault value does nothing anymore. If you want to set a widget back - to its default value, you must save the old value of the attribute before - you change it. - - \sa focusRectPolicy() QWidget::setAttribute() -*/ void QMacStyle::setFocusRectPolicy(QWidget *w, FocusRectPolicy policy) { switch (policy) { @@ -3061,29 +2963,11 @@ void QMacStyle::setFocusRectPolicy(QWidget *w, FocusRectPolicy policy) } } -/*! - \obsolete - Returns the focus rectangle policy for the widget \a w. - - The focus rectangle policy can be one of \l{QMacStyle::FocusRectPolicy}. - - In 4.3 and up this function will simply test for the - Qt::WA_MacShowFocusRect attribute and will never return - QMacStyle::FocusDefault. - - \sa setFocusRectPolicy(), QWidget::testAttribute() -*/ QMacStyle::FocusRectPolicy QMacStyle::focusRectPolicy(const QWidget *w) { return w->testAttribute(Qt::WA_MacShowFocusRect) ? FocusEnabled : FocusDisabled; } -/*! - \obsolete - - Call QWidget::setAttribute() with Qt::WA_MacMiniSize, Qt::WA_MacSmallSize, - or Qt::WA_MacNormalSize instead. -*/ void QMacStyle::setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy policy) { QWidget *wadget = const_cast<QWidget *>(widget); @@ -3092,12 +2976,6 @@ void QMacStyle::setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy poli wadget->setAttribute(Qt::WA_MacMiniSize, policy == SizeMini); } -/*! - \obsolete - - Call QWidget::testAttribute() with Qt::WA_MacMiniSize, Qt::WA_MacSmallSize, - or Qt::WA_MacNormalSize instead. -*/ QMacStyle::WidgetSizePolicy QMacStyle::widgetSizePolicy(const QWidget *widget) { while (widget) { @@ -3113,7 +2991,6 @@ QMacStyle::WidgetSizePolicy QMacStyle::widgetSizePolicy(const QWidget *widget) return SizeDefault; } -/*! \reimp */ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w) const { @@ -3546,7 +3423,6 @@ static inline QPixmap darkenPixmap(const QPixmap &pixmap) -/*! \reimp */ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p, const QWidget *w) const { @@ -4599,7 +4475,7 @@ static void setLayoutItemMargins(int left, int top, int right, int bottom, QRect rect->adjust(left, top, right, bottom); } } -/*! \reimp */ + QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, const QWidget *widget) const { @@ -4893,7 +4769,6 @@ static inline void drawToolbarButtonArrow(const QRect &toolButtonRect, ThemeDraw HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal); } -/*! \reimp */ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *widget) const { @@ -5064,11 +4939,10 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex bdi.kind = kThemeIncDecButton; break; case QAquaSizeMini: + bdi.kind = kThemeIncDecButtonMini; + break; case QAquaSizeSmall: - if (aquaSize == QAquaSizeMini) - bdi.kind = kThemeIncDecButtonMini; - else - bdi.kind = kThemeIncDecButtonSmall; + bdi.kind = kThemeIncDecButtonSmall; break; } if (!(sb->stepEnabled & (QAbstractSpinBox::StepUpEnabled @@ -5088,8 +4962,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex bdi.value = kThemeButtonOff; bdi.adornment = kThemeAdornmentNone; - QRect updown = subControlRect(CC_SpinBox, sb, SC_SpinBoxUp, - widget); + QRect updown = subControlRect(CC_SpinBox, sb, SC_SpinBoxUp, widget); + updown |= subControlRect(CC_SpinBox, sb, SC_SpinBoxDown, widget); HIRect newRect = qt_hirectForQRect(updown); QRect off_rct; @@ -5100,15 +4974,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex int(outRect.size.width - newRect.size.width), int(outRect.size.height - newRect.size.height)); - // HIThemeGetButtonBackgroundBounds offsets non-focused normal sized - // buttons by one in de y direction, account for that here. - if (bdi.adornment == kThemeAdornmentNone && bdi.kind == kThemeIncDecButton) - off_rct.adjust(0, 1, 0, 0); - - // Adjust the rect for small buttos also. - if (bdi.adornment == kThemeAdornmentFocus && bdi.kind == kThemeIncDecButtonSmall) - off_rct.adjust(0, 0, 0, -1); - newRect = qt_hirectForQRect(updown, off_rct); HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0); } @@ -5278,7 +5143,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) { if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) { -// p->fillRect(tb->rect, QColor(155, 0, 155, 155)); if (tb->subControls & SC_ToolButtonMenu) { QStyleOption arrowOpt(0); arrowOpt.rect = subControlRect(cc, tb, SC_ToolButtonMenu, widget); @@ -5287,7 +5151,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex arrowOpt.state = tb->state; arrowOpt.palette = tb->palette; drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget); - } else if (tb->features & QStyleOptionToolButton::HasMenu) { + } else if ((tb->features & QStyleOptionToolButton::HasMenu) + && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) { drawToolbarButtonArrow(tb->rect, tds, cg); } if (tb->state & State_On) { @@ -5411,7 +5276,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex } } -/*! \reimp */ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt, const QWidget *widget) const @@ -5542,7 +5406,6 @@ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc, return sc; } -/*! \reimp */ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget) const { @@ -5784,39 +5647,61 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op break; case CC_SpinBox: if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) { - const int spinner_w = 14, - fw = pixelMetric(PM_SpinBoxFrameWidth, spin, widget); + QAquaWidgetSize aquaSize = d->aquaSizeConstrain(spin, widget); + int spinner_w; + int spinBoxSep; + int fw = pixelMetric(PM_SpinBoxFrameWidth, spin, widget); + switch (aquaSize) { + default: + case QAquaSizeUnknown: + case QAquaSizeLarge: + spinner_w = 14; + spinBoxSep = 2; + break; + case QAquaSizeSmall: + spinner_w = 12; + spinBoxSep = 2; + break; + case QAquaSizeMini: + spinner_w = 10; + spinBoxSep = 1; + break; + } + switch (sc) { case SC_SpinBoxUp: case SC_SpinBoxDown: { if (spin->buttonSymbols == QAbstractSpinBox::NoButtons) break; - const int frameWidth = pixelMetric(PM_SpinBoxFrameWidth, spin, widget); - const int spinner_w = 18; - const int y = frameWidth; - const int x = spin->rect.width() - spinner_w + frameWidth; + + const int y = fw; + const int x = spin->rect.width() - spinner_w; ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spin->rect.height() - y * 2); HIThemeButtonDrawInfo bdi; bdi.version = qt_mac_hitheme_version; bdi.kind = kThemeIncDecButton; - QAquaWidgetSize aquaSize = d->aquaSizeConstrain(opt, widget); + int hackTranslateX; switch (aquaSize) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - bdi.kind = kThemeIncDecButton; - break; - case QAquaSizeMini: - case QAquaSizeSmall: - if (aquaSize == QAquaSizeMini) - bdi.kind = kThemeIncDecButtonMini; - else - bdi.kind = kThemeIncDecButtonSmall; - break; + default: + case QAquaSizeUnknown: + case QAquaSizeLarge: + bdi.kind = kThemeIncDecButton; + hackTranslateX = 0; + break; + case QAquaSizeSmall: + bdi.kind = kThemeIncDecButtonSmall; + hackTranslateX = -2; + break; + case QAquaSizeMini: + bdi.kind = kThemeIncDecButtonMini; + hackTranslateX = -1; + break; } bdi.state = kThemeStateActive; bdi.value = kThemeButtonOff; bdi.adornment = kThemeAdornmentNone; HIRect hirect = qt_hirectForQRect(ret); + HIRect outRect; HIThemeGetButtonBackgroundBounds(&hirect, &bdi, &outRect); ret = qt_qrectForHIRect(outRect); @@ -5831,13 +5716,13 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op Q_ASSERT(0); break; } - ret.translate(-1, -2); // hack: position the buttons correctly (weird that we need this) + ret.translate(hackTranslateX, 0); // hack: position the buttons correctly (weird that we need this) ret = visualRect(spin->direction, spin->rect, ret); break; } case SC_SpinBoxEditField: ret.setRect(fw, fw, - spin->rect.width() - spinner_w - fw * 2 - macSpinBoxSep + 1, + spin->rect.width() - spinner_w - fw * 2 - spinBoxSep, spin->rect.height() - fw * 2); ret = visualRect(spin->direction, spin->rect, ret); break; @@ -5860,7 +5745,6 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op return ret; } -/*! \reimp */ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &csz, const QWidget *widget) const { @@ -5869,8 +5753,8 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, switch (ct) { case QStyle::CT_SpinBox: - sz.setWidth(sz.width() + macSpinBoxSep); - sz.setHeight(sz.height() - 3); // hack to work around horrible sizeHint() code in QAbstractSpinBox + // hack to work around horrible sizeHint() code in QAbstractSpinBox + sz.setHeight(sz.height() - 3); break; case QStyle::CT_TabBarTab: if (const QStyleOptionTabV3 *tab = qstyleoption_cast<const QStyleOptionTabV3 *>(opt)) { @@ -6155,9 +6039,6 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, return sz; } -/*! - \reimp -*/ void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal, bool enabled, const QString &text, QPalette::ColorRole textRole) const { @@ -6166,9 +6047,6 @@ void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPale QWindowsStyle::drawItemText(p, r, flags, pal, enabled, text, textRole); } -/*! - \reimp -*/ bool QMacStyle::event(QEvent *e) { if(e->type() == QEvent::FocusIn) { @@ -6243,9 +6121,6 @@ void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayI } } -/*! - \internal -*/ QIcon QMacStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *opt, const QWidget *widget) const { @@ -6359,9 +6234,6 @@ QIcon QMacStyle::standardIconImplementation(StandardPixmap standardIcon, const Q return QWindowsStyle::standardIconImplementation(standardIcon, opt, widget); } -/*! - \internal -*/ int QMacStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, diff --git a/src/gui/styles/qmotifstyle.cpp b/src/gui/styles/qmotifstyle.cpp index 7d4fab8..be0e3eb 100644 --- a/src/gui/styles/qmotifstyle.cpp +++ b/src/gui/styles/qmotifstyle.cpp @@ -2026,10 +2026,6 @@ QMotifStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, QSize sz(contentsSize); switch(ct) { - case CT_Splitter: - sz = QSize(10, 10); - break; - case CT_RadioButton: case CT_CheckBox: sz = QCommonStyle::sizeFromContents(ct, opt, contentsSize, widget); diff --git a/src/gui/styles/qplastiquestyle.cpp b/src/gui/styles/qplastiquestyle.cpp index 66464ff..91ad64e 100644 --- a/src/gui/styles/qplastiquestyle.cpp +++ b/src/gui/styles/qplastiquestyle.cpp @@ -2845,8 +2845,8 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { QPixmap cache; QString pixmapName = uniqueName(QLatin1String("headersection"), option, option->rect.size()); - pixmapName += QLatin1String("-") + QString::number(int(header->position)); - pixmapName += QLatin1String("-") + QString::number(int(header->orientation)); + pixmapName += QString::number(- int(header->position)); + pixmapName += QString::number(- int(header->orientation)); if (!UsePixmapCache || !QPixmapCache::find(pixmapName, cache)) { cache = QPixmap(option->rect.size()); @@ -5460,6 +5460,11 @@ int QPlastiqueStyle::styleHint(StyleHint hint, const QStyleOption *option, const case SH_Menu_SubMenuPopupDelay: ret = 96; // from Plastik break; +#ifndef Q_OS_WIN + case SH_Menu_AllowActiveAndDisabled: + ret = false; + break; +#endif default: ret = QWindowsStyle::styleHint(hint, option, widget, returnData); break; diff --git a/src/gui/styles/qstyle.cpp b/src/gui/styles/qstyle.cpp index 982f48f..3fab682 100644 --- a/src/gui/styles/qstyle.cpp +++ b/src/gui/styles/qstyle.cpp @@ -1048,6 +1048,8 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value SE_TabBarTabRightButton Area for a widget on the right side of a tab in a tab bar. \value SE_TabBarTabText Area for the text on a tab in a tab bar. + \value SE_ToolBarHandle Area for the handle of a tool bar. + \sa subElementRect() */ @@ -1330,7 +1332,7 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value PM_LayoutVerticalSpacing Default \l{QLayout::spacing}{vertical spacing} for a QLayout. \value PM_MaximumDragDistance The maximum allowed distance between - the mouse and a slider when dragging. Exceeding the specified + the mouse and a scrollbar when dragging. Exceeding the specified distance will cause the slider to jump back to the original position; a value of -1 disables this behavior. @@ -2437,7 +2439,7 @@ QDebug operator<<(QDebug debug, QStyle::State state) qSort(states); debug << states.join(QLatin1String(" | ")); - debug << ")"; + debug << ')'; return debug; } #endif diff --git a/src/gui/styles/qstyle.h b/src/gui/styles/qstyle.h index c1cbbdd..cc92459 100644 --- a/src/gui/styles/qstyle.h +++ b/src/gui/styles/qstyle.h @@ -373,6 +373,8 @@ public: SE_ShapedFrameContents, + SE_ToolBarHandle, + // do not add any values below/greater than this SE_CustomBase = 0xf0000000 }; diff --git a/src/gui/styles/qstylehelper_p.h b/src/gui/styles/qstylehelper_p.h index 711bd2d..5385d9f 100644 --- a/src/gui/styles/qstylehelper_p.h +++ b/src/gui/styles/qstylehelper_p.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include <QtCore/qglobal.h> #include <QtCore/qpoint.h> #include <QtGui/qpolygon.h> diff --git a/src/gui/styles/qstyleoption.cpp b/src/gui/styles/qstyleoption.cpp index ce053ae..e441101 100644 --- a/src/gui/styles/qstyleoption.cpp +++ b/src/gui/styles/qstyleoption.cpp @@ -48,6 +48,7 @@ #ifndef QT_NO_DEBUG #include <qdebug.h> #endif +#include <QtCore/qmath.h> QT_BEGIN_NAMESPACE @@ -4998,6 +4999,34 @@ QStyleOptionGraphicsItem::QStyleOptionGraphicsItem(int version) } /*! + \since 4.6 + + Returns the level of detail from the \a worldTransform. + + Its value represents the maximum value of the height and + width of a unity rectangle, mapped using the \a worldTransform + of the painter used to draw the item. By default, if no + transformations are applied, its value is 1. If zoomed out 1:2, the level + of detail will be 0.5, and if zoomed in 2:1, its value is 2. + + For more advanced level-of-detail metrics, use + QStyleOptionGraphicsItem::matrix directly. + + \sa QStyleOptionGraphicsItem::matrix +*/ +qreal QStyleOptionGraphicsItem::levelOfDetailFromTransform(const QTransform &worldTransform) +{ + if (worldTransform.type() <= QTransform::TxTranslate) + return 1; // Translation only? The LOD is 1. + + // Two unit vectors. + QLineF v1(0, 0, 1, 0); + QLineF v2(0, 0, 0, 1); + // LOD is the transformed area of a 1x1 rectangle. + return qSqrt(worldTransform.map(v1).length() * worldTransform.map(v2).length()); +} + +/*! \fn QStyleOptionGraphicsItem::QStyleOptionGraphicsItem(const QStyleOptionGraphicsItem &other) Constructs a copy of \a other. @@ -5029,19 +5058,10 @@ QStyleOptionGraphicsItem::QStyleOptionGraphicsItem(int version) /*! \variable QStyleOptionGraphicsItem::levelOfDetail - \brief a simple metric for determining an item's level of detail - - This simple metric provides an easy way to determine the level of detail - for an item. Its value represents the maximum value of the height and - width of a unity rectangle, mapped using the complete transformation - matrix of the painter used to draw the item. By default, if no - transformations are applied, its value is 1. If zoomed out 1:2, the level - of detail will be 0.5, and if zoomed in 2:1, its value is 2. - - For more advanced level-of-detail metrics, use - QStyleOptionGraphicsItem::matrix directly. + \obsolete - \sa QStyleOptionGraphicsItem::matrix + Use QStyleOptionGraphicsItem::levelOfDetailFromTransform + together with QPainter::worldTransform() instead. */ /*! @@ -5342,10 +5362,10 @@ QDebug operator<<(QDebug debug, const QStyleOption &option) { debug << "QStyleOption("; debug << QStyleOption::OptionType(option.type); - debug << "," << (option.direction == Qt::RightToLeft ? "RightToLeft" : "LeftToRight"); - debug << "," << option.state; - debug << "," << option.rect; - debug << ")"; + debug << ',' << (option.direction == Qt::RightToLeft ? "RightToLeft" : "LeftToRight"); + debug << ',' << option.state; + debug << ',' << option.rect; + debug << ')'; return debug; } #endif diff --git a/src/gui/styles/qstyleoption.h b/src/gui/styles/qstyleoption.h index 5759a05..eb05324 100644 --- a/src/gui/styles/qstyleoption.h +++ b/src/gui/styles/qstyleoption.h @@ -856,6 +856,7 @@ public: QStyleOptionGraphicsItem(); QStyleOptionGraphicsItem(const QStyleOptionGraphicsItem &other) : QStyleOption(Version, Type) { *this = other; } + static qreal levelOfDetailFromTransform(const QTransform &worldTransform); protected: QStyleOptionGraphicsItem(int version); }; diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index ebddfd5..9a8f97e 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -1555,7 +1555,7 @@ QVector<QCss::StyleRule> QStyleSheetStyle::styleRules(const QWidget *w) const if (widCacheIt == styleSheetCache->constEnd()) { parser.init(wid->styleSheet()); if (!parser.parse(&ss)) { - parser.init(QLatin1String("* {") + wid->styleSheet() + QLatin1String("}")); + parser.init(QLatin1String("* {") + wid->styleSheet() + QLatin1Char('}')); if (!parser.parse(&ss)) qWarning("Could not parse stylesheet of widget %p", wid); } @@ -2702,14 +2702,10 @@ void QStyleSheetStyle::polish(QWidget *w) QRenderRule rule = renderRule(sa, PseudoElement_None, PseudoClass_Enabled); if ((rule.hasBorder() && rule.border()->hasBorderImage()) || (rule.hasBackground() && !rule.background()->pixmap.isNull())) { - QObject::disconnect(sa->horizontalScrollBar(), SIGNAL(valueChanged(int)), - sa, SLOT(update())); - QObject::disconnect(sa->verticalScrollBar(), SIGNAL(valueChanged(int)), - sa, SLOT(update())); QObject::connect(sa->horizontalScrollBar(), SIGNAL(valueChanged(int)), - sa, SLOT(update())); + sa, SLOT(update()), Qt::UniqueConnection); QObject::connect(sa->verticalScrollBar(), SIGNAL(valueChanged(int)), - sa, SLOT(update())); + sa, SLOT(update()), Qt::UniqueConnection); } } #endif @@ -3030,6 +3026,7 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC if (const QStyleOptionToolButton *tool = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) { QStyleOptionToolButton toolOpt(*tool); rule.configurePalette(&toolOpt.palette, QPalette::ButtonText, QPalette::Button); + toolOpt.font = rule.font.resolve(toolOpt.font); toolOpt.rect = rule.borderRect(opt->rect); bool customArrow = (tool->features & (QStyleOptionToolButton::HasMenu | QStyleOptionToolButton::MenuButtonPopup)); bool customDropDown = tool->features & QStyleOptionToolButton::MenuButtonPopup; @@ -4758,7 +4755,7 @@ QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *op case CT_LineEdit: #ifndef QT_NO_SPINBOX // ### hopelessly broken QAbstractSpinBox (part 2) - if (QAbstractSpinBox *spinBox = qobject_cast<QAbstractSpinBox *>(w->parentWidget())) { + if (QAbstractSpinBox *spinBox = qobject_cast<QAbstractSpinBox *>(w ? w->parentWidget() : 0)) { QRenderRule rule = renderRule(spinBox, opt); if (rule.hasBox() || !rule.hasNativeBorder()) return csz; @@ -4805,13 +4802,10 @@ QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *op if ((pe == PseudoElement_MenuSeparator) && subRule.hasContentsSize()) { return QSize(sz.width(), subRule.size().height()); } else if ((pe == PseudoElement_Item) && (subRule.hasBox() || subRule.hasBorder())) { - int width = csz.width(), height = qMax(csz.height(), mi->fontMetrics.height()); - if (!mi->icon.isNull()) { - int iconExtent = pixelMetric(PM_SmallIconSize); - height = qMax(height, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height()); - } - width += mi->tabWidth; - return subRule.boxSize(csz.expandedTo(subRule.minimumContentsSize())); + int width = csz.width(); + if (mi->text.contains(QLatin1Char('\t'))) + width += 12; //as in QCommonStyle + return subRule.boxSize(subRule.adjustSize(QSize(width, csz.height()))); } } break; @@ -5084,9 +5078,12 @@ int QStyleSheetStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWi #ifndef QT_NO_COMBOBOX if (qobject_cast<const QComboBox *>(w)) { QAbstractItemView *view = qFindChild<QAbstractItemView *>(w); - QRenderRule subRule = renderRule(view, PseudoElement_None); - if (subRule.hasBox() || !subRule.hasNativeBorder()) - return QFrame::NoFrame; + if (view) { + view->ensurePolished(); + QRenderRule subRule = renderRule(view, PseudoElement_None); + if (subRule.hasBox() || !subRule.hasNativeBorder()) + return QFrame::NoFrame; + } } #endif // QT_NO_COMBOBOX break; diff --git a/src/gui/styles/qwindowsxpstyle.cpp b/src/gui/styles/qwindowsxpstyle.cpp index 639eff0..3dac9f5 100644 --- a/src/gui/styles/qwindowsxpstyle.cpp +++ b/src/gui/styles/qwindowsxpstyle.cpp @@ -1792,7 +1792,12 @@ case PE_Frame: return; case PE_IndicatorToolBarSeparator: - + if (option->rect.height() < 3) { + // XP style requires a few pixels for the separator + // to be visible. + QWindowsStyle::drawPrimitive(pe, option, p, widget); + return; + } name = QLatin1String("TOOLBAR"); partId = TP_SEPARATOR; diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index db1e781..0494b72 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -278,19 +278,15 @@ static const QCssKnownValue values[NumKnownValues - 1] = { { "xx-large", Value_XXLarge } }; +//Map id to strings as they appears in the 'values' array above +static const int indexOfId[NumKnownValues] = { 0, 40, 47, 41, 48, 53, 34, 26, 68, 69, 25, 42, 5, 62, 46, + 29, 57, 58, 27, 50, 60, 6, 10, 38, 55, 19, 13, 17, 18, 20, 21, 49, 24, 45, 65, 36, 3, 2, 39, 61, 16, + 11, 56, 14, 32, 63, 54, 64, 33, 67, 8, 28, 37, 12, 35, 59, 7, 9, 4, 66, 52, 22, 23, 30, 31, 1, 15, 0, + 51, 44, 43 }; + QString Value::toString() const { - static int indexOfId[NumKnownValues - 1]; - static bool hasCachedIndexes = false; - if (type == KnownIdentifier) { - if (!hasCachedIndexes) { - for (int i = 0; i < NumKnownValues - 1; ++i) - indexOfId[values[i].id] = i; - - hasCachedIndexes = true; - } - return QLatin1String(values[indexOfId[variant.toInt()]].name); } else { return variant.toString(); @@ -1165,13 +1161,20 @@ static bool setFontWeightFromValue(const Value &value, QFont *font) return true; } -static bool setFontFamilyFromValues(const QVector<Value> &values, QFont *font) +/** \internal + * parse the font family from the values (starting from index \a start) + * and set it the \a font + * \returns true if a family was extracted. + */ +static bool setFontFamilyFromValues(const QVector<Value> &values, QFont *font, int start = 0) { QString family; - for (int i = 0; i < values.count(); ++i) { + for (int i = start; i < values.count(); ++i) { const Value &v = values.at(i); - if (v.type == Value::TermOperatorComma) - break; + if (v.type == Value::TermOperatorComma) { + family += QLatin1Char(','); + continue; + } const QString str = v.variant.toString(); if (str.isEmpty()) break; @@ -1225,9 +1228,7 @@ static void parseShorthandFontProperty(const QVector<Value> &values, QFont *font } if (i < values.count()) { - QString fam = values.at(i).variant.toString(); - if (!fam.isEmpty()) - font->setFamily(fam); + setFontFamilyFromValues(values, font, i); } } @@ -1507,7 +1508,7 @@ QRect Declaration::rectValue() const QStringList func = v.variant.toStringList(); if (func.count() != 2 || func.at(0).compare(QLatin1String("rect")) != 0) return QRect(); - QStringList args = func[1].split(QLatin1String(" "), QString::SkipEmptyParts); + QStringList args = func[1].split(QLatin1Char(' '), QString::SkipEmptyParts); if (args.count() != 4) return QRect(); QRect rect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()); @@ -2152,7 +2153,7 @@ void Parser::init(const QString &css, bool isFile) if (isFile) { QFile file(css); if (file.open(QFile::ReadOnly)) { - sourcePath = QFileInfo(styleSheet).absolutePath() + QLatin1String("/"); + sourcePath = QFileInfo(styleSheet).absolutePath() + QLatin1Char('/'); QTextStream stream(&file); styleSheet = stream.readAll(); } else { diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h index 97a0aef..72bd637 100644 --- a/src/gui/text/qcssparser_p.h +++ b/src/gui/text/qcssparser_p.h @@ -403,7 +403,7 @@ struct BorderData { // 4. QVector<Declaration> - { prop1: value1; prop2: value2; } // 5. Declaration - prop1: value1; -struct Q_GUI_EXPORT Declaration +struct Q_AUTOTEST_EXPORT Declaration { struct DeclarationData : public QSharedData { @@ -495,7 +495,7 @@ const quint64 PseudoClass_Alternate = Q_UINT64_C(0x0000100000000000); const quint64 PseudoClass_Any = Q_UINT64_C(0x0000ffffffffffff); const int NumPseudos = 46; -struct Q_GUI_EXPORT Pseudo +struct Pseudo { Pseudo() : negated(false) { } quint64 type; @@ -504,7 +504,7 @@ struct Q_GUI_EXPORT Pseudo bool negated; }; -struct Q_GUI_EXPORT AttributeSelector +struct AttributeSelector { enum ValueMatchType { NoMatch, @@ -519,7 +519,7 @@ struct Q_GUI_EXPORT AttributeSelector ValueMatchType valueMatchCriterium; }; -struct Q_GUI_EXPORT BasicSelector +struct BasicSelector { inline BasicSelector() : relationToNext(NoRelation) {} @@ -539,7 +539,7 @@ struct Q_GUI_EXPORT BasicSelector Relation relationToNext; }; -struct Q_GUI_EXPORT Selector +struct Q_AUTOTEST_EXPORT Selector { QVector<BasicSelector> basicSelectors; int specificity() const; @@ -552,7 +552,7 @@ struct MediaRule; struct PageRule; struct ImportRule; -struct Q_GUI_EXPORT ValueExtractor +struct Q_AUTOTEST_EXPORT ValueExtractor { ValueExtractor(const QVector<Declaration> &declarations, const QPalette & = QPalette()); @@ -586,7 +586,7 @@ private: QPalette pal; }; -struct Q_GUI_EXPORT StyleRule +struct StyleRule { StyleRule() : order(0) { } QVector<Selector> selectors; @@ -594,19 +594,19 @@ struct Q_GUI_EXPORT StyleRule int order; }; -struct Q_GUI_EXPORT MediaRule +struct MediaRule { QStringList media; QVector<StyleRule> styleRules; }; -struct Q_GUI_EXPORT PageRule +struct PageRule { QString selector; QVector<Declaration> declarations; }; -struct Q_GUI_EXPORT ImportRule +struct ImportRule { QString href; QStringList media; @@ -620,7 +620,7 @@ enum StyleSheetOrigin { StyleSheetOrigin_Inline }; -struct Q_GUI_EXPORT StyleSheet +struct StyleSheet { StyleSheet() : origin(StyleSheetOrigin_Unspecified), depth(0) { } QVector<StyleRule> styleRules; //only contains rules that are not indexed diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 24ff10b..c5096bf 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -913,7 +913,7 @@ void QFont::setPointSize(int pointSize) void QFont::setPointSizeF(qreal pointSize) { if (pointSize <= 0) { - qWarning("QFont::setPointSizeF: Point size <= 0 (%d), must be greater than 0", pointSize); + qWarning("QFont::setPointSizeF: Point size <= 0 (%f), must be greater than 0", pointSize); return; } @@ -1897,6 +1897,20 @@ void QFont::insertSubstitutions(const QString &familyName, } } +/*! \fn void QFont::initialize() + \internal + + Internal function that initializes the font system. The font cache + and font dict do not alloc the keys. The key is a QString which is + shared between QFontPrivate and QXFontName. +*/ + +/*! \fn void QFont::cleanup() + \internal + + Internal function that cleans up the font system. +*/ + // ### mark: should be called removeSubstitutions() /*! Removes all the substitutions for \a familyName. diff --git a/src/gui/text/qfont_x11.cpp b/src/gui/text/qfont_x11.cpp index 710792c..6b0e46c 100644 --- a/src/gui/text/qfont_x11.cpp +++ b/src/gui/text/qfont_x11.cpp @@ -129,13 +129,6 @@ Q_GUI_EXPORT void qt_x11_set_fallback_font_family(int script, const QString &fam int QFontPrivate::defaultEncodingID = -1; -/*! - Internal function that initializes the font system. - - \internal - The font cache and font dict do not alloc the keys. The key is a QString - which is shared between QFontPrivate and QXFontName. -*/ void QFont::initialize() { extern int qt_encoding_id_for_mib(int mib); // from qfontdatabase_x11.cpp @@ -184,10 +177,6 @@ void QFont::initialize() QFontPrivate::defaultEncodingID = qt_encoding_id_for_mib(mib); } -/*! \internal - - Internal function that cleans up the font system. -*/ void QFont::cleanup() { QFontCache::cleanup(); diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index c3fc9f5..d3020b0 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -792,7 +792,7 @@ static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDe if (! desc.foundry->name.isEmpty() && desc.family->count > 1) { fontDef->family += QString::fromLatin1(" ["); fontDef->family += desc.foundry->name; - fontDef->family += QString::fromLatin1("]"); + fontDef->family += QLatin1Char(']'); } if (desc.style->smoothScalable) @@ -1495,7 +1495,7 @@ QStringList QFontDatabase::families(WritingSystem writingSystem) const if (!foundry.isEmpty()) { str += QLatin1String(" ["); str += foundry; - str += QLatin1String("]"); + str += QLatin1Char(']'); } flist.append(str); } diff --git a/src/gui/text/qfontdatabase_qws.cpp b/src/gui/text/qfontdatabase_qws.cpp index f62a6d1..9a29de2 100644 --- a/src/gui/text/qfontdatabase_qws.cpp +++ b/src/gui/text/qfontdatabase_qws.cpp @@ -767,8 +767,8 @@ QFontEngine *loadSingleEngine(int script, const QFontPrivate *fp, QString fn = qwsFontPath(); fn += QLatin1Char('/'); fn += family->name.toLower() - + QLatin1String("_") + QString::number(pixelSize*10) - + QLatin1String("_") + QString::number(style->key.weight) + + QLatin1Char('_') + QString::number(pixelSize*10) + + QLatin1Char('_') + QString::number(style->key.weight) + (style->key.style == QFont::StyleItalic ? QLatin1String("i.qpf") : QLatin1String(".qpf")); //###rotation ### diff --git a/src/gui/text/qfontdatabase_x11.cpp b/src/gui/text/qfontdatabase_x11.cpp index 15e626e..605a7dd 100644 --- a/src/gui/text/qfontdatabase_x11.cpp +++ b/src/gui/text/qfontdatabase_x11.cpp @@ -494,7 +494,7 @@ static inline bool isFixedPitch(char **tokens) Fills in a font definition (QFontDef) from an XLFD (X Logical Font Description). - Returns true if the the given xlfd is valid. + Returns true if the given xlfd is valid. */ bool qt_fillFontDef(const QByteArray &xlfd, QFontDef *fd, int dpi, QtFontDesc *desc) { @@ -509,9 +509,9 @@ bool qt_fillFontDef(const QByteArray &xlfd, QFontDef *fd, int dpi, QtFontDesc *d fd->styleStrategy |= QFont::NoAntialias; fd->family = QString::fromLatin1(tokens[Family]); QString foundry = QString::fromLatin1(tokens[Foundry]); - if (! foundry.isEmpty() && foundry != QString::fromLatin1("*") && (!desc || desc->family->count > 1)) + if (! foundry.isEmpty() && foundry != QLatin1String("*") && (!desc || desc->family->count > 1)) fd->family += - QString::fromLatin1(" [") + foundry + QString::fromLatin1("]"); + QLatin1String(" [") + foundry + QLatin1Char(']'); if (qstrlen(tokens[AddStyle]) > 0) fd->addStyle = QString::fromLatin1(tokens[AddStyle]); @@ -1802,30 +1802,30 @@ QFontEngine *QFontDatabase::loadXlfd(int screen, int script, const QFontDef &req QByteArray xlfd("-"); xlfd += desc.foundry->name.isEmpty() ? QByteArray("*") : desc.foundry->name.toLatin1(); - xlfd += "-"; + xlfd += '-'; xlfd += desc.family->name.isEmpty() ? QByteArray("*") : desc.family->name.toLatin1(); - xlfd += "-"; + xlfd += '-'; xlfd += desc.style->weightName ? desc.style->weightName : "*"; - xlfd += "-"; + xlfd += '-'; xlfd += (desc.style->key.style == QFont::StyleItalic - ? "i" - : (desc.style->key.style == QFont::StyleOblique ? "o" : "r")); - xlfd += "-"; + ? 'i' + : (desc.style->key.style == QFont::StyleOblique ? 'o' : 'r')); + xlfd += '-'; xlfd += desc.style->setwidthName ? desc.style->setwidthName : "*"; // ### handle add-style xlfd += "-*-"; xlfd += QByteArray::number(px); - xlfd += "-"; + xlfd += '-'; xlfd += QByteArray::number(desc.encoding->xpoint); - xlfd += "-"; + xlfd += '-'; xlfd += QByteArray::number(desc.encoding->xres); - xlfd += "-"; + xlfd += '-'; xlfd += QByteArray::number(desc.encoding->yres); - xlfd += "-"; + xlfd += '-'; xlfd += desc.encoding->pitch; - xlfd += "-"; + xlfd += '-'; xlfd += QByteArray::number(desc.encoding->avgwidth); - xlfd += "-"; + xlfd += '-'; xlfd += xlfd_for_id(desc.encoding->encoding); FM_DEBUG(" using XLFD: %s\n", xlfd.data()); diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 47fe5c2..6e8adcf 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -624,6 +624,45 @@ QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, int /* margin */, const Q return rgbMask; } +QImage QFontEngine::alphaMapForGlyph(glyph_t glyph) +{ + glyph_metrics_t gm = boundingBox(glyph); + int glyph_x = qFloor(gm.x.toReal()); + int glyph_y = qFloor(gm.y.toReal()); + int glyph_width = qCeil((gm.x + gm.width).toReal()) - glyph_x; + int glyph_height = qCeil((gm.y + gm.height).toReal()) - glyph_y; + + if (glyph_width <= 0 || glyph_height <= 0) + return QImage(); + QFixedPoint pt; + pt.x = 0; + pt.y = -glyph_y; // the baseline + QPainterPath path; + QImage im(glyph_width + qAbs(glyph_x) + 4, glyph_height, QImage::Format_ARGB32_Premultiplied); + im.fill(Qt::transparent); + QPainter p(&im); + p.setRenderHint(QPainter::Antialiasing); + addGlyphsToPath(&glyph, &pt, 1, &path, 0); + p.setPen(Qt::NoPen); + p.setBrush(Qt::black); + p.drawPath(path); + p.end(); + + QImage indexed(im.width(), im.height(), QImage::Format_Indexed8); + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgba(0, 0, 0, i); + indexed.setColorTable(colors); + + for (int y=0; y<im.height(); ++y) { + uchar *dst = (uchar *) indexed.scanLine(y); + uint *src = (uint *) im.scanLine(y); + for (int x=0; x<im.width(); ++x) + dst[x] = qAlpha(src[x]); + } + + return indexed; +} void QFontEngine::removeGlyphFromCache(glyph_t) { @@ -876,7 +915,7 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor) end: qSort(kerning_pairs); // for (int i = 0; i < kerning_pairs.count(); ++i) -// qDebug() << "i" << i << "left_right" << hex << kerning_pairs.at(i).left_right; +// qDebug() << 'i' << i << "left_right" << hex << kerning_pairs.at(i).left_right; } #else @@ -1607,12 +1646,6 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) return allExist; } -QFontEngine *QFontEngineMulti::engine(int at) const -{ - Q_ASSERT(at < engines.size()); - return engines.at(at); -} - QImage QFontEngineMulti::alphaMapForGlyph(glyph_t) { Q_ASSERT(false); diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index cb0b436..a93c391 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -54,8 +54,6 @@ #include <private/qpdf_p.h> #include <private/qharfbuzz_p.h> -#include <private/qpdf_p.h> - #include "qfontengine_ft_p.h" #include <ft2build.h> #include FT_FREETYPE_H @@ -613,7 +611,7 @@ QFontEngineFT::QFontEngineFT(const QFontDef &fd) subpixelType = Subpixel_None; lcdFilterType = 0; #if defined(FT_LCD_FILTER_H) - lcdFilterType = (int) FT_LCD_FILTER_DEFAULT; + lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT); #endif defaultFormat = Format_None; canUploadGlyphsToServer = false; @@ -1521,6 +1519,11 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs return false; } +#if !defined(QT_NO_FONTCONFIG) + extern QMutex *qt_fontdatabase_mutex(); + QMutex *mtx = 0; +#endif + bool mirrored = flags & QTextEngine::RightToLeft; int glyph_pos = 0; if (freetype->symbol_map) { @@ -1533,6 +1536,11 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs if ( !glyphs->glyphs[glyph_pos] ) { glyph_t glyph; #if !defined(QT_NO_FONTCONFIG) + if (!mtx) { + mtx = qt_fontdatabase_mutex(); + mtx->lock(); + } + if (FcCharSetHasChar(freetype->charset, uc)) { #else if (false) { @@ -1561,20 +1569,26 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs if (mirrored) uc = QChar::mirroredChar(uc); glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0; - if (!glyphs->glyphs[glyph_pos] + if (!glyphs->glyphs[glyph_pos]) { #if !defined(QT_NO_FONTCONFIG) - && FcCharSetHasChar(freetype->charset, uc) + if (!mtx) { + mtx = qt_fontdatabase_mutex(); + mtx->lock(); + } + + if (FcCharSetHasChar(freetype->charset, uc)) #endif - ) { - redo: - glyph_t glyph = FT_Get_Char_Index(face, uc); - if (!glyph && (uc == 0xa0 || uc == 0x9)) { - uc = 0x20; - goto redo; + { + redo: + glyph_t glyph = FT_Get_Char_Index(face, uc); + if (!glyph && (uc == 0xa0 || uc == 0x9)) { + uc = 0x20; + goto redo; + } + glyphs->glyphs[glyph_pos] = glyph; + if (uc < QFreetypeFace::cmapCacheSize) + freetype->cmapCache[uc] = glyph; } - glyphs->glyphs[glyph_pos] = glyph; - if (uc < QFreetypeFace::cmapCacheSize) - freetype->cmapCache[uc] = glyph; } ++glyph_pos; } @@ -1583,6 +1597,11 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs *nglyphs = glyph_pos; glyphs->numGlyphs = glyph_pos; +#if !defined(QT_NO_FONTCONFIG) + if (mtx) + mtx->unlock(); +#endif + if (flags & QTextEngine::GlyphIndicesOnly) return true; @@ -1788,9 +1807,11 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g) GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono; - Glyph *glyph = loadGlyph(g, glyph_format); - if (!glyph) - return QImage(); + Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, glyph_format); + if (!glyph) { + unlockFace(); + return QFontEngine::alphaMapForGlyph(g); + } const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4; diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm index 6b5bd0f..2e62086 100644 --- a/src/gui/text/qfontengine_mac.mm +++ b/src/gui/text/qfontengine_mac.mm @@ -553,7 +553,9 @@ QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph) 8, im.bytesPerLine(), colorspace, cgflags); CGContextSetFontSize(ctx, fontDef.pixelSize); - CGContextSetShouldAntialias(ctx, fontDef.pointSize > qt_antialiasing_threshold && !(fontDef.styleStrategy & QFont::NoAntialias)); + CGContextSetShouldAntialias(ctx, fontDef.pointSize > qt_antialiasing_threshold + && !(fontDef.styleStrategy & QFont::NoAntialias)); + CGContextSetShouldSmoothFonts(ctx, false); CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx); CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, 1, 0, 0); diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 8f6b92a..0f8d81c 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -178,7 +178,7 @@ public: * Create a qimage with the alpha values for the glyph. * Returns an image indexed_8 with index values ranging from 0=fully transparant to 255=opaque */ - virtual QImage alphaMapForGlyph(glyph_t) = 0; + virtual QImage alphaMapForGlyph(glyph_t); virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t); virtual QImage alphaRGBMapForGlyph(glyph_t, int margin, const QTransform &t); @@ -353,7 +353,7 @@ private: int _size; }; -class Q_GUI_EXPORT QFontEngineMulti : public QFontEngine +class QFontEngineMulti : public QFontEngine { public: explicit QFontEngineMulti(int engineCount); @@ -389,7 +389,9 @@ public: inline virtual const char *name() const { return "Multi"; } - QFontEngine *engine(int at) const; + QFontEngine *engine(int at) const + {Q_ASSERT(at < engines.size()); return engines.at(at); } + protected: friend class QPSPrintEnginePrivate; diff --git a/src/gui/text/qfontengine_qpf.cpp b/src/gui/text/qfontengine_qpf.cpp index b7d1c59..8222b7f 100644 --- a/src/gui/text/qfontengine_qpf.cpp +++ b/src/gui/text/qfontengine_qpf.cpp @@ -308,7 +308,7 @@ QFontEngineQPF::QFontEngineQPF(const QFontDef &def, int fileDescriptor, QFontEng readOnly = true; #if defined(DEBUG_FONTENGINE) - qDebug() << "QFontEngineQPF::QFontEngineQPF( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ")"; + qDebug() << "QFontEngineQPF::QFontEngineQPF( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')'; #endif #ifndef QT_FONTS_ARE_RESOURCES @@ -316,9 +316,9 @@ QFontEngineQPF::QFontEngineQPF(const QFontDef &def, int fileDescriptor, QFontEng if (!renderingFontEngine) return; - fileName = fontDef.family.toLower() + QLatin1String("_") + fileName = fontDef.family.toLower() + QLatin1Char('_') + QString::number(fontDef.pixelSize) - + QLatin1String("_") + QString::number(fontDef.weight) + + QLatin1Char('_') + QString::number(fontDef.weight) + (fontDef.style != QFont::StyleNormal ? QLatin1String("_italic") : QLatin1String("")) + QLatin1String(".qsf"); @@ -550,7 +550,7 @@ bool QFontEngineQPF::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph #if 0 && defined(DEBUG_FONTENGINE) QChar c(uc); if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c)) - qDebug() << "glyph for character" << c << "/" << hex << uc << "is" << dec << glyphs[glyph_pos].glyph; + qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph; seenGlyphs.insert(c); #endif diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp index 6551e87..002e670 100644 --- a/src/gui/text/qfontengine_win.cpp +++ b/src/gui/text/qfontengine_win.cpp @@ -1406,8 +1406,8 @@ QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin #endif #endif - QNativeImage *ni = new QNativeImage(iw + 2 * margin, - ih + 2 * margin, + QNativeImage *ni = new QNativeImage(iw + 2 * margin + 4, + ih + 2 * margin + 4, QNativeImage::systemFormat(), true); ni->image.fill(0xffffffff); diff --git a/src/gui/text/qfontengine_x11.cpp b/src/gui/text/qfontengine_x11.cpp index 0972b2b..bafc99d 100644 --- a/src/gui/text/qfontengine_x11.cpp +++ b/src/gui/text/qfontengine_x11.cpp @@ -227,7 +227,7 @@ static QFontEngine::FaceId fontFile(const QByteArray &_xname, QFreetypeFace **fr QByteArray best_mapping; for (QStringList::ConstIterator it = fontpath.constBegin(); it != fontpath.constEnd(); ++it) { - if ((*it).left(1) != QLatin1String("/")) + if (!(*it).startsWith(QLatin1Char('/'))) continue; // not a path name, a font server QString fontmapname; int num = 0; @@ -693,9 +693,8 @@ QFontEngine::FaceId QFontEngineXLFD::faceId() const if (freetype) { const_cast<QFontEngineXLFD *>(this)->fsType = freetype->fsType(); } else { - QFontEngine::Properties properties = QFontEngine::properties(); face_id.index = 0; - face_id.filename = "-" + properties.postscriptName; + face_id.filename = '-' + QFontEngine::properties().postscriptName; } } #endif diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index 88d0610..87da628 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -670,8 +670,8 @@ QRect QFontMetrics::boundingRect(const QString &text) const Returns the rectangle that is covered by ink if character \a ch were to be drawn at the origin of the coordinate system. - Note that the bounding rectangle may extend to the left of (0, 0), - e.g. for italicized fonts, and that the text output may cover \e + Note that the bounding rectangle may extend to the left of (0, 0) + (e.g., for italicized fonts), and that the text output may cover \e all pixels in the bounding rectangle. For a space character the rectangle will usually be empty. @@ -724,7 +724,7 @@ QRect QFontMetrics::boundingRect(QChar ch) const \o Qt::AlignCenter (== \c{Qt::AlignHCenter | Qt::AlignVCenter}) \o Qt::TextSingleLine ignores newline characters in the text. \o Qt::TextExpandTabs expands tabs (see below) - \o Qt::TextShowMnemonic interprets "&x" as \underline{x}, i.e. underlined. + \o Qt::TextShowMnemonic interprets "&x" as \underline{x}; i.e., underlined. \o Qt::TextWordWrap breaks the text to fit the rectangle. \endlist @@ -781,7 +781,7 @@ QRect QFontMetrics::boundingRect(const QRect &rect, int flags, const QString &te \list \o Qt::TextSingleLine ignores newline characters. \o Qt::TextExpandTabs expands tabs (see below) - \o Qt::TextShowMnemonic interprets "&x" as \underline{x}, i.e. underlined. + \o Qt::TextShowMnemonic interprets "&x" as \underline{x}; i.e., underlined. \o Qt::TextWordBreak breaks the text to fit the rectangle. \endlist @@ -1500,7 +1500,7 @@ QRectF QFontMetricsF::boundingRect(QChar ch) const \o Qt::AlignCenter (== \c{Qt::AlignHCenter | Qt::AlignVCenter}) \o Qt::TextSingleLine ignores newline characters in the text. \o Qt::TextExpandTabs expands tabs (see below) - \o Qt::TextShowMnemonic interprets "&x" as \underline{x}, i.e. underlined. + \o Qt::TextShowMnemonic interprets "&x" as \underline{x}; i.e., underlined. \o Qt::TextWordWrap breaks the text to fit the rectangle. \endlist @@ -1559,7 +1559,7 @@ QRectF QFontMetricsF::boundingRect(const QRectF &rect, int flags, const QString& \list \o Qt::TextSingleLine ignores newline characters. \o Qt::TextExpandTabs expands tabs (see below) - \o Qt::TextShowMnemonic interprets "&x" as \underline{x}, i.e. underlined. + \o Qt::TextShowMnemonic interprets "&x" as \underline{x}; i.e., underlined. \o Qt::TextWordBreak breaks the text to fit the rectangle. \endlist diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp index 0d1a884..e4d813d 100644 --- a/src/gui/text/qfontsubset.cpp +++ b/src/gui/text/qfontsubset.cpp @@ -333,17 +333,17 @@ QByteArray QFontSubset::glyphName(unsigned int glyph, const QVector<int> reverse name[0] = 0; } if (name[0]) { - s << "/" << name; + s << '/' << name; } else #endif #if defined(Q_WS_X11) if (fontEngine->type() == QFontEngine::XLFD) { uint uc = static_cast<QFontEngineXLFD *>(fontEngine)->toUnicode(glyphIndex); - s << "/" << glyphName(uc, false /* ### */); + s << '/' << glyphName(uc, false /* ### */); } else #endif if (reverseMap[glyphIndex] && reverseMap[glyphIndex] < 0x10000) { - s << "/" << glyphName(reverseMap[glyphIndex], false); + s << '/' << glyphName(reverseMap[glyphIndex], false); } else { s << "/gl" << (int)glyphIndex; } @@ -395,13 +395,13 @@ QByteArray QFontSubset::widthArray() const int endnonlinear = startLinear ? startLinear : g; // qDebug(" startLinear=%x endnonlinear=%x", startLinear,endnonlinear); if (endnonlinear > start) { - s << start << "["; + s << start << '['; for (int i = start; i < endnonlinear; ++i) s << (widths[i]*scale).toInt(); s << "]\n"; } if (startLinear) - s << startLinear << g - 1 << (widths[startLinear]*scale).toInt() << "\n"; + s << startLinear << g - 1 << (widths[startLinear]*scale).toInt() << '\n'; } s << "]\n"; } @@ -488,14 +488,14 @@ QByteArray QFontSubset::createToUnicodeMap() const int endnonlinear = startLinear ? startLinear : g; // qDebug(" startLinear=%x endnonlinear=%x", startLinear,endnonlinear); if (endnonlinear > start) { - s << "<" << QPdf::toHex((ushort)start, buf) << "> <"; + s << '<' << QPdf::toHex((ushort)start, buf) << "> <"; s << QPdf::toHex((ushort)(endnonlinear - 1), buf) << "> "; if (endnonlinear == start + 1) { - s << "<" << QPdf::toHex((ushort)reverseMap[start], buf) << ">\n"; + s << '<' << QPdf::toHex((ushort)reverseMap[start], buf) << ">\n"; } else { - s << "["; + s << '['; for (int i = start; i < endnonlinear; ++i) { - s << "<" << QPdf::toHex((ushort)reverseMap[i], buf) << "> "; + s << '<' << QPdf::toHex((ushort)reverseMap[i], buf) << "> "; } s << "]\n"; } @@ -508,9 +508,9 @@ QByteArray QFontSubset::createToUnicodeMap() const int uc_end = uc_start + len - 1; if ((uc_end >> 8) != (uc_start >> 8)) len = 256 - (uc_start & 0xff); - s << "<" << QPdf::toHex((ushort)startLinear, buf) << "> <"; + s << '<' << QPdf::toHex((ushort)startLinear, buf) << "> <"; s << QPdf::toHex((ushort)(startLinear + len - 1), buf) << "> "; - s << "<" << QPdf::toHex((ushort)reverseMap[startLinear], buf) << ">\n"; + s << '<' << QPdf::toHex((ushort)reverseMap[startLinear], buf) << ">\n"; checkRanges(ts, ranges, nranges); startLinear += len; } @@ -1655,7 +1655,7 @@ QByteArray QFontSubset::toType1() const QByteArray id = QByteArray::number(object_id); QByteArray psname = properties.postscriptName; - psname.replace(" ", ""); + psname.replace(' ', ""); standard_font = false; @@ -1681,12 +1681,12 @@ QByteArray QFontSubset::toType1() const #endif s << "/F" << id << "-Base\n"; if (standard_font) { - s << "/" << psname << " findfont\n" + s << '/' << psname << " findfont\n" "0 dict copy dup /NumGlyphs 0 put dup /CMap 256 array put def\n"; } else { s << "<<\n"; if(!psname.isEmpty()) - s << "/FontName /" << psname << "\n"; + s << "/FontName /" << psname << '\n'; s << "/FontInfo <</FsType " << (int)fontEngine->fsType << ">>\n" "/FontType 1\n" "/PaintType 0\n" @@ -1722,7 +1722,7 @@ QByteArray QFontSubset::type1AddedGlyphs() const int nGlyphs = glyph_indices.size(); QByteArray id = QByteArray::number(object_id); - s << "F" << id << "-Base [\n"; + s << 'F' << id << "-Base [\n"; for (int i = downloaded_glyphs; i < nGlyphs; ++i) { glyph_t g = glyph_indices.at(i); QPainterPath path; diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index f3d025c..0958b52 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -82,7 +82,7 @@ #include "private/qapplication_p.h" #include "private/qshortcutmap_p.h" #include <qkeysequence.h> -#define ACCEL_KEY(k) (!qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? QLatin1String("\t") + QString(QKeySequence(k)) : QString()) +#define ACCEL_KEY(k) (!qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? QLatin1Char('\t') + QString(QKeySequence(k)) : QString()) #else #define ACCEL_KEY(k) QString() #endif diff --git a/src/gui/text/qtextcontrol_p.h b/src/gui/text/qtextcontrol_p.h index e50540a..4dac4f7 100644 --- a/src/gui/text/qtextcontrol_p.h +++ b/src/gui/text/qtextcontrol_p.h @@ -83,7 +83,7 @@ class QAbstractScrollArea; class QEvent; class QTimerEvent; -class Q_GUI_EXPORT QTextControl : public QObject +class Q_AUTOTEST_EXPORT QTextControl : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(QTextControl) diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index c327b9f..b9e1c89 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -145,7 +145,6 @@ void QTextCursorPrivate::remove() { if (anchor == position) return; - priv->beginEditBlock(); currentCharFormat = -1; int pos1 = position; int pos2 = adjusted_anchor; @@ -159,15 +158,18 @@ void QTextCursorPrivate::remove() // deleting inside table? -> delete only content QTextTable *table = complexSelectionTable(); if (table) { + priv->beginEditBlock(); int startRow, startCol, numRows, numCols; selectedTableCells(&startRow, &numRows, &startCol, &numCols); clearCells(table, startRow, startCol, numRows, numCols, op); + adjusted_anchor = anchor = position; + priv->endEditBlock(); } else { priv->remove(pos1, pos2-pos1, op); + adjusted_anchor = anchor = position; + priv->finishEdit(); } - adjusted_anchor = anchor = position; - priv->endEditBlock(); } void QTextCursorPrivate::clearCells(QTextTable *table, int startRow, int startCol, int numRows, int numCols, QTextUndoCommand::Operation op) @@ -1074,7 +1076,10 @@ QTextCursor::QTextCursor(const QTextCursor &cursor) } /*! - Makes a copy of \a cursor and assigns it to this QTextCursor. + Makes a copy of \a cursor and assigns it to this QTextCursor. Note + that QTextCursor is an \l{Implicitly Shared Classes}{implicitly + shared} class. + */ QTextCursor &QTextCursor::operator=(const QTextCursor &cursor) { @@ -1288,9 +1293,14 @@ void QTextCursor::insertText(const QString &text, const QTextCharFormat &_format QTextCharFormat format = _format; format.clearProperty(QTextFormat::ObjectIndex); - d->priv->beginEditBlock(); + bool hasEditBlock = false; + + if (d->anchor != d->position) { + hasEditBlock = true; + d->priv->beginEditBlock(); + d->remove(); + } - d->remove(); if (!text.isEmpty()) { QTextFormatCollection *formats = d->priv->formatCollection(); int formatIdx = formats->indexForFormat(format); @@ -1320,6 +1330,11 @@ void QTextCursor::insertText(const QString &text, const QTextCharFormat &_format || ch == QChar::ParagraphSeparator || ch == QLatin1Char('\r')) { + if (!hasEditBlock) { + hasEditBlock = true; + d->priv->beginEditBlock(); + } + if (blockEnd > blockStart) d->priv->insert(d->position, textStart + blockStart, blockEnd - blockStart, formatIdx); @@ -1330,7 +1345,8 @@ void QTextCursor::insertText(const QString &text, const QTextCharFormat &_format if (textStart + blockStart < textEnd) d->priv->insert(d->position, textStart + blockStart, textEnd - textStart - blockStart, formatIdx); } - d->priv->endEditBlock(); + if (hasEditBlock) + d->priv->endEditBlock(); d->setX(); } @@ -1345,12 +1361,15 @@ void QTextCursor::deleteChar() if (!d || !d->priv) return; - if (d->position == d->anchor) { - if (!d->canDelete(d->position)) - return; - d->adjusted_anchor = d->anchor = - d->priv->nextCursorPosition(d->anchor, QTextLayout::SkipCharacters); + if (d->position != d->anchor) { + removeSelectedText(); + return; } + + if (!d->canDelete(d->position)) + return; + d->adjusted_anchor = d->anchor = + d->priv->nextCursorPosition(d->anchor, QTextLayout::SkipCharacters); d->remove(); d->setX(); } @@ -1365,27 +1384,29 @@ void QTextCursor::deletePreviousChar() { if (!d || !d->priv) return; - - if (d->position == d->anchor) { - if (d->anchor < 1 || !d->canDelete(d->anchor-1)) - return; - d->anchor--; - - QTextDocumentPrivate::FragmentIterator fragIt = d->priv->find(d->anchor); - const QTextFragmentData * const frag = fragIt.value(); - int fpos = fragIt.position(); - QChar uc = d->priv->buffer().at(d->anchor - fpos + frag->stringPosition); - if (d->anchor > fpos && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) { - // second half of a surrogate, check if we have the first half as well, - // if yes delete both at once - uc = d->priv->buffer().at(d->anchor - 1 - fpos + frag->stringPosition); - if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) - --d->anchor; - } - - d->adjusted_anchor = d->anchor; + + if (d->position != d->anchor) { + removeSelectedText(); + return; } - + + if (d->anchor < 1 || !d->canDelete(d->anchor-1)) + return; + d->anchor--; + + QTextDocumentPrivate::FragmentIterator fragIt = d->priv->find(d->anchor); + const QTextFragmentData * const frag = fragIt.value(); + int fpos = fragIt.position(); + QChar uc = d->priv->buffer().at(d->anchor - fpos + frag->stringPosition); + if (d->anchor > fpos && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) { + // second half of a surrogate, check if we have the first half as well, + // if yes delete both at once + uc = d->priv->buffer().at(d->anchor - 1 - fpos + frag->stringPosition); + if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) + --d->anchor; + } + + d->adjusted_anchor = d->anchor; d->remove(); d->setX(); } @@ -1501,7 +1522,9 @@ void QTextCursor::removeSelectedText() if (!d || !d->priv || d->position == d->anchor) return; + d->priv->beginEditBlock(); d->remove(); + d->priv->endEditBlock(); d->setX(); } diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index e84b324..23c3c20 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -287,7 +287,7 @@ QTextCodec *Qt::codecForHtml(const QByteArray &ba) that inform connected editor widgets about the state of the undo/redo system. - \sa QTextCursor QTextEdit \link richtext.html Rich Text Processing\endlink + \sa QTextCursor, QTextEdit, \link richtext.html Rich Text Processing\endlink , {Text Object Example} */ /*! @@ -2201,7 +2201,7 @@ void QTextHtmlExporter::emitTextLength(const char *attribute, const QTextLength if (length.type() == QTextLength::PercentageLength) html += QLatin1String("%\""); else - html += QLatin1String("\""); + html += QLatin1Char('\"'); } void QTextHtmlExporter::emitAlignment(Qt::Alignment align) diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp index 05ddf47..e1da4be 100644 --- a/src/gui/text/qtextdocument_p.cpp +++ b/src/gui/text/qtextdocument_p.cpp @@ -404,7 +404,7 @@ int QTextDocumentPrivate::insertBlock(const QChar &blockSeparator, int b = blocks.findNode(pos); QTextBlockData *B = blocks.fragment(b); - QTextUndoCommand c = { QTextUndoCommand::BlockInserted, true, + QTextUndoCommand c = { QTextUndoCommand::BlockInserted, editBlock != 0, op, charFormat, strPos, pos, { blockFormat }, B->revision }; @@ -439,20 +439,19 @@ void QTextDocumentPrivate::insert(int pos, int strPos, int strLength, int format Q_ASSERT(pos >= 0 && pos < fragments.length()); Q_ASSERT(formats.format(format).isCharFormat()); - beginEditBlock(); insert_string(pos, strPos, strLength, format, QTextUndoCommand::MoveCursor); if (undoEnabled) { int b = blocks.findNode(pos); QTextBlockData *B = blocks.fragment(b); - QTextUndoCommand c = { QTextUndoCommand::Inserted, true, + QTextUndoCommand c = { QTextUndoCommand::Inserted, editBlock != 0, QTextUndoCommand::MoveCursor, format, strPos, pos, { strLength }, B->revision }; appendUndoItem(c); B->revision = undoState; Q_ASSERT(undoState == undoStack.size()); } - endEditBlock(); + finishEdit(); } void QTextDocumentPrivate::insert(int pos, const QString &str, int format) @@ -584,8 +583,6 @@ void QTextDocumentPrivate::move(int pos, int to, int length, QTextUndoCommand::O Q_ASSERT(startAndEndInSameFrame || endIsEndOfChildFrame || startIsStartOfFrameAndEndIsEndOfFrameWithCommonParent || isFirstTableCell); #endif - beginEditBlock(); - split(pos); split(pos+length); @@ -605,10 +602,10 @@ void QTextDocumentPrivate::move(int pos, int to, int length, QTextUndoCommand::O int blockRevision = B->revision; QTextFragmentData *X = fragments.fragment(x); - QTextUndoCommand c = { QTextUndoCommand::Removed, true, + QTextUndoCommand c = { QTextUndoCommand::Removed, editBlock != 0, op, X->format, X->stringPosition, key, { X->size_array[0] }, blockRevision }; - QTextUndoCommand cInsert = { QTextUndoCommand::Inserted, true, + QTextUndoCommand cInsert = { QTextUndoCommand::Inserted, editBlock != 0, op, X->format, X->stringPosition, dstKey, { X->size_array[0] }, blockRevision }; @@ -648,7 +645,7 @@ void QTextDocumentPrivate::move(int pos, int to, int length, QTextUndoCommand::O Q_ASSERT(blocks.length() == fragments.length()); - endEditBlock(); + finishEdit(); } void QTextDocumentPrivate::remove(int pos, int length, QTextUndoCommand::Operation op) @@ -1004,8 +1001,12 @@ void QTextDocumentPrivate::appendUndoItem(const QTextUndoCommand &c) if (!undoStack.isEmpty() && modified) { QTextUndoCommand &last = undoStack[undoState - 1]; - if (last.tryMerge(c)) - return; + if ( (last.block && c.block) // part of the same block => can merge + || (!c.block && !last.block // two single undo items => can merge + && (undoState < 2 || !undoStack[undoState-2].block))) { + if (last.tryMerge(c)) + return; + } } if (modifiedState > undoState) modifiedState = -1; @@ -1013,6 +1014,9 @@ void QTextDocumentPrivate::appendUndoItem(const QTextUndoCommand &c) undoState++; emitUndoAvailable(true); emitRedoAvailable(false); + + if (!c.block) + emit document()->undoCommandAdded(); } void QTextDocumentPrivate::truncateUndoStack() @@ -1082,7 +1086,6 @@ void QTextDocumentPrivate::joinPreviousEditBlock() void QTextDocumentPrivate::endEditBlock() { - Q_Q(QTextDocument); if (--editBlock) return; @@ -1093,6 +1096,16 @@ void QTextDocumentPrivate::endEditBlock() emit document()->undoCommandAdded(); } + finishEdit(); +} + +void QTextDocumentPrivate::finishEdit() +{ + Q_Q(QTextDocument); + + if (editBlock) + return; + if (framesDirty) scan_frames(docChangeFrom, docChangeOldLength, docChangeLength); @@ -1279,7 +1292,7 @@ void QTextDocumentPrivate::changeObjectFormat(QTextObject *obj, int format) if (f) documentChange(f->firstPosition(), f->lastPosition() - f->firstPosition()); - QTextUndoCommand c = { QTextUndoCommand::GroupFormatChange, true, QTextUndoCommand::MoveCursor, oldFormatIndex, + QTextUndoCommand c = { QTextUndoCommand::GroupFormatChange, editBlock != 0, QTextUndoCommand::MoveCursor, oldFormatIndex, 0, 0, { obj->d_func()->objectIndex }, 0 }; appendUndoItem(c); diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h index 25763e1..d754ff0 100644 --- a/src/gui/text/qtextdocument_p.h +++ b/src/gui/text/qtextdocument_p.h @@ -139,7 +139,7 @@ public: MoveCursor = 1 }; quint16 command; - quint8 block; ///< All undo commands that have this set to zero/false are combined with the preceding command on undo/redo. + quint8 block; ///< All undo commands that have this set to true are combined with the preceding command on undo/redo. quint8 operation; int format; quint32 strPos; @@ -202,6 +202,7 @@ public: inline void beginEditBlock() { editBlock++; } void joinPreviousEditBlock(); void endEditBlock(); + void finishEdit(); inline bool isInEditBlock() const { return editBlock; } void enableUndoRedo(bool enable); inline bool isUndoRedoEnabled() const { return undoEnabled; } diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index c66d0c1..fa032e6 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -2500,7 +2500,7 @@ void QTextDocumentLayoutPrivate::layoutBlock(const QTextBlock &bl, int blockPosi LDEBUG << "layoutBlock from=" << layoutFrom << "to=" << layoutTo; -// qDebug() << "layoutBlock; width" << layoutStruct->x_right - layoutStruct->x_left << "(maxWidth is btw" << tl->maximumWidth() << ")"; +// qDebug() << "layoutBlock; width" << layoutStruct->x_right - layoutStruct->x_left << "(maxWidth is btw" << tl->maximumWidth() << ')'; if (previousBlockFormat) { qreal margin = qMax(blockFormat.topMargin(), previousBlockFormat->bottomMargin()); diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index faa06b7..a28c655 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -363,7 +363,7 @@ static bool bidiItemize(QTextEngine *engine, QScriptAnalysis *analysis, QBidiCon #if (BIDI_DEBUG >= 2) // qDebug() << "pos=" << current << " dir=" << directions[dir] // << " current=" << directions[dirCurrent] << " last=" << directions[status.last] -// << " eor=" << eor << "/" << directions[status.eor] +// << " eor=" << eor << '/' << directions[status.eor] // << " sor=" << sor << " lastStrong=" // << directions[status.lastStrong] // << " level=" << (int)control.level << " override=" << (bool)control.override; @@ -1099,6 +1099,16 @@ void QTextEngine::shapeTextWithCE(int item) const } #endif +static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLayout &source, int num) +{ + if (num > 0 && destination.glyphs != source.glyphs) { + memmove(destination.glyphs, source.glyphs, num * sizeof(HB_Glyph)); + memmove(destination.attributes, source.attributes, num * sizeof(HB_GlyphAttributes)); + memmove(destination.advances_x, source.advances_x, num * sizeof(HB_Fixed)); + memmove(destination.offsets, source.offsets, num * sizeof(HB_FixedPoint)); + } +} + /// take the item from layoutData->items and void QTextEngine::shapeTextWithHarfbuzz(int item) const { @@ -1189,7 +1199,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const - int initial_glyph_pos = 0; + int remaining_glyphs = entire_shaper_item.num_glyphs; int glyph_pos = 0; // for each item shape using harfbuzz and store the results in our layoutData's glyphs array. for (int k = 0; k < itemBoundaries.size(); k += 2) { // for the +2, see the comment at the definition of itemBoundaries @@ -1209,7 +1219,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const QFontEngine *actualFontEngine = font; uint engineIdx = 0; if (font->type() == QFontEngine::Multi) { - engineIdx = uint(initialGlyphs.glyphs[itemBoundaries[k + 1]] >> 24); + engineIdx = uint(availableGlyphs(&si).glyphs[glyph_pos] >> 24); actualFontEngine = static_cast<QFontEngineMulti *>(font)->engine(engineIdx); } @@ -1219,16 +1229,18 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const shaper_item.glyphIndicesPresent = true; + remaining_glyphs -= shaper_item.initialGlyphCount; + do { - ensureSpace(glyph_pos + shaper_item.num_glyphs); - initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs); - shaper_item.num_glyphs = layoutData->glyphLayout.numGlyphs - layoutData->used - glyph_pos; + ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs); - const QGlyphLayout g = availableGlyphs(&si); - shaper_item.glyphs = g.glyphs + glyph_pos; - shaper_item.attributes = g.attributes + glyph_pos; - shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances_x + glyph_pos); - shaper_item.offsets = reinterpret_cast<HB_FixedPoint *>(g.offsets + glyph_pos); + const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos); + moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs); + + shaper_item.glyphs = g.glyphs; + shaper_item.attributes = g.attributes; + shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances_x); + shaper_item.offsets = reinterpret_cast<HB_FixedPoint *>(g.offsets); if (shaper_item.glyphIndicesPresent) { for (hb_uint32 i = 0; i < shaper_item.initialGlyphCount; ++i) @@ -1241,18 +1253,18 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const } while (!qShapeItem(&shaper_item)); // this does the actual shaping via harfbuzz. QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos, shaper_item.num_glyphs); + moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs); - for (hb_uint32 i = 0; i < shaper_item.item.length; ++i) { + for (hb_uint32 i = 0; i < shaper_item.num_glyphs; ++i) g.glyphs[i] = g.glyphs[i] | (engineIdx << 24); + + for (hb_uint32 i = 0; i < shaper_item.item.length; ++i) shaper_item.log_clusters[i] += glyph_pos; - } if (kerningEnabled && !shaper_item.kerning_applied) font->doKerning(&g, option.useDesignMetrics() ? QFlag(QTextEngine::DesignMetrics) : QFlag(0)); glyph_pos += shaper_item.num_glyphs; - - initial_glyph_pos += shaper_item.initialGlyphCount; } // qDebug(" -> item: script=%d num_glyphs=%d", shaper_item.script, shaper_item.num_glyphs); diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index 21bfc4d..38ac4ca 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -1449,7 +1449,7 @@ void QTextCharFormat::setUnderlineStyle(UnderlineStyle style) /*! \since 4.5 \fn bool QTextCharFormat::fontKerning() const - Returns true if the the font kerning is enabled. + Returns true if the font kerning is enabled. \sa setFontKerning() \sa font() diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index b1f1b75..ee743dc 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -499,7 +499,7 @@ void QTextHtmlParser::dumpHtml() { for (int i = 0; i < count(); ++i) { qDebug().nospace() << qPrintable(QString(depth(i)*4, QLatin1Char(' '))) - << qPrintable(at(i).tag) << ":" + << qPrintable(at(i).tag) << ':' << quoteNewline(at(i).text); ; } diff --git a/src/gui/text/qtextimagehandler_p.h b/src/gui/text/qtextimagehandler_p.h index f5426b5..1f29642 100644 --- a/src/gui/text/qtextimagehandler_p.h +++ b/src/gui/text/qtextimagehandler_p.h @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE class QTextImageFormat; -class Q_GUI_EXPORT QTextImageHandler : public QObject, +class QTextImageHandler : public QObject, public QTextObjectInterface { Q_OBJECT @@ -72,7 +72,7 @@ public: virtual void drawObject(QPainter *p, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format); typedef QImage (*ExternalImageLoaderFunction)(const QString &name, const QString &context); - static ExternalImageLoaderFunction externalLoader; + static Q_GUI_EXPORT ExternalImageLoaderFunction externalLoader; //this is needed by Qt3Support }; QT_END_NAMESPACE diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 3222237..fa624ef 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1145,7 +1145,7 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRang } QPainterPath excludedRegion; - QPainterPath needsTextButNoBackground; + QPainterPath textDoneRegion; for (int i = 0; i < selections.size(); ++i) { FormatRange selection = selections.at(i); const QBrush bg = selection.format.background(); @@ -1205,18 +1205,25 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRang } - p->save(); - p->setClipPath(region, Qt::IntersectClip); - selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush)); - // don't just clear the property, set an empty brush that overrides a potential - // background brush specified in the text - selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush()); - selection.format.clearProperty(QTextFormat::OutlinePen); + bool hasText = (selection.format.foreground().style() != Qt::NoBrush); + bool hasBackground= (selection.format.background().style() != Qt::NoBrush); + + if (hasBackground) { + selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush)); + // don't just clear the property, set an empty brush that overrides a potential + // background brush specified in the text + selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush()); + selection.format.clearProperty(QTextFormat::OutlinePen); + } - bool noText = (selection.format.foreground().style() == Qt::NoBrush); + selection.format.setProperty(SuppressText, !hasText); + + if (hasText && !hasBackground && !(textDoneRegion & region).isEmpty()) + continue; - selection.format.setProperty(SuppressText, noText); + p->save(); + p->setClipPath(region, Qt::IntersectClip); for (int line = firstLine; line < lastLine; ++line) { QTextLine l(line, d); @@ -1224,13 +1231,17 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRang } p->restore(); - if (noText) - needsTextButNoBackground += region; - else - needsTextButNoBackground -= region; + if (hasText) { + textDoneRegion += region; + } else { + if (hasBackground) + textDoneRegion -= region; + } + excludedRegion += region; } + QPainterPath needsTextButNoBackground = excludedRegion - textDoneRegion; if (!needsTextButNoBackground.isEmpty()){ p->save(); p->setClipPath(needsTextButNoBackground, Qt::IntersectClip); diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index 3f4c8e5..71b68e0 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE objects, you will also need to reimplement QTextDocument::createObject() which acts as a factory method for creating text objects. - \sa QTextDocument + \sa QTextDocument, {Text Object Example} */ /*! diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp index ba1c04f..48708c9 100644 --- a/src/gui/text/qtexttable.cpp +++ b/src/gui/text/qtexttable.cpp @@ -525,7 +525,12 @@ void QTextTablePrivate::update() const Rows and columns within a QTextTable can be merged and split using the mergeCells() and splitCell() functions. However, only cells that span multiple rows or columns can be split. (Merging or splitting does not increase or decrease - the number of rows and columns.) + the number of rows and columns.) + + Note that if you have merged multiple columns and rows into one cell, you will not + be able to split the merged cell into new cells spanning over more than one row + or column. To be able to split cells spanning over several rows and columns you + need to do this over several iterations. \table 80% \row diff --git a/src/gui/util/qcompleter.cpp b/src/gui/util/qcompleter.cpp index a622385..bed10dc 100644 --- a/src/gui/util/qcompleter.cpp +++ b/src/gui/util/qcompleter.cpp @@ -824,7 +824,7 @@ void QCompleterPrivate::_q_complete(QModelIndex index, bool highlighted) Q_Q(QCompleter); QString completion; - if (!index.isValid() || (index.row() >= proxy->engine->matchCount())) { + if (!index.isValid() || (!proxy->showAll && (index.row() >= proxy->engine->matchCount()))) { completion = prefix; } else { QModelIndex si = proxy->mapToSource(index); @@ -1664,7 +1664,7 @@ QStringList QCompleter::splitPath(const QString& path) const doubleSlash.clear(); #endif - QRegExp re(QLatin1String("[") + QRegExp::escape(sep) + QLatin1String("]")); + QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']')); QStringList parts = pathCopy.split(re); #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) diff --git a/src/gui/util/qdesktopservices_mac.cpp b/src/gui/util/qdesktopservices_mac.cpp index fdafa1e..fb1e193 100644 --- a/src/gui/util/qdesktopservices_mac.cpp +++ b/src/gui/util/qdesktopservices_mac.cpp @@ -154,7 +154,7 @@ QString QDesktopServices::storageLocation(StandardLocation type) QString appName = QCoreApplication::applicationName(); if (!appName.isEmpty() && (QDesktopServices::DataLocation == type || QDesktopServices::CacheLocation == type)) - path += QLatin1String("/") + appName; + path += QLatin1Char('/') + appName; return path; } diff --git a/src/gui/util/qdesktopservices_x11.cpp b/src/gui/util/qdesktopservices_x11.cpp index b3486e8..8c4a597 100644 --- a/src/gui/util/qdesktopservices_x11.cpp +++ b/src/gui/util/qdesktopservices_x11.cpp @@ -164,8 +164,8 @@ QString QDesktopServices::storageLocation(StandardLocation type) QString key = lst.at(1); QString value = lst.at(2); if (value.length() > 2 - && value.startsWith(QLatin1String("\"")) - && value.endsWith(QLatin1String("\""))) + && value.startsWith(QLatin1Char('\"')) + && value.endsWith(QLatin1Char('\"'))) value = value.mid(1, value.length() - 2); // Store the key and value: "DESKTOP", "$HOME/Desktop" lines[key] = value; diff --git a/src/gui/util/qsystemtrayicon_win.cpp b/src/gui/util/qsystemtrayicon_win.cpp index a6dcea6..c46c929 100644 --- a/src/gui/util/qsystemtrayicon_win.cpp +++ b/src/gui/util/qsystemtrayicon_win.cpp @@ -662,7 +662,7 @@ void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString //message is limited to 255 chars + NULL QString messageString; if (message.isEmpty() && !title.isEmpty()) - messageString = QLatin1String(" "); //ensures that the message shows when only title is set + messageString = QLatin1Char(' '); //ensures that the message shows when only title is set else messageString = message.left(255) + QChar(); diff --git a/src/gui/util/qundostack.cpp b/src/gui/util/qundostack.cpp index 11f65e3..a6b9c23 100644 --- a/src/gui/util/qundostack.cpp +++ b/src/gui/util/qundostack.cpp @@ -715,7 +715,7 @@ int QUndoStack::index() const } /*! - Repeatedly calls undo() or redo() until the the current command index reaches + Repeatedly calls undo() or redo() until the current command index reaches \a idx. This function can be used to roll the state of the document forwards of backwards. indexChanged() is emitted only once. diff --git a/src/gui/widgets/qabstractbutton.cpp b/src/gui/widgets/qabstractbutton.cpp index f2a9ceb..1900016 100644 --- a/src/gui/widgets/qabstractbutton.cpp +++ b/src/gui/widgets/qabstractbutton.cpp @@ -215,11 +215,8 @@ void QButtonGroup::setExclusive(bool exclusive) d->exclusive = exclusive; } -/*! - Adds the given \a button to the end of the group's internal list of buttons. - \sa removeButton() -*/ +// TODO: Qt 5: Merge with addButton(QAbstractButton *button, int id) void QButtonGroup::addButton(QAbstractButton *button) { addButton(button, -1); @@ -232,8 +229,18 @@ void QButtonGroup::addButton(QAbstractButton *button, int id) previous->removeButton(button); button->d_func()->group = this; d->buttonList.append(button); - if (id != -1) + if (id == -1) { + QList<int> ids = d->mapping.values(); + if (ids.isEmpty()) + d->mapping[button] = -2; + else { + qSort(ids); + d->mapping[button] = ids.first()-1; + } + } else { d->mapping[button] = id; + } + if (d->exclusive && button->isChecked()) button->d_func()->notifyChecked(); } diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp index 9886969..5eed745 100644 --- a/src/gui/widgets/qabstractscrollarea.cpp +++ b/src/gui/widgets/qabstractscrollarea.cpp @@ -873,21 +873,22 @@ bool QAbstractScrollArea::event(QEvent *e) case QEvent::Resize: d->layoutChildren(); break; - case QEvent::Paint: + case QEvent::Paint: { + QStyleOption option; + option.initFrom(this); if (d->cornerPaintingRect.isValid()) { - QStyleOption option; option.rect = d->cornerPaintingRect; QPainter p(this); style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this); } #ifdef Q_WS_MAC if (d->reverseCornerPaintingRect.isValid()) { - QStyleOption option; option.rect = d->reverseCornerPaintingRect; QPainter p(this); style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this); } #endif + } QFrame::paintEvent((QPaintEvent*)e); break; #ifndef QT_NO_CONTEXTMENU @@ -1264,6 +1265,12 @@ QSize QAbstractScrollArea::minimumSizeHint() const int hsbExt = d->hbar->sizeHint().height(); int vsbExt = d->vbar->sizeHint().width(); int extra = 2 * d->frameWidth; + QStyleOption opt; + opt.initFrom(this); + if ((d->frameStyle != QFrame::NoFrame) + && style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, this)) { + extra += style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &opt, this); + } return QSize(d->scrollBarContainers[Qt::Horizontal]->sizeHint().width() + vsbExt + extra, d->scrollBarContainers[Qt::Vertical]->sizeHint().height() + hsbExt + extra); } diff --git a/src/gui/widgets/qabstractscrollarea_p.h b/src/gui/widgets/qabstractscrollarea_p.h index e4c47e9..f153711 100644 --- a/src/gui/widgets/qabstractscrollarea_p.h +++ b/src/gui/widgets/qabstractscrollarea_p.h @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE class QScrollBar; class QAbstractScrollAreaScrollBarContainer; -class Q_GUI_EXPORT QAbstractScrollAreaPrivate: public QFramePrivate +class QAbstractScrollAreaPrivate: public QFramePrivate { Q_DECLARE_PUBLIC(QAbstractScrollArea) diff --git a/src/gui/widgets/qabstractspinbox.cpp b/src/gui/widgets/qabstractspinbox.cpp index 347f89a..09accc7 100644 --- a/src/gui/widgets/qabstractspinbox.cpp +++ b/src/gui/widgets/qabstractspinbox.cpp @@ -193,6 +193,7 @@ void QAbstractSpinBox::setButtonSymbols(ButtonSymbols buttonSymbols) Q_D(QAbstractSpinBox); if (d->buttonSymbols != buttonSymbols) { d->buttonSymbols = buttonSymbols; + d->updateEditFieldGeometry(); update(); } } @@ -1780,8 +1781,8 @@ void QAbstractSpinBoxPrivate::interpret(EmitPolicy ep) q->fixup(tmp); QASBDEBUG() << "QAbstractSpinBoxPrivate::interpret() text '" << edit->displayText() - << "' >> '" << copy << "'" - << "' >> '" << tmp << "'"; + << "' >> '" << copy << '\'' + << "' >> '" << tmp << '\''; doInterpret = tmp != copy && (q->validate(tmp, pos) == QValidator::Acceptable); if (!doInterpret) { diff --git a/src/gui/widgets/qbuttongroup.cpp b/src/gui/widgets/qbuttongroup.cpp index 06bcf1e..ebfafe3 100644 --- a/src/gui/widgets/qbuttongroup.cpp +++ b/src/gui/widgets/qbuttongroup.cpp @@ -176,11 +176,21 @@ */ /*! - \fn void QButtonGroup::addButton(QAbstractButton *button, int id = -1); + \fn void QButtonGroup::addButton(QAbstractButton *button); + + Adds the given \a button to the end of the group's internal list of buttons. + An \a id will be assigned to the button by this QButtonGroup. Automatically + assigned ids are guaranteed to be negative, starting with -2. If you are also + assigning your own ids, use positive values to avoid conflicts. + + \sa removeButton() buttons() +*/ + +/*! + \fn void QButtonGroup::addButton(QAbstractButton *button, int id); Adds the given \a button to the button group, with the given \a - id. If \a id is -1 (the default), an id will be assigned to the - button by this QButtonGroup. + id. It is recommended to assign only positive ids. \sa removeButton() buttons() */ diff --git a/src/gui/widgets/qcalendarwidget.cpp b/src/gui/widgets/qcalendarwidget.cpp index 92c12a5..8703139 100644 --- a/src/gui/widgets/qcalendarwidget.cpp +++ b/src/gui/widgets/qcalendarwidget.cpp @@ -198,7 +198,7 @@ QString QCalendarDayValidator::text() const { QString str; if (m_day / 10 == 0) - str += QLatin1String("0"); + str += QLatin1Char('0'); str += QString::number(m_day); return highlightString(str, m_pos); } @@ -210,7 +210,7 @@ QString QCalendarDayValidator::text(const QDate &date, int repeat) const } else if (repeat == 2) { QString str; if (date.day() / 10 == 0) - str += QLatin1String("0"); + str += QLatin1Char('0'); return str + QString::number(date.day()); } else if (repeat == 3) { return m_locale.dayName(date.dayOfWeek(), QLocale::ShortFormat); @@ -316,7 +316,7 @@ QString QCalendarMonthValidator::text() const { QString str; if (m_month / 10 == 0) - str += QLatin1String("0"); + str += QLatin1Char('0'); str += QString::number(m_month); return highlightString(str, m_pos); } @@ -328,7 +328,7 @@ QString QCalendarMonthValidator::text(const QDate &date, int repeat) const } else if (repeat == 2) { QString str; if (date.month() / 10 == 0) - str += QLatin1String("0"); + str += QLatin1Char('0'); return str + QString::number(date.month()); } else if (repeat == 3) { return m_locale.standaloneMonthName(date.month(), QLocale::ShortFormat); @@ -432,7 +432,7 @@ QString QCalendarYearValidator::text() const int pow = 10; for (int i = 0; i < 3; i++) { if (m_year / pow == 0) - str += QLatin1String("0"); + str += QLatin1Char('0'); pow *= 10; } str += QString::number(m_year); @@ -445,7 +445,7 @@ QString QCalendarYearValidator::text(const QDate &date, int repeat) const QString str; int year = date.year() % 100; if (year / 10 == 0) - str = QLatin1String("0"); + str = QLatin1Char('0'); return str + QString::number(year); } return QString::number(date.year()); @@ -577,7 +577,7 @@ void QCalendarDateValidator::setFormat(const QString &format) clear(); int pos = 0; - const QLatin1String quote("'"); + const QLatin1Char quote('\''); bool quoting = false; QString separator; while (pos < format.size()) { @@ -2791,7 +2791,7 @@ QTextCharFormat QCalendarWidget::dateTextFormat(const QDate &date) const void QCalendarWidget::setDateTextFormat(const QDate &date, const QTextCharFormat &format) { Q_D(QCalendarWidget); - if ( date.isNull() && !format.isValid() ) + if (date.isNull()) d->m_model->m_dateFormats.clear(); else d->m_model->m_dateFormats[date] = format; diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index f30ece4..01fe9d2 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -947,7 +947,7 @@ QComboBoxPrivateContainer* QComboBoxPrivate::viewContainer() container = new QComboBoxPrivateContainer(new QComboBoxListView(q), q); container->itemView()->setModel(model); container->itemView()->setTextElideMode(Qt::ElideMiddle); - updateDelegate(); + updateDelegate(true); updateLayoutDirection(); updateViewContainerPaletteAndOpacity(); QObject::connect(container, SIGNAL(itemSelected(QModelIndex)), @@ -1589,15 +1589,25 @@ bool QComboBox::isEditable() const return d->lineEdit != 0; } -void QComboBoxPrivate::updateDelegate() +/*! \internal + update the default delegate + depending on the style's SH_ComboBox_Popup hint, we use a different default delegate. + + but we do not change the delegate is the combobox use a custom delegate, + unless \a force is set to true. + */ +void QComboBoxPrivate::updateDelegate(bool force) { Q_Q(QComboBox); QStyleOptionComboBox opt; q->initStyleOption(&opt); - if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q)) - q->setItemDelegate(new QComboMenuDelegate(q->view(), q)); - else - q->setItemDelegate(new QComboBoxDelegate(q->view(), q)); + if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q)) { + if (force || qobject_cast<QComboBoxDelegate *>(q->itemDelegate())) + q->setItemDelegate(new QComboMenuDelegate(q->view(), q)); + } else { + if (force || qobject_cast<QComboMenuDelegate *>(q->itemDelegate())) + q->setItemDelegate(new QComboBoxDelegate(q->view(), q)); + } } QIcon QComboBoxPrivate::itemIcon(const QModelIndex &index) const diff --git a/src/gui/widgets/qcombobox_p.h b/src/gui/widgets/qcombobox_p.h index a0b76cf..0998e52 100644 --- a/src/gui/widgets/qcombobox_p.h +++ b/src/gui/widgets/qcombobox_p.h @@ -256,7 +256,7 @@ private: }; class QComboMenuDelegate : public QAbstractItemDelegate -{ +{ Q_OBJECT public: QComboMenuDelegate(QObject *parent, QComboBox *cmb) : QAbstractItemDelegate(parent), mCombo(cmb) {} @@ -285,12 +285,12 @@ private: // Vista does not use the new theme for combo boxes and there might // be other side effects from using the new class class QComboBoxDelegate : public QItemDelegate -{ +{ Q_OBJECT public: QComboBoxDelegate(QObject *parent, QComboBox *cmb) : QItemDelegate(parent), mCombo(cmb) {} static bool isSeparator(const QModelIndex &index) { - return index.data(Qt::AccessibleDescriptionRole).toString() == QString::fromLatin1("separator"); + return index.data(Qt::AccessibleDescriptionRole).toString() == QLatin1String("separator"); } static void setSeparator(QAbstractItemModel *model, const QModelIndex &index) { model->setData(index, QString::fromLatin1("separator"), Qt::AccessibleDescriptionRole); @@ -367,7 +367,7 @@ public: int itemRole() const; void updateLayoutDirection(); void setCurrentIndex(const QModelIndex &index); - void updateDelegate(); + void updateDelegate(bool force = false); void keyboardSearchString(const QString &text); void modelChanged(); void updateViewContainerPaletteAndOpacity(); diff --git a/src/gui/widgets/qframe.cpp b/src/gui/widgets/qframe.cpp index 6f81331..22a990b 100644 --- a/src/gui/widgets/qframe.cpp +++ b/src/gui/widgets/qframe.cpp @@ -59,8 +59,7 @@ QFramePrivate::QFramePrivate() midLineWidth(0), frameWidth(0), leftFrameWidth(0), rightFrameWidth(0), - topFrameWidth(0), bottomFrameWidth(0), - oldFrameStyle(QFrame::NoFrame | QFrame::Plain) + topFrameWidth(0), bottomFrameWidth(0) { } @@ -333,7 +332,6 @@ void QFrame::setFrameStyle(int style) d->frameStyle = (short)style; update(); d->updateFrameWidth(); - d->oldFrameStyle = (short)style; } /*! diff --git a/src/gui/widgets/qframe_p.h b/src/gui/widgets/qframe_p.h index 4fd341d..537f5bf 100644 --- a/src/gui/widgets/qframe_p.h +++ b/src/gui/widgets/qframe_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE -class Q_GUI_EXPORT QFramePrivate : public QWidgetPrivate +class QFramePrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QFrame) public: @@ -74,7 +74,6 @@ public: short frameWidth; short leftFrameWidth, rightFrameWidth; short topFrameWidth, bottomFrameWidth; - short oldFrameStyle; inline void init(); diff --git a/src/gui/widgets/qlabel.cpp b/src/gui/widgets/qlabel.cpp index 016b7c1..1aef133 100644 --- a/src/gui/widgets/qlabel.cpp +++ b/src/gui/widgets/qlabel.cpp @@ -1170,7 +1170,7 @@ void QLabelPrivate::updateShortcut() shortcutCursor.deleteChar(); // remove the ampersand shortcutCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); } else { - if (!text.contains(QLatin1String("&"))) + if (!text.contains(QLatin1Char('&'))) return; hasShortcut = true; shortcutId = q->grabShortcut(QKeySequence::mnemonic(text)); diff --git a/src/gui/widgets/qlcdnumber.cpp b/src/gui/widgets/qlcdnumber.cpp index 9d98dbc..6686d7e 100644 --- a/src/gui/widgets/qlcdnumber.cpp +++ b/src/gui/widgets/qlcdnumber.cpp @@ -1275,7 +1275,7 @@ bool QLCDNumber::event(QEvent *e) /*! \fn int QLCDNumber::margin() const - Returns the with of the the margin around the contents of the widget. + Returns the width of the margin around the contents of the widget. Use QWidget::getContentsMargins() instead. \sa setMargin(), QWidget::getContentsMargins() diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index d16ed10..a4b0b4f 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -79,7 +79,7 @@ #include "private/qapplication_p.h" #include "private/qshortcutmap_p.h" #include "qkeysequence.h" -#define ACCEL_KEY(k) (!qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? QLatin1String("\t") + QString(QKeySequence(k)) : QString()) +#define ACCEL_KEY(k) (!qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? QLatin1Char('\t') + QString(QKeySequence(k)) : QString()) #else #define ACCEL_KEY(k) QString() #endif @@ -3675,7 +3675,7 @@ void QLineEditPrivate::redo() { /*! \fn int QLineEdit::margin() const - Returns the with of the the margin around the contents of the widget. + Returns the width of the margin around the contents of the widget. Use QWidget::getContentsMargins() instead. \sa setMargin(), QWidget::getContentsMargins() diff --git a/src/gui/widgets/qmainwindow.cpp b/src/gui/widgets/qmainwindow.cpp index 1afb28a..558ba42 100644 --- a/src/gui/widgets/qmainwindow.cpp +++ b/src/gui/widgets/qmainwindow.cpp @@ -480,9 +480,6 @@ void QMainWindow::setMenuBar(QMenuBar *menuBar) oldMenuBar->hide(); oldMenuBar->deleteLater(); } -#ifdef Q_WS_WINCE - if (menuBar && menuBar->size().height() > 0) -#endif d->layout->setMenuBar(menuBar); } @@ -1411,10 +1408,10 @@ bool QMainWindow::event(QEvent *event) This property is false by default and only has any effect on Mac OS X 10.4 or higher. - If set to true, then the top toolbar area is replaced with a Carbon - HIToolbar and all toolbars in the top toolbar area are moved to that. Any - toolbars added afterwards will also be added to the Carbon HIToolbar. This - means a couple of things. + If set to true, then the top toolbar area is replaced with a Carbon HIToolbar + or a Cocoa NSToolbar (depending on whether Qt was built with Carbon or Cocoa). + All toolbars in the top toolbar area and any toolbars added afterwards are + moved to that. This means a couple of things. \list \i QToolBars in this toolbar area are not movable and you cannot drag other diff --git a/src/gui/widgets/qmdiarea.cpp b/src/gui/widgets/qmdiarea.cpp index 598d3b5..6acd977 100644 --- a/src/gui/widgets/qmdiarea.cpp +++ b/src/gui/widgets/qmdiarea.cpp @@ -81,7 +81,7 @@ subwindows. This information could be used in a popup menu containing a list of windows, for example. - The subwindows are sorted by the the current + The subwindows are sorted by the current \l{QMdiArea::}{WindowOrder}. This is used for the subWindowList() and for activateNextSubWindow() and acivatePreviousSubWindow(). Also, it is used when cascading or tiling the windows with diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm index d2aad99..cce083f 100644 --- a/src/gui/widgets/qmenu_mac.mm +++ b/src/gui/widgets/qmenu_mac.mm @@ -142,6 +142,39 @@ static int qt_mac_CountMenuItems(OSMenuRef menu) return 0; } +static quint32 constructModifierMask(quint32 accel_key) +{ + quint32 ret = 0; + const bool dontSwap = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta); +#ifndef QT_MAC_USE_COCOA + if ((accel_key & Qt::ALT) == Qt::ALT) + ret |= kMenuOptionModifier; + if ((accel_key & Qt::SHIFT) == Qt::SHIFT) + ret |= kMenuShiftModifier; + if (dontSwap) { + if ((accel_key & Qt::META) != Qt::META) + ret |= kMenuNoCommandModifier; + if ((accel_key & Qt::CTRL) == Qt::CTRL) + ret |= kMenuControlModifier; + } else { + if ((accel_key & Qt::CTRL) != Qt::CTRL) + ret |= kMenuNoCommandModifier; + if ((accel_key & Qt::META) == Qt::META) + ret |= kMenuControlModifier; + } +#else + if ((accel_key & Qt::CTRL) == Qt::CTRL) + ret |= (dontSwap ? NSControlKeyMask : NSCommandKeyMask); + if ((accel_key & Qt::META) == Qt::META) + ret |= (dontSwap ? NSCommandKeyMask : NSControlKeyMask); + if ((accel_key & Qt::ALT) == Qt::ALT) + ret |= NSAlternateKeyMask; + if ((accel_key & Qt::SHIFT) == Qt::SHIFT) + ret |= NSShiftKeyMask; +#endif + return ret; +} + static bool actualMenuItemVisibility(const QMenuBarPrivate::QMacMenuBarPrivate *mbp, const QMacMenuAction *action) { @@ -525,15 +558,7 @@ static bool qt_mac_auto_apple_menu(MenuCommand cmd) static void qt_mac_get_accel(quint32 accel_key, quint32 *modif, quint32 *key) { if (modif) { - *modif = 0; - if ((accel_key & Qt::CTRL) != Qt::CTRL) - *modif |= kMenuNoCommandModifier; - if ((accel_key & Qt::META) == Qt::META) - *modif |= kMenuControlModifier; - if ((accel_key & Qt::ALT) == Qt::ALT) - *modif |= kMenuOptionModifier; - if ((accel_key & Qt::SHIFT) == Qt::SHIFT) - *modif |= kMenuShiftModifier; + *modif = constructModifierMask(accel_key); } accel_key &= ~(Qt::MODIFIER_MASK | Qt::UNICODE_ACCEL); @@ -928,14 +953,14 @@ static QKeySequence qt_mac_menu_merge_accel(QMacMenuAction *action) ret = action->action->shortcut(); #ifndef QT_MAC_USE_COCOA else if (action->command == kHICommandPreferences) - ret = QKeySequence(Qt::CTRL+Qt::Key_Comma); + ret = QKeySequence(QKeySequence::Preferences); else if (action->command == kHICommandQuit) - ret = QKeySequence(Qt::CTRL+Qt::Key_Q); + ret = QKeySequence(QKeySequence::Quit); #else else if (action->menuItem == [loader preferencesMenuItem]) - ret = QKeySequence(Qt::CTRL+Qt::Key_Comma); + ret = QKeySequence(QKeySequence::Preferences); else if (action->menuItem == [loader quitMenuItem]) - ret = QKeySequence(Qt::CTRL+Qt::Key_Q); + ret = QKeySequence(QKeySequence::Quit); #endif return ret; } @@ -1220,58 +1245,21 @@ QMenuPrivate::QMacMenuPrivate::addAction(QMacMenuAction *action, QMacMenuAction NSString *keySequenceToKeyEqivalent(const QKeySequence &accel) { quint32 accel_key = (accel[0] & ~(Qt::MODIFIER_MASK | Qt::UNICODE_ACCEL)); - unichar keyEquiv[1] = { 0 }; - if (accel_key == Qt::Key_Return) - keyEquiv[0] = kReturnCharCode; - else if (accel_key == Qt::Key_Enter) - keyEquiv[0] = kEnterCharCode; - else if (accel_key == Qt::Key_Tab) - keyEquiv[0] = kTabCharCode; - else if (accel_key == Qt::Key_Backspace) - keyEquiv[0] = kBackspaceCharCode; - else if (accel_key == Qt::Key_Delete) - keyEquiv[0] = NSDeleteFunctionKey; - else if (accel_key == Qt::Key_Escape) - keyEquiv[0] = kEscapeCharCode; - else if (accel_key == Qt::Key_PageUp) - keyEquiv[0] = NSPageUpFunctionKey; - else if (accel_key == Qt::Key_PageDown) - keyEquiv[0] = NSPageDownFunctionKey; - else if (accel_key == Qt::Key_Up) - keyEquiv[0] = NSUpArrowFunctionKey; - else if (accel_key == Qt::Key_Down) - keyEquiv[0] = NSDownArrowFunctionKey; - else if (accel_key == Qt::Key_Left) - keyEquiv[0] = NSLeftArrowFunctionKey; - else if (accel_key == Qt::Key_Right) - keyEquiv[0] = NSRightArrowFunctionKey; - else if (accel_key == Qt::Key_CapsLock) - keyEquiv[0] = kMenuCapsLockGlyph; // ### Cocoa has no equivalent - else if (accel_key >= Qt::Key_F1 && accel_key <= Qt::Key_F15) - keyEquiv[0] = (accel_key - Qt::Key_F1) + NSF1FunctionKey; - else if (accel_key == Qt::Key_Home) - keyEquiv[0] = NSHomeFunctionKey; - else if (accel_key == Qt::Key_End) - keyEquiv[0] = NSEndFunctionKey; - else - keyEquiv[0] = unichar(QChar(accel_key).toLower().unicode()); - return [NSString stringWithCharacters:keyEquiv length:1]; + extern QChar qt_macSymbolForQtKey(int key); // qkeysequence.cpp + QChar keyEquiv = qt_macSymbolForQtKey(accel_key); + if (keyEquiv.isNull()) { + if (accel_key >= Qt::Key_F1 && accel_key <= Qt::Key_F15) + keyEquiv = (accel_key - Qt::Key_F1) + NSF1FunctionKey; + else + keyEquiv = unichar(QChar(accel_key).toLower().unicode()); + } + return [NSString stringWithCharacters:&keyEquiv.unicode() length:1]; } // return the cocoa modifier mask for the QKeySequence (currently only looks at the first one). NSUInteger keySequenceModifierMask(const QKeySequence &accel) { - NSUInteger ret = 0; - quint32 accel_key = accel[0]; - if ((accel_key & Qt::CTRL) == Qt::CTRL) - ret |= NSCommandKeyMask; - if ((accel_key & Qt::META) == Qt::META) - ret |= NSControlKeyMask; - if ((accel_key & Qt::ALT) == Qt::ALT) - ret |= NSAlternateKeyMask; - if ((accel_key & Qt::SHIFT) == Qt::SHIFT) - ret |= NSShiftKeyMask; - return ret; + return constructModifierMask(accel[0]); } void diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index dddd83e..edfeee7 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -208,7 +208,7 @@ public: QString searchBuffer; QBasicTimer searchBufferTimer; - //passing of mouse events up the parent heirarchy + //passing of mouse events up the parent hierarchy QPointer<QMenu> activeMenu; bool mouseEventTaken(QMouseEvent *); diff --git a/src/gui/widgets/qmenu_wince.cpp b/src/gui/widgets/qmenu_wince.cpp index 315bd51..2ce89f9 100644 --- a/src/gui/widgets/qmenu_wince.cpp +++ b/src/gui/widgets/qmenu_wince.cpp @@ -58,6 +58,9 @@ #include <QtCore/qlibrary.h> #include <commctrl.h> +#if Q_OS_WINCE_WM +# include <windowsm.h> +#endif #include "qguifunctions_wince.h" @@ -71,6 +74,12 @@ #define SHCMBM_GETSUBMENU (WM_USER + 401) #endif +#ifdef Q_OS_WINCE_WM +# define SHMBOF_NODEFAULT 0x00000001 +# define SHMBOF_NOTIFY 0x00000002 +# define SHCMBM_OVERRIDEKEY (WM_USER + 0x193) +#endif + extern bool qt_wince_is_smartphone();//defined in qguifunctions_wce.cpp extern bool qt_wince_is_pocket_pc(); //defined in qguifunctions_wce.cpp @@ -204,8 +213,15 @@ static HWND qt_wce_create_menubar(HWND parentHandle, HINSTANCE resourceHandle, i mbi.dwFlags = flags; mbi.nToolBarId = toolbarID; - if (ptrCreateMenuBar(&mbi)) + if (ptrCreateMenuBar(&mbi)) { +#ifdef Q_OS_WINCE_WM + // Tell the menu bar that we want to override hot key behaviour. + LPARAM lparam = MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, + SHMBOF_NODEFAULT | SHMBOF_NOTIFY); + SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TBACK, lparam); +#endif return mbi.hwndMB; + } } return 0; } diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index d4de5bd..cffc3d5 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -1273,6 +1273,8 @@ void QMenuBar::actionEvent(QActionEvent *e) #else QMenuBarPrivate::QWceMenuBarPrivate *nativeMenuBar = d->wce_menubar; #endif + if (!nativeMenuBar) + return; if(e->type() == QEvent::ActionAdded) nativeMenuBar->addAction(e->action(), nativeMenuBar->findAction(e->before())); else if(e->type() == QEvent::ActionRemoved) @@ -2418,7 +2420,7 @@ int QMenuBar::findIdForAction(QAction *act) const /*! \fn int QMenuBar::margin() const - Returns the with of the the margin around the contents of the widget. + Returns the width of the margin around the contents of the widget. Use QWidget::getContentsMargins() instead. \sa setMargin(), QWidget::getContentsMargins() diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp index a51ed2d..f317742 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -560,7 +560,8 @@ QRectF QPlainTextEditControl::blockBoundingRect(const QTextBlock &block) const { if (!currentBlock.isValid()) return QRectF(); Q_ASSERT(currentBlock.blockNumber() == currentBlockNumber); - QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout()); + QTextDocument *doc = document(); + QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout()); Q_ASSERT(documentLayout); QPointF offset; @@ -571,13 +572,22 @@ QRectF QPlainTextEditControl::blockBoundingRect(const QTextBlock &block) const { offset.ry() += r.height(); currentBlock = currentBlock.next(); ++currentBlockNumber; + if (!currentBlock.isVisible()) { + currentBlock = doc->findBlockByLineNumber(currentBlock.firstLineNumber()); + currentBlockNumber = currentBlock.blockNumber(); + } r = documentLayout->blockBoundingRect(currentBlock); } while (currentBlockNumber > blockNumber && offset.y() >= -textEdit->viewport()->height()) { currentBlock = currentBlock.previous(); + --currentBlockNumber; + while (!currentBlock.isVisible()) { + currentBlock = currentBlock.previous(); + --currentBlockNumber; + } if (!currentBlock.isValid()) break; - --currentBlockNumber; + r = documentLayout->blockBoundingRect(currentBlock); offset.ry() -= r.height(); } @@ -629,7 +639,7 @@ void QPlainTextEditPrivate::setTopBlock(int blockNumber, int lineNumber, int dx) if (viewport->updatesEnabled() && viewport->isVisible()) { int dy = 0; - if (doc->findBlockByLineNumber(control->topBlock).isValid()) { + if (doc->findBlockByNumber(control->topBlock).isValid()) { dy = (int)(-q->blockBoundingGeometry(block).y()) + verticalOffset() - verticalOffset(blockNumber, lineNumber); } diff --git a/src/gui/widgets/qprintpreviewwidget.cpp b/src/gui/widgets/qprintpreviewwidget.cpp index 16334b8..d4e5122 100644 --- a/src/gui/widgets/qprintpreviewwidget.cpp +++ b/src/gui/widgets/qprintpreviewwidget.cpp @@ -98,29 +98,8 @@ void PageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QRectF paperRect(0,0, paperSize.width(), paperSize.height()); - painter->setClipRect(paperRect & option->exposedRect); - painter->fillRect(paperRect, Qt::white); - if (!pagePicture) - return; - painter->drawPicture(pageRect.topLeft(), *pagePicture); - - // Effect: make anything drawn in the margins look washed out. - QPainterPath path; - path.addRect(paperRect); - path.addRect(pageRect); - painter->setPen(QPen(Qt::NoPen)); - painter->setBrush(QColor(255, 255, 255, 180)); - painter->drawPath(path); - - painter->setClipRect(option->exposedRect); -#if 0 - // Draw frame around paper. - painter->setPen(QPen(Qt::black, 0)); - painter->setBrush(Qt::NoBrush); - painter->drawRect(paperRect); -#endif - // Draw shadow + painter->setClipRect(option->exposedRect); qreal shWidth = paperRect.width()/100; QRectF rshadow(paperRect.topRight() + QPointF(0, shWidth), paperRect.bottomRight() + QPointF(shWidth, 0)); @@ -141,6 +120,27 @@ void PageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, cgrad.setColorAt(1.0, QColor(0,0,0,0)); painter->fillRect(cshadow, QBrush(cgrad)); + painter->setClipRect(paperRect & option->exposedRect); + painter->fillRect(paperRect, Qt::white); + if (!pagePicture) + return; + painter->drawPicture(pageRect.topLeft(), *pagePicture); + + // Effect: make anything drawn in the margins look washed out. + QPainterPath path; + path.addRect(paperRect); + path.addRect(pageRect); + painter->setPen(QPen(Qt::NoPen)); + painter->setBrush(QColor(255, 255, 255, 180)); + painter->drawPath(path); + +#if 0 + // Draw frame around paper. + painter->setPen(QPen(Qt::black, 0)); + painter->setBrush(Qt::NoBrush); + painter->drawRect(paperRect); +#endif + // todo: drawtext "Page N" below paper } diff --git a/src/gui/widgets/qprogressbar.cpp b/src/gui/widgets/qprogressbar.cpp index cdb3836..804220d 100644 --- a/src/gui/widgets/qprogressbar.cpp +++ b/src/gui/widgets/qprogressbar.cpp @@ -448,19 +448,19 @@ QString QProgressBar::text() const qint64 totalSteps = qint64(d->maximum) - qint64(d->minimum); QString result = d->format; - result.replace(QLatin1String("%m"), QString::fromLatin1("%1").arg(totalSteps)); - result.replace(QLatin1String("%v"), QString::fromLatin1("%1").arg(d->value)); + result.replace(QLatin1String("%m"), QString::number(totalSteps)); + result.replace(QLatin1String("%v"), QString::number(d->value)); // If max and min are equal and we get this far, it means that the // progress bar has one step and that we are on that step. Return // 100% here in order to avoid division by zero further down. if (totalSteps == 0) { - result.replace(QLatin1String("%p"), QString::fromLatin1("%1").arg(100)); + result.replace(QLatin1String("%p"), QString::number(100)); return result; } int progress = int(((qreal(d->value) - qreal(d->minimum)) * 100.0) / totalSteps); - result.replace(QLatin1String("%p"), QString::fromLatin1("%1").arg(progress)); + result.replace(QLatin1String("%p"), QString::number(progress)); return result; } diff --git a/src/gui/widgets/qpushbutton.cpp b/src/gui/widgets/qpushbutton.cpp index 03ca751..ca58f87 100644 --- a/src/gui/widgets/qpushbutton.cpp +++ b/src/gui/widgets/qpushbutton.cpp @@ -527,8 +527,7 @@ void QPushButton::setMenu(QMenu* menu) return; if (menu && !d->menu) { - disconnect(this, SIGNAL(pressed()), this, SLOT(_q_popupPressed())); - connect(this, SIGNAL(pressed()), this, SLOT(_q_popupPressed())); + connect(this, SIGNAL(pressed()), this, SLOT(_q_popupPressed()), Qt::UniqueConnection); } if (d->menu) removeAction(d->menu->menuAction()); diff --git a/src/gui/widgets/qscrollarea.cpp b/src/gui/widgets/qscrollarea.cpp index 6aca7d3..8b01453 100644 --- a/src/gui/widgets/qscrollarea.cpp +++ b/src/gui/widgets/qscrollarea.cpp @@ -127,7 +127,7 @@ QT_BEGIN_NAMESPACE setting the layout's \l{QLayout::sizeConstraint}{size constraint} property to one which provides constraints on the minimum and/or maximum size of the layout (e.g., QLayout::SetMinAndMaxSize) will - cause the size of the the scroll area to be updated whenever the + cause the size of the scroll area to be updated whenever the contents of the layout changes. For a complete example using the QScrollArea class, see the \l diff --git a/src/gui/widgets/qslider.cpp b/src/gui/widgets/qslider.cpp index 32b9021..5b9c8a4 100644 --- a/src/gui/widgets/qslider.cpp +++ b/src/gui/widgets/qslider.cpp @@ -62,7 +62,6 @@ public: int tickInterval; QSlider::TickPosition tickPosition; int clickOffset; - int snapBackPosition; void init(); void resetLayoutItemMargins(); int pixelPosToRangeValue(int pos) const; @@ -493,7 +492,6 @@ void QSlider::mousePressEvent(QMouseEvent *ev) setRepeatAction(SliderNoAction); QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); d->clickOffset = d->pick(ev->pos() - sr.topLeft()); - d->snapBackPosition = d->position; update(sr); setSliderDown(true); } @@ -513,14 +511,6 @@ void QSlider::mouseMoveEvent(QMouseEvent *ev) int newPosition = d->pixelPosToRangeValue(d->pick(ev->pos()) - d->clickOffset); QStyleOptionSlider opt; initStyleOption(&opt); - int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this); - if (m >= 0) { - QRect r = rect(); - r.adjust(-m, -m, m, m); - if (!r.contains(ev->pos())) { - newPosition = d->snapBackPosition; - } - } setSliderPosition(newPosition); } diff --git a/src/gui/widgets/qspinbox.cpp b/src/gui/widgets/qspinbox.cpp index c691eaf..f12946c 100644 --- a/src/gui/widgets/qspinbox.cpp +++ b/src/gui/widgets/qspinbox.cpp @@ -1030,7 +1030,7 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, { if (cachedText == input && !input.isEmpty()) { state = cachedState; - QSBDEBUG() << "cachedText was" << "'" << cachedText << "'" << "state was " + QSBDEBUG() << "cachedText was '" << cachedText << "' state was " << state << " and value was " << cachedValue; return cachedValue; @@ -1048,7 +1048,7 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, || (min >= 0 && copy == QLatin1String("+")))) { state = QValidator::Intermediate; QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num; - } else if (copy.startsWith(QLatin1String("-")) && min >= 0) { + } else if (copy.startsWith(QLatin1Char('-')) && min >= 0) { state = QValidator::Invalid; // special-case -0 will be interpreted as 0 and thus not be invalid with a range from 0-100 } else { bool ok = false; @@ -1254,9 +1254,7 @@ QVariant QDoubleSpinBoxPrivate::valueFromText(const QString &f) const double QDoubleSpinBoxPrivate::round(double value) const { - Q_Q(const QDoubleSpinBox); - const QString strDbl = q->locale().toString(value, 'f', decimals); - return q->locale().toDouble(strDbl); + return QString::number(value, 'f', decimals).toDouble(); } @@ -1271,7 +1269,7 @@ QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, { if (cachedText == input && !input.isEmpty()) { state = cachedState; - QSBDEBUG() << "cachedText was" << "'" << cachedText << "'" << "state was " + QSBDEBUG() << "cachedText was '" << cachedText << "' state was " << state << " and value was " << cachedValue; return cachedValue; } diff --git a/src/gui/widgets/qsplitter.cpp b/src/gui/widgets/qsplitter.cpp index 06774bc..400d78a 100644 --- a/src/gui/widgets/qsplitter.cpp +++ b/src/gui/widgets/qsplitter.cpp @@ -1525,7 +1525,7 @@ void QSplitter::setOpaqueResize(bool on) /*! \fn int QSplitter::margin() const - Returns the with of the the margin around the contents of the widget. + Returns the width of the margin around the contents of the widget. Use QWidget::getContentsMargins() instead. \sa setMargin(), QWidget::getContentsMargins() diff --git a/src/gui/widgets/qtabbar.cpp b/src/gui/widgets/qtabbar.cpp index 49de8c1..bd8a1b0 100644 --- a/src/gui/widgets/qtabbar.cpp +++ b/src/gui/widgets/qtabbar.cpp @@ -176,12 +176,11 @@ void QTabBar::initStyleOption(QStyleOptionTab *option, int tabIndex) const if (tw->cornerWidget(Qt::TopRightCorner) || tw->cornerWidget(Qt::BottomRightCorner)) option->cornerWidgets |= QStyleOptionTab::RightCornerWidget; } +#endif QRect textRect = style()->subElementRect(QStyle::SE_TabBarTabText, option, this); - option->text = fontMetrics().elidedText(option->text, d->elideMode, textRect.width(), Qt::TextShowMnemonic); -#endif } /*! @@ -1085,7 +1084,7 @@ void QTabBar::setTabData(int index, const QVariant & data) } /*! - Returns the datad of the tab at position \a index, or a null + Returns the data of the tab at position \a index, or a null variant if \a index is out of range. */ QVariant QTabBar::tabData(int index) const @@ -1536,9 +1535,10 @@ void QTabBar::paintEvent(QPaintEvent *) } if (!d->dragInProgress) p.drawControl(QStyle::CE_TabBarTab, tab); - else - d->movingTab->setGeometry(tab.rect); - + else { + int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0, this); + d->movingTab->setGeometry(tab.rect.adjusted(-taboverlap, 0, taboverlap, 0)); + } } // Only draw the tear indicator if necessary. Most of the time we don't need too. @@ -1805,7 +1805,9 @@ void QTabBarPrivate::setupMovableTab() if (!movingTab) movingTab = new QWidget(q); + int taboverlap = q->style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0 ,q); QRect grabRect = q->tabRect(pressedIndex); + grabRect.adjust(-taboverlap, 0, taboverlap, 0); QPixmap grabImage(grabRect.size()); grabImage.fill(Qt::transparent); @@ -1813,7 +1815,7 @@ void QTabBarPrivate::setupMovableTab() QStyleOptionTabV3 tab; q->initStyleOption(&tab, pressedIndex); - tab.rect.moveTopLeft(QPoint(0, 0)); + tab.rect.moveTopLeft(QPoint(taboverlap, 0)); p.drawControl(QStyle::CE_TabBarTab, tab); p.end(); @@ -2224,6 +2226,7 @@ void QTabBar::setTabButton(int index, ButtonPosition position, QWidget *widget) d->tabList[index].rightWidget = widget; } d->layoutTabs(); + d->refresh(); update(); } diff --git a/src/gui/widgets/qtabwidget.cpp b/src/gui/widgets/qtabwidget.cpp index c16e000..43b2f54 100644 --- a/src/gui/widgets/qtabwidget.cpp +++ b/src/gui/widgets/qtabwidget.cpp @@ -504,7 +504,7 @@ QIcon QTabWidget::tabIcon(int index) const } /*! - Returns true if the the page at position \a index is enabled; otherwise returns false. + Returns true if the page at position \a index is enabled; otherwise returns false. \sa setTabEnabled(), QWidget::isEnabled() */ diff --git a/src/gui/widgets/qtoolbar.cpp b/src/gui/widgets/qtoolbar.cpp index fadccbc..d765794 100644 --- a/src/gui/widgets/qtoolbar.cpp +++ b/src/gui/widgets/qtoolbar.cpp @@ -274,9 +274,11 @@ void QToolBarPrivate::endDrag() bool QToolBarPrivate::mousePressEvent(QMouseEvent *event) { - if (layout->handleRect().contains(event->pos()) == false) { + Q_Q(QToolBar); + QStyleOptionToolBar opt; + q->initStyleOption(&opt); + if (q->style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, q).contains(event->pos()) == false) { #ifdef Q_WS_MAC - Q_Q(QToolBar); // When using the unified toolbar on Mac OS X the user can can click and // drag between toolbar contents to move the window. Make this work by // implementing the standard mouse-dragging code and then call @@ -1041,7 +1043,7 @@ void QToolBar::paintEvent(QPaintEvent *) style->drawControl(QStyle::CE_ToolBar, &opt, &p, this); } - opt.rect = d->layout->handleRect(); + opt.rect = style->subElementRect(QStyle::SE_ToolBarHandle, &opt, this); if (opt.rect.isValid()) style->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this); } @@ -1142,7 +1144,9 @@ bool QToolBar::event(QEvent *event) case QEvent::HoverMove: { #ifndef QT_NO_CURSOR QHoverEvent *e = static_cast<QHoverEvent*>(event); - if (d->layout->handleRect().contains(e->pos())) + QStyleOptionToolBar opt; + initStyleOption(&opt); + if (style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, this).contains(e->pos())) setCursor(Qt::SizeAllCursor); else unsetCursor(); diff --git a/src/gui/widgets/qtoolbarlayout.cpp b/src/gui/widgets/qtoolbarlayout.cpp index 7771f46..0bfa493 100644 --- a/src/gui/widgets/qtoolbarlayout.cpp +++ b/src/gui/widgets/qtoolbarlayout.cpp @@ -334,7 +334,7 @@ void QToolBarLayout::updateGeomArray() const if (QMainWindow *mw = qobject_cast<QMainWindow *>(parentWidget()->parentWidget())) { if (mw->unifiedTitleAndToolBarOnMac() && mw->toolBarArea(static_cast<QToolBar *>(parentWidget())) == Qt::TopToolBarArea) { - if (that->expandFlag) { + if (expandFlag) { tb->setMaximumSize(0xFFFFFF, 0xFFFFFF); } else { tb->setMaximumSize(hint); @@ -360,23 +360,11 @@ void QToolBarLayout::setGeometry(const QRect &rect) QStyle *style = tb->style(); QStyleOptionToolBar opt; tb->initStyleOption(&opt); - const int handleExtent = movable() - ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0; const int margin = this->margin(); const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb); Qt::Orientation o = tb->orientation(); QLayout::setGeometry(rect); - if (movable()) { - if (o == Qt::Horizontal) { - handRect = QRect(margin, margin, handleExtent, rect.height() - 2*margin); - handRect = QStyle::visualRect(parentWidget()->layoutDirection(), rect, handRect); - } else { - handRect = QRect(margin, margin, rect.width() - 2*margin, handleExtent); - } - } else { - handRect = QRect(); - } bool ranOutOfSpace = false; if (!animating) @@ -742,11 +730,6 @@ QToolBarItem *QToolBarLayout::createItem(QAction *action) return result; } -QRect QToolBarLayout::handleRect() const -{ - return handRect; -} - QT_END_NAMESPACE #endif // QT_NO_TOOLBAR diff --git a/src/gui/widgets/qtoolbarlayout_p.h b/src/gui/widgets/qtoolbarlayout_p.h index 2eca773..37755b1 100644 --- a/src/gui/widgets/qtoolbarlayout_p.h +++ b/src/gui/widgets/qtoolbarlayout_p.h @@ -65,7 +65,7 @@ class QAction; class QToolBarExtension; class QMenu; -class Q_GUI_EXPORT QToolBarItem : public QWidgetItem +class QToolBarItem : public QWidgetItem { public: QToolBarItem(QWidget *widget); @@ -75,7 +75,7 @@ public: bool customWidget; }; -class Q_GUI_EXPORT QToolBarLayout : public QLayout +class QToolBarLayout : public QLayout { Q_OBJECT @@ -100,8 +100,6 @@ public: int indexOf(QAction *action) const; int indexOf(QWidget *widget) const { return QLayout::indexOf(widget); } - QRect handleRect() const; - bool layoutActions(const QSize &size); QSize expandedSize(const QSize &size) const; bool expanded, animating; diff --git a/src/gui/widgets/qtoolbox.cpp b/src/gui/widgets/qtoolbox.cpp index 81935a5..271130a 100644 --- a/src/gui/widgets/qtoolbox.cpp +++ b/src/gui/widgets/qtoolbox.cpp @@ -802,7 +802,7 @@ void QToolBox::itemRemoved(int index) /*! \fn int QToolBox::margin() const - Returns the with of the the margin around the contents of the widget. + Returns the width of the margin around the contents of the widget. Use QWidget::getContentsMargins() instead. \sa setMargin(), QWidget::getContentsMargins() diff --git a/src/network/access/qhttp.cpp b/src/network/access/qhttp.cpp index 96ccc91..49ce5a3 100644 --- a/src/network/access/qhttp.cpp +++ b/src/network/access/qhttp.cpp @@ -64,10 +64,10 @@ # include "qtimer.h" #endif -QT_BEGIN_NAMESPACE - #ifndef QT_NO_HTTP +QT_BEGIN_NAMESPACE + class QHttpNormalRequest; class QHttpRequest { @@ -950,7 +950,7 @@ void QHttpHeader::setContentLength(int len) } /*! - Returns true if the header has an entry for the the special HTTP + Returns true if the header has an entry for the special HTTP header field \c content-type; otherwise returns false. \sa contentType() setContentType() @@ -1446,7 +1446,7 @@ QString QHttpRequestHeader::toString() const that indicates if the request finished with an error. To make an HTTP request you must set up suitable HTTP headers. The - following example demonstrates, how to request the main HTML page + following example demonstrates how to request the main HTML page from the Trolltech home page (i.e., the URL \c http://qtsoftware.com/index.html): diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 5940fba..43fbb16 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qhttpnetworkconnection_p.h" +#include "private/qnoncontiguousbytedevice_p.h" #include <private/qnetworkrequest_p.h> #include <private/qobject_p.h> #include <private/qauthenticator_p.h> @@ -71,6 +72,7 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host #ifndef QT_NO_NETWORKPROXY , networkProxy(QNetworkProxy::NoProxy) #endif + { } @@ -205,12 +207,19 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair) // add missing fields for the request QByteArray value; // check if Content-Length is provided - QIODevice *data = request.data(); - if (data && request.contentLength() == -1) { - if (!data->isSequential()) - request.setContentLength(data->size()); - else - bufferData(messagePair); // ### or do chunked upload + QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice(); + if (uploadByteDevice) { + if (request.contentLength() != -1 && uploadByteDevice->size() != -1) { + // both values known, take the smaller one. + request.setContentLength(qMin(uploadByteDevice->size(), request.contentLength())); + } else if (request.contentLength() == -1 && uploadByteDevice->size() != -1) { + // content length not supplied by user, but the upload device knows it + request.setContentLength(uploadByteDevice->size()); + } else if (request.contentLength() != -1 && uploadByteDevice->size() == -1) { + // everything OK, the user supplied us the contentLength + } else if (request.contentLength() == -1 && uploadByteDevice->size() == -1) { + qFatal("QHttpNetworkConnectionPrivate: Neither content-length nor upload device size were given"); + } } // set the Connection/Proxy-Connection: Keep-Alive headers #ifndef QT_NO_NETWORKPROXY @@ -361,18 +370,12 @@ bool QHttpNetworkConnectionPrivate::sendRequest(QAbstractSocket *socket) false); #endif socket->write(header); - QIODevice *data = channels[i].request.d->data; - QHttpNetworkReply *reply = channels[i].reply; - if (reply && reply->d_func()->requestDataBuffer.size()) - data = &channels[i].reply->d_func()->requestDataBuffer; - if (data && (data->isOpen() || data->open(QIODevice::ReadOnly))) { - if (data->isSequential()) { - channels[i].bytesTotal = -1; - QObject::connect(data, SIGNAL(readyRead()), q, SLOT(_q_dataReadyReadNoBuffer())); - QObject::connect(data, SIGNAL(readChannelFinished()), q, SLOT(_q_dataReadyReadNoBuffer())); - } else { - channels[i].bytesTotal = data->size(); - } + QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice(); + if (uploadByteDevice) { + // connect the signals so this function gets called again + QObject::connect(uploadByteDevice, SIGNAL(readyRead()), q, SLOT(_q_uploadDataReadyRead())); + + channels[i].bytesTotal = channels[i].request.contentLength(); } else { channels[i].state = WaitingState; break; @@ -380,30 +383,81 @@ bool QHttpNetworkConnectionPrivate::sendRequest(QAbstractSocket *socket) // write the initial chunk together with the headers // fall through } - case WritingState: { // write the data - QIODevice *data = channels[i].request.d->data; - if (channels[i].reply->d_func()->requestDataBuffer.size()) - data = &channels[i].reply->d_func()->requestDataBuffer; - if (!data || channels[i].bytesTotal == channels[i].written) { + case WritingState: + { + // write the data + QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice(); + if (!uploadByteDevice || channels[i].bytesTotal == channels[i].written) { + if (uploadByteDevice) + emit channels[i].reply->dataSendProgress(channels[i].written, channels[i].bytesTotal); channels[i].state = WaitingState; // now wait for response + sendRequest(socket); break; } - QByteArray chunk; - chunk.resize(ChunkSize); - qint64 readSize = data->read(chunk.data(), ChunkSize); - if (readSize == -1) { - // source has reached EOF - channels[i].state = WaitingState; // now wait for response - } else if (readSize > 0) { - // source gave us something useful - channels[i].written += socket->write(chunk.data(), readSize); - if (channels[i].reply) - emit channels[i].reply->dataSendProgress(channels[i].written, channels[i].bytesTotal); + // only feed the QTcpSocket buffer when there is less than 32 kB in it + const qint64 socketBufferFill = 32*1024; + const qint64 socketWriteMaxSize = 16*1024; + + +#ifndef QT_NO_OPENSSL + QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket); + while ((sslSocket->encryptedBytesToWrite() + sslSocket->bytesToWrite()) <= socketBufferFill + && channels[i].bytesTotal != channels[i].written) +#else + while (socket->bytesToWrite() <= socketBufferFill + && channels[i].bytesTotal != channels[i].written) +#endif + { + // get pointer to upload data + qint64 currentReadSize; + qint64 desiredReadSize = qMin(socketWriteMaxSize, channels[i].bytesTotal - channels[i].written); + const char *readPointer = uploadByteDevice->readPointer(desiredReadSize, currentReadSize); + + if (currentReadSize == -1) { + // premature eof happened + emitReplyError(socket, channels[i].reply, QNetworkReply::UnknownNetworkError); + return false; + break; + } else if (readPointer == 0 || currentReadSize == 0) { + // nothing to read currently, break the loop + break; + } else { + qint64 currentWriteSize = socket->write(readPointer, currentReadSize); + if (currentWriteSize == -1 || currentWriteSize != currentReadSize) { + // socket broke down + emitReplyError(socket, channels[i].reply, QNetworkReply::UnknownNetworkError); + return false; + } else { + channels[i].written += currentWriteSize; + uploadByteDevice->advanceReadPointer(currentWriteSize); + + emit channels[i].reply->dataSendProgress(channels[i].written, channels[i].bytesTotal); + + if (channels[i].written == channels[i].bytesTotal) { + // make sure this function is called once again + channels[i].state = WaitingState; + sendRequest(socket); + break; + } + } + } } break; } + case WaitingState: + { + QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice(); + if (uploadByteDevice) { + QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), q, SLOT(_q_uploadDataReadyRead())); + } + // ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called + // this is needed if the sends an reply before we have finished sending the request. In that + // case receiveReply had been called before but ignored the server reply + receiveReply(socket, channels[i].reply); + break; + } case ReadingState: case Wait4AuthState: // ignore _q_bytesWritten in these states @@ -479,6 +533,9 @@ bool QHttpNetworkConnectionPrivate::expand(QAbstractSocket *socket, QHttpNetwork // make sure that the reply is valid if (channels[i].reply != reply) return true; + // emit dataReadProgress signal (signal is currently not connected + // to the rest of QNAM) since readProgress of the + // QNonContiguousByteDevice is used emit reply->dataReadProgress(reply->d_func()->totalProgress, 0); // make sure that the reply is valid if (channels[i].reply != reply) @@ -529,10 +586,20 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN QHttpNetworkReplyPrivate::ReplyState state = reply ? reply->d_func()->state : QHttpNetworkReplyPrivate::AllDoneState; switch (state) { case QHttpNetworkReplyPrivate::NothingDoneState: - case QHttpNetworkReplyPrivate::ReadingStatusState: - bytes += reply->d_func()->readStatus(socket); + case QHttpNetworkReplyPrivate::ReadingStatusState: { + qint64 statusBytes = reply->d_func()->readStatus(socket); + if (statusBytes == -1) { + // error reading the status, close the socket and emit error + socket->close(); + reply->d_func()->errorString = errorDetail(QNetworkReply::ProtocolFailure, socket); + emit reply->finishedWithError(QNetworkReply::ProtocolFailure, reply->d_func()->errorString); + QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); + break; + } + bytes += statusBytes; channels[i].lastStatus = reply->d_func()->statusCode; break; + } case QHttpNetworkReplyPrivate::ReadingHeaderState: bytes += reply->d_func()->readHeader(socket); if (reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) { @@ -569,6 +636,9 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN // make sure that the reply is valid if (channels[i].reply != reply) return; + // emit dataReadProgress signal (signal is currently not connected + // to the rest of QNAM) since readProgress of the + // QNonContiguousByteDevice is used emit reply->dataReadProgress(reply->d_func()->totalProgress, reply->d_func()->bodyLength); // make sure that the reply is valid if (channels[i].reply != reply) @@ -633,10 +703,37 @@ void QHttpNetworkConnectionPrivate::handleStatus(QAbstractSocket *socket, QHttpN switch (statusCode) { case 401: case 407: - handleAuthenticateChallenge(socket, reply, (statusCode == 407), resend); - if (resend) { - eraseData(reply); - sendRequest(socket); + if (handleAuthenticateChallenge(socket, reply, (statusCode == 407), resend)) { + if (resend) { + int i = indexOf(socket); + + QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice(); + if (uploadByteDevice) { + if (uploadByteDevice->reset()) { + channels[i].written = 0; + } else { + emitReplyError(socket, reply, QNetworkReply::ContentReSendError); + break; + } + } + + eraseData(reply); + + // also use async _q_startNextRequest so we dont break with closed + // proxy or server connections.. + channels[i].resendCurrent = true; + QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); + } + } else { + int i = indexOf(socket); + emit channels[i].reply->headerChanged(); + emit channels[i].reply->readyRead(); + QNetworkReply::NetworkError errorCode = (statusCode == 407) + ? QNetworkReply::ProxyAuthenticationRequiredError + : QNetworkReply::AuthenticationRequiredError; + reply->d_func()->errorString = errorDetail(errorCode, socket); + emit q->error(errorCode, reply->d_func()->errorString); + emit channels[i].reply->finished(); } break; default: @@ -739,7 +836,6 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket // authentication is cancelled, send the current contents to the user. emit channels[i].reply->headerChanged(); emit channels[i].reply->readyRead(); - emit channels[i].reply->finished(); QNetworkReply::NetworkError errorCode = isProxy ? QNetworkReply::ProxyAuthenticationRequiredError @@ -970,6 +1066,7 @@ void QHttpNetworkConnectionPrivate::_q_bytesWritten(qint64 bytes) QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender()); if (!socket) return; // ### error + // bytes have been written to the socket. write even more of them :) if (isSocketWriting(socket)) sendRequest(socket); // otherwise we do nothing @@ -1128,80 +1225,21 @@ void QHttpNetworkConnectionPrivate::_q_proxyAuthenticationRequired(const QNetwor } #endif -void QHttpNetworkConnectionPrivate::_q_dataReadyReadNoBuffer() +void QHttpNetworkConnectionPrivate::_q_uploadDataReadyRead() { Q_Q(QHttpNetworkConnection); - // data emitted either readyRead() + // upload data emitted readyRead() // find out which channel it is for - QIODevice *sender = qobject_cast<QIODevice *>(q->sender()); + QObject *sender = q->sender(); - // won't match anything if the qobject_cast above failed for (int i = 0; i < channelCount; ++i) { - if (sender == channels[i].request.data()) { + if (sender == channels[i].request.uploadByteDevice()) { sendRequest(channels[i].socket); break; } } } -void QHttpNetworkConnectionPrivate::_q_dataReadyReadBuffer() -{ - Q_Q(QHttpNetworkConnection); - QIODevice *sender = qobject_cast<QIODevice *>(q->sender()); - HttpMessagePair *thePair = 0; - for (int i = 0; !thePair && i < lowPriorityQueue.size(); ++i) - if (lowPriorityQueue.at(i).first.data() == sender) - thePair = &lowPriorityQueue[i]; - - for (int i = 0; !thePair && i < highPriorityQueue.size(); ++i) - if (highPriorityQueue.at(i).first.data() == sender) - thePair = &highPriorityQueue[i]; - - if (thePair) { - bufferData(*thePair); - - // are we finished buffering? - if (!thePair->second->d_func()->requestIsBuffering) - _q_startNextRequest(); - } -} - -void QHttpNetworkConnectionPrivate::bufferData(HttpMessagePair &messagePair) -{ - Q_Q(QHttpNetworkConnection); - QHttpNetworkRequest &request = messagePair.first; - QHttpNetworkReply *reply = messagePair.second; - Q_ASSERT(request.data()); - if (!reply->d_func()->requestIsBuffering) { // first time - QObject::connect(request.data(), SIGNAL(readyRead()), q, SLOT(_q_dataReadyReadBuffer())); - QObject::connect(request.data(), SIGNAL(readChannelFinished()), q, SLOT(_q_dataReadyReadBuffer())); - reply->d_func()->requestIsBuffering = true; - reply->d_func()->requestDataBuffer.open(QIODevice::ReadWrite); - } - - // always try to read at least one byte - // ### FIXME! use a QRingBuffer - qint64 bytesToRead = qMax<qint64>(1, request.data()->bytesAvailable()); - QByteArray newData; - newData.resize(bytesToRead); - qint64 bytesActuallyRead = request.data()->read(newData.data(), bytesToRead); - - if (bytesActuallyRead > 0) { - // we read something - newData.chop(bytesToRead - bytesActuallyRead); - reply->d_func()->requestDataBuffer.write(newData); - } else if (bytesActuallyRead == -1) { // last time - QObject::disconnect(request.data(), SIGNAL(readyRead()), q, SLOT(_q_dataReadyReadBuffer())); - QObject::disconnect(request.data(), SIGNAL(readChannelFinished()), q, SLOT(_q_dataReadyReadBuffer())); - - request.setContentLength(reply->d_func()->requestDataBuffer.size()); - reply->d_func()->requestDataBuffer.seek(0); - reply->d_func()->requestIsBuffering = false; - } -} - -// QHttpNetworkConnection - QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent) : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent) { diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index 09bd459..9b127dd 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -146,8 +146,7 @@ private: #ifndef QT_NO_NETWORKPROXY Q_PRIVATE_SLOT(d_func(), void _q_proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)) #endif - Q_PRIVATE_SLOT(d_func(), void _q_dataReadyReadBuffer()) - Q_PRIVATE_SLOT(d_func(), void _q_dataReadyReadNoBuffer()) + Q_PRIVATE_SLOT(d_func(), void _q_uploadDataReadyRead()) #ifndef QT_NO_OPENSSL Q_PRIVATE_SLOT(d_func(), void _q_encrypted()) @@ -209,8 +208,8 @@ public: #ifndef QT_NO_NETWORKPROXY void _q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); // from transparent proxy #endif - void _q_dataReadyReadNoBuffer(); - void _q_dataReadyReadBuffer(); + + void _q_uploadDataReadyRead(); void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request); bool ensureConnection(QAbstractSocket *socket); @@ -219,7 +218,6 @@ public: #ifndef QT_NO_COMPRESS bool expand(QAbstractSocket *socket, QHttpNetworkReply *reply, bool dataComplete); #endif - void bufferData(HttpMessagePair &request); void removeReply(QHttpNetworkReply *reply); QString hostName; diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index fe3f6af..310994c 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -409,39 +409,62 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket) if (fragment.endsWith('\r')) { fragment.truncate(fragment.length()-1); } - parseStatus(fragment); + bool ok = parseStatus(fragment); state = ReadingHeaderState; fragment.clear(); // next fragment + + if (!ok) + return -1; break; } else { c = 0; bytes += socket->read(&c, 1); fragment.append(c); } + + // is this a valid reply? + if (fragment.length() >= 5 && !fragment.startsWith("HTTP/")) + return -1; + } + return bytes; } -void QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status) +bool QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status) { - const QByteArrayMatcher sp(" "); - int i = sp.indexIn(status); - const QByteArray version = status.mid(0, i); - int j = sp.indexIn(status, i + 1); + // from RFC 2616: + // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF + // HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT + // that makes: 'HTTP/n.n xxx Message' + // byte count: 0123456789012 + + static const int minLength = 11; + static const int dotPos = 6; + static const int spacePos = 8; + static const char httpMagic[] = "HTTP/"; + + if (status.length() < minLength + || !status.startsWith(httpMagic) + || status.at(dotPos) != '.' + || status.at(spacePos) != ' ') { + // I don't know how to parse this status line + return false; + } + + // optimize for the valid case: defer checking until the end + majorVersion = status.at(dotPos - 1) - '0'; + minorVersion = status.at(dotPos + 1) - '0'; + + int i = spacePos; + int j = status.indexOf(' ', i + 1); // j == -1 || at(j) == ' ' so j+1 == 0 && j+1 <= length() const QByteArray code = status.mid(i + 1, j - i - 1); - const QByteArray reason = status.mid(j + 1, status.count() - j); - const QByteArrayMatcher slash("/"); - int k = slash.indexIn(version); - const QByteArrayMatcher dot("."); - int l = dot.indexIn(version, k); - const QByteArray major = version.mid(k + 1, l - k - 1); - const QByteArray minor = version.mid(l + 1, version.count() - l); + bool ok; + statusCode = code.toInt(&ok); + reasonPhrase = QString::fromLatin1(status.constData() + j + 1); - majorVersion = QString::fromAscii(major.constData()).toInt(); - minorVersion = QString::fromAscii(minor.constData()).toInt(); - statusCode = QString::fromAscii(code.constData()).toInt(); - reasonPhrase = QString::fromAscii(reason.constData()); + return ok && uint(majorVersion) <= 9 && uint(minorVersion) <= 9; } qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket) @@ -521,13 +544,13 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *ou { qint64 bytes = 0; if (isChunked()) { - bytes += transferChunked(socket, out); // chunked transfer encoding (rfc 2616, sec 3.6) + bytes += readReplyBodyChunked(socket, out); // chunked transfer encoding (rfc 2616, sec 3.6) } else if (bodyLength > 0) { // we have a Content-Length - bytes += transferRaw(socket, out, bodyLength - contentRead); + bytes += readReplyBodyRaw(socket, out, bodyLength - contentRead); if (contentRead + bytes == bodyLength) state = AllDoneState; } else { - bytes += transferRaw(socket, out, socket->bytesAvailable()); + bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable()); } if (state == AllDoneState) socket->readAll(); // Read the rest to clean (CRLF) @@ -535,7 +558,7 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *ou return bytes; } -qint64 QHttpNetworkReplyPrivate::transferRaw(QIODevice *in, QIODevice *out, qint64 size) +qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *in, QIODevice *out, qint64 size) { qint64 bytes = 0; Q_ASSERT(in); @@ -561,7 +584,7 @@ qint64 QHttpNetworkReplyPrivate::transferRaw(QIODevice *in, QIODevice *out, qint } -qint64 QHttpNetworkReplyPrivate::transferChunked(QIODevice *in, QIODevice *out) +qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QIODevice *out) { qint64 bytes = 0; while (in->bytesAvailable()) { // while we can read from input @@ -660,4 +683,4 @@ void QHttpNetworkReply::ignoreSslErrors() QT_END_NAMESPACE -#endif // QT_NO_HTTP
\ No newline at end of file +#endif // QT_NO_HTTP diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index c17c65c..cc5cce8 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -139,7 +139,7 @@ Q_SIGNALS: void finishedWithError(QNetworkReply::NetworkError errorCode, const QString &detail = QString()); void headerChanged(); void dataReadProgress(int done, int total); - void dataSendProgress(int done, int total); + void dataSendProgress(qint64 done, qint64 total); private: Q_DECLARE_PRIVATE(QHttpNetworkReply) @@ -154,7 +154,7 @@ public: QHttpNetworkReplyPrivate(const QUrl &newUrl = QUrl()); ~QHttpNetworkReplyPrivate(); qint64 readStatus(QAbstractSocket *socket); - void parseStatus(const QByteArray &status); + bool parseStatus(const QByteArray &status); qint64 readHeader(QAbstractSocket *socket); void parseHeader(const QByteArray &header); qint64 readBody(QAbstractSocket *socket, QIODevice *out); @@ -162,8 +162,8 @@ public: QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const; void clear(); - qint64 transferRaw(QIODevice *in, QIODevice *out, qint64 size); - qint64 transferChunked(QIODevice *in, QIODevice *out); + qint64 readReplyBodyRaw(QIODevice *in, QIODevice *out, qint64 size); + qint64 readReplyBodyChunked(QIODevice *in, QIODevice *out); qint64 getChunkSize(QIODevice *in, qint64 *chunkSize); qint64 bytesAvailable() const; @@ -206,7 +206,6 @@ public: QByteArray responseData; // uncompressed body QByteArray compressedData; // compressed body (temporary) - QBuffer requestDataBuffer; bool requestIsBuffering; bool requestIsPrepared; }; diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index 420cb69..b9b9d84 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -40,12 +40,13 @@ ****************************************************************************/ #include "qhttpnetworkrequest_p.h" +#include "private/qnoncontiguousbytedevice_p.h" QT_BEGIN_NAMESPACE QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op, QHttpNetworkRequest::Priority pri, const QUrl &newUrl) - : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), data(0), + : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0), autoDecompress(false) { } @@ -55,7 +56,7 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest { operation = other.operation; priority = other.priority; - data = other.data; + uploadByteDevice = other.uploadByteDevice; autoDecompress = other.autoDecompress; } @@ -67,7 +68,7 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot { return QHttpNetworkHeaderPrivate::operator==(other) && (operation == other.operation) - && (data == other.data); + && (uploadByteDevice == other.uploadByteDevice); } QByteArray QHttpNetworkRequestPrivate::methodName() const @@ -109,7 +110,7 @@ QByteArray QHttpNetworkRequestPrivate::uri(bool throughProxy) const QUrl::FormattingOptions format(QUrl::RemoveFragment); // for POST, query data is send as content - if (operation == QHttpNetworkRequest::Post && !data) + if (operation == QHttpNetworkRequest::Post && !uploadByteDevice) format |= QUrl::RemoveQuery; // for requests through proxy, the Request-URI contains full url if (throughProxy) @@ -126,11 +127,11 @@ QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request { QByteArray ba = request.d->methodName(); QByteArray uri = request.d->uri(throughProxy); - ba += " " + uri; + ba += ' ' + uri; QString majorVersion = QString::number(request.majorVersion()); QString minorVersion = QString::number(request.minorVersion()); - ba += " HTTP/" + majorVersion.toLatin1() + "." + minorVersion.toLatin1() + "\r\n"; + ba += " HTTP/" + majorVersion.toLatin1() + '.' + minorVersion.toLatin1() + "\r\n"; QList<QPair<QByteArray, QByteArray> > fields = request.header(); QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin(); @@ -140,7 +141,7 @@ QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request // add content type, if not set in the request if (request.headerField("content-type").isEmpty()) ba += "Content-Type: application/x-www-form-urlencoded\r\n"; - if (!request.d->data && request.d->url.hasQuery()) { + if (!request.d->uploadByteDevice && request.d->url.hasQuery()) { QByteArray query = request.d->url.encodedQuery(); ba += "Content-Length: "+ QByteArray::number(query.size()) + "\r\n"; ba += "\r\n"; @@ -236,14 +237,14 @@ void QHttpNetworkRequest::setPriority(Priority priority) d->priority = priority; } -QIODevice *QHttpNetworkRequest::data() const +void QHttpNetworkRequest::setUploadByteDevice(QNonContiguousByteDevice *bd) { - return d->data; + d->uploadByteDevice = bd; } -void QHttpNetworkRequest::setData(QIODevice *data) +QNonContiguousByteDevice* QHttpNetworkRequest::uploadByteDevice() const { - d->data = data; + return d->uploadByteDevice; } int QHttpNetworkRequest::majorVersion() const diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h index d18e116..ed4325a 100644 --- a/src/network/access/qhttpnetworkrequest_p.h +++ b/src/network/access/qhttpnetworkrequest_p.h @@ -58,6 +58,8 @@ QT_BEGIN_NAMESPACE +class QNonContiguousByteDevice; + class QHttpNetworkRequestPrivate; class Q_AUTOTEST_EXPORT QHttpNetworkRequest: public QHttpNetworkHeader { @@ -104,8 +106,8 @@ public: Priority priority() const; void setPriority(Priority priority); - QIODevice *data() const; - void setData(QIODevice *data); + void setUploadByteDevice(QNonContiguousByteDevice *bd); + QNonContiguousByteDevice* uploadByteDevice() const; private: QSharedDataPointer<QHttpNetworkRequestPrivate> d; @@ -113,7 +115,6 @@ private: friend class QHttpNetworkConnectionPrivate; }; - class QHttpNetworkRequestPrivate : public QHttpNetworkHeaderPrivate { public: @@ -129,7 +130,7 @@ public: QHttpNetworkRequest::Operation operation; QHttpNetworkRequest::Priority priority; - mutable QIODevice *data; + mutable QNonContiguousByteDevice* uploadByteDevice; bool autoDecompress; }; diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index df468b8..b9d1b85 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -50,6 +50,8 @@ #include "qnetworkaccesscachebackend_p.h" #include "qabstractnetworkcache.h" +#include "private/qnoncontiguousbytedevice_p.h" + QT_BEGIN_NAMESPACE static bool factoryDataShutdown = false; @@ -109,17 +111,43 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM return 0; } -QNetworkAccessBackend::QNetworkAccessBackend() + +QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice() { + QNonContiguousByteDevice* device = 0; + + if (reply->outgoingDataBuffer) + device = QNonContiguousByteDeviceFactory::create(reply->outgoingDataBuffer); + else + device = QNonContiguousByteDeviceFactory::create(reply->outgoingData); + + bool bufferDisallowed = + reply->request.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, + QVariant(false)) == QVariant(true); + if (bufferDisallowed) + device->disableReset(); + + // make sure we delete this later + device->setParent(this); + + connect(device, SIGNAL(readProgress(qint64,qint64)), this, SLOT(emitReplyUploadProgress(qint64,qint64))); + + return device; } -QNetworkAccessBackend::~QNetworkAccessBackend() +// need to have this function since the reply is a private member variable +// and the special backends need to access this. +void QNetworkAccessBackend::emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal) { + reply->emitUploadProgress(bytesSent, bytesTotal); } -void QNetworkAccessBackend::upstreamReadyRead() +QNetworkAccessBackend::QNetworkAccessBackend() +{ +} + +QNetworkAccessBackend::~QNetworkAccessBackend() { - // do nothing } void QNetworkAccessBackend::downstreamReadyWrite() @@ -184,23 +212,6 @@ bool QNetworkAccessBackend::isCachingEnabled() const return reply->isCachingEnabled(); } -qint64 QNetworkAccessBackend::upstreamBytesAvailable() const -{ - return reply->writeBuffer.size(); -} - -void QNetworkAccessBackend::upstreamBytesConsumed(qint64 count) -{ - // remove count bytes from the write buffer - reply->consume(count); -} - -QByteArray QNetworkAccessBackend::readUpstream() -{ - // ### this is expensive. Consider making QRingBuffer::peekAll keep the buffer it returns - return reply->writeBuffer.peek(upstreamBytesAvailable()); -} - qint64 QNetworkAccessBackend::nextDownstreamBlockSize() const { return reply->nextDownstreamBlockSize(); @@ -213,12 +224,12 @@ qint64 QNetworkAccessBackend::downstreamBytesToConsume() const void QNetworkAccessBackend::writeDownstreamData(const QByteArray &data) { - reply->feed(data); + reply->appendDownstreamData(data); } void QNetworkAccessBackend::writeDownstreamData(QIODevice *data) { - reply->feed(data); + reply->appendDownstreamData(data); } QVariant QNetworkAccessBackend::header(QNetworkRequest::KnownHeaders header) const diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h index 9012396..6035f3a 100644 --- a/src/network/access/qnetworkaccessbackend_p.h +++ b/src/network/access/qnetworkaccessbackend_p.h @@ -70,6 +70,8 @@ class QNetworkAccessManagerPrivate; class QNetworkReplyImplPrivate; class QAbstractNetworkCache; class QNetworkCacheMetaData; +class QNetworkAccessBackendUploadIODevice; +class QNonContiguousByteDevice; // Should support direct file upload from disk or download to disk. // @@ -86,14 +88,13 @@ public: // have different names. The Connection has two streams: // // - Upstream: - // Upstream is data that is being written into this connection, - // from the user. Upstream operates in a "pull" mechanism: the - // connection will be notified that there is more data available - // by a call to "upstreamReadyRead". The number of bytes - // available is given by upstreamBytesAvailable(). A call to - // readUpstream() always yields the entire upstream buffer. When - // the connection has processed a certain amount of bytes from - // that buffer, it should call upstreamBytesConsumed(). + // The upstream uses a QNonContiguousByteDevice provided + // by the backend. This device emits the usual readyRead() + // signal when the backend has data available for the connection + // to write. The different backends can listen on this signal + // and then pull upload data from the QNonContiguousByteDevice and + // deal with it. + // // // - Downstream: // Downstream is the data that is being read from this @@ -111,12 +112,9 @@ public: virtual void open() = 0; virtual void closeDownstreamChannel() = 0; - virtual void closeUpstreamChannel() = 0; virtual bool waitForDownstreamReadyRead(int msecs) = 0; - virtual bool waitForUpstreamBytesWritten(int msecs) = 0; // slot-like: - virtual void upstreamReadyRead(); virtual void downstreamReadyWrite(); virtual void copyFinished(QIODevice *); virtual void ignoreSslErrors(); @@ -155,18 +153,24 @@ public: QVariant attribute(QNetworkRequest::Attribute code) const; void setAttribute(QNetworkRequest::Attribute code, const QVariant &value); + // return true if the QNonContiguousByteDevice of the upload + // data needs to support reset(). Currently needed for HTTP. + // This will possibly enable buffering of the upload data. + virtual bool needsResetableUploadData() {return false;}; + protected: - // these functions control the upstream mechanism - // that is, data coming into the backend and out via the connection - qint64 upstreamBytesAvailable() const; - void upstreamBytesConsumed(qint64 count); - QByteArray readUpstream(); + // Create the device used for reading the upload data + QNonContiguousByteDevice* createUploadByteDevice(); + // these functions control the downstream mechanism // that is, data that has come via the connection and is going out the backend qint64 nextDownstreamBlockSize() const; qint64 downstreamBytesToConsume() const; void writeDownstreamData(const QByteArray &data); + +public slots: + // for task 251801, needs to be a slot to be called asynchronously void writeDownstreamData(QIODevice *data); protected slots: @@ -179,10 +183,12 @@ protected slots: void metaDataChanged(); void redirectionRequested(const QUrl &destination); void sslErrors(const QList<QSslError> &errors); + void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal); private: friend class QNetworkAccessManager; friend class QNetworkAccessManagerPrivate; + friend class QNetworkAccessBackendUploadIODevice; QNetworkAccessManagerPrivate *manager; QNetworkReplyImplPrivate *reply; }; diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp index 2e5f1b1..d4bda9a 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend.cpp +++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp @@ -41,6 +41,8 @@ #include "qnetworkaccessdebugpipebackend_p.h" #include "QtCore/qdatastream.h" +#include <QCoreApplication> +#include "private/qnoncontiguousbytedevice_p.h" QT_BEGIN_NAMESPACE @@ -51,12 +53,6 @@ enum { WriteBufferSize = ReadBufferSize }; -struct QNetworkAccessDebugPipeBackend::DataPacket -{ - QList<QPair<QByteArray, QByteArray> > headers; - QByteArray data; -}; - QNetworkAccessBackend * QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const @@ -79,12 +75,14 @@ QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation o } QNetworkAccessDebugPipeBackend::QNetworkAccessDebugPipeBackend() - : incomingPacketSize(0), bareProtocol(false) + : bareProtocol(false), hasUploadFinished(false), hasDownloadFinished(false), + hasEverythingFinished(false), bytesDownloaded(0), bytesUploaded(0) { } QNetworkAccessDebugPipeBackend::~QNetworkAccessDebugPipeBackend() { + // this is signals disconnect, not network! socket.disconnect(this); // we're not interested in the signals at this point } @@ -92,160 +90,150 @@ void QNetworkAccessDebugPipeBackend::open() { socket.connectToHost(url().host(), url().port(12345)); socket.setReadBufferSize(ReadBufferSize); + + // socket ready read -> we can push from socket to downstream connect(&socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); - connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError())); connect(&socket, SIGNAL(disconnected()), SLOT(socketDisconnected())); + connect(&socket, SIGNAL(connected()), SLOT(socketConnected())); + // socket bytes written -> we can push more from upstream to socket + connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); bareProtocol = url().queryItemValue(QLatin1String("bare")) == QLatin1String("1"); - if (!bareProtocol) { - // "Handshake": - // send outgoing metadata and the URL being requested - DataPacket packet; - //packet.metaData = request().metaData(); - packet.data = url().toEncoded(); - send(packet); + if (operation() == QNetworkAccessManager::PutOperation) { + uploadByteDevice = createUploadByteDevice(); + QObject::connect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot())); + QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection); } } -void QNetworkAccessDebugPipeBackend::closeDownstreamChannel() +void QNetworkAccessDebugPipeBackend::socketReadyRead() { - if (operation() == QNetworkAccessManager::GetOperation) - socket.disconnectFromHost(); + pushFromSocketToDownstream(); } -void QNetworkAccessDebugPipeBackend::closeUpstreamChannel() +void QNetworkAccessDebugPipeBackend::downstreamReadyWrite() { - if (operation() == QNetworkAccessManager::PutOperation) - socket.disconnectFromHost(); - else if (operation() == QNetworkAccessManager::PostOperation) { - send(DataPacket()); - } + pushFromSocketToDownstream(); } -bool QNetworkAccessDebugPipeBackend::waitForDownstreamReadyRead(int ms) +void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64) { - readyReadEmitted = false; - if (socket.bytesAvailable()) { - socketReadyRead(); - if (readyReadEmitted) - return true; - } - socket.waitForReadyRead(ms); - return readyReadEmitted; + pushFromUpstreamToSocket(); } -bool QNetworkAccessDebugPipeBackend::waitForUpstreamBytesWritten(int ms) +void QNetworkAccessDebugPipeBackend::uploadReadyReadSlot() { - bytesWrittenEmitted = false; - upstreamReadyRead(); - if (bytesWrittenEmitted) - return true; - - socket.waitForBytesWritten(ms); - return bytesWrittenEmitted; + pushFromUpstreamToSocket(); } -void QNetworkAccessDebugPipeBackend::upstreamReadyRead() +void QNetworkAccessDebugPipeBackend::pushFromSocketToDownstream() { - int maxWrite = WriteBufferSize - socket.bytesToWrite(); - if (maxWrite <= 0) - return; // can't write yet, wait for the socket to write - - if (bareProtocol) { - QByteArray data = readUpstream(); - if (data.isEmpty()) - return; + QByteArray buffer; - socket.write(data); - upstreamBytesConsumed(data.size()); - bytesWrittenEmitted = true; + if (socket.state() == QAbstractSocket::ConnectingState) { return; } - DataPacket packet; - packet.data = readUpstream(); - if (packet.data.isEmpty()) - return; // we'll be called again when there's data - if (packet.data.size() > maxWrite) - packet.data.truncate(maxWrite); - - if (!send(packet)) { - QString msg = QObject::tr("Write error writing to %1: %2") - .arg(url().toString(), socket.errorString()); - error(QNetworkReply::ProtocolFailure, msg); + forever { + if (hasDownloadFinished) + return; - finished(); - return; + buffer.resize(ReadBufferSize); + qint64 haveRead = socket.read(buffer.data(), ReadBufferSize); + + if (haveRead == -1) { + hasDownloadFinished = true; + // this ensures a good last downloadProgress is emitted + setHeader(QNetworkRequest::ContentLengthHeader, QVariant()); + possiblyFinish(); + break; + } else if (haveRead == 0) { + break; + } else { + // have read something + buffer.resize(haveRead); + bytesDownloaded += haveRead; + writeDownstreamData(buffer); + } } - upstreamBytesConsumed(packet.data.size()); - bytesWrittenEmitted = true; } -void QNetworkAccessDebugPipeBackend::downstreamReadyWrite() +void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket() { - socketReadyRead(); -} + // FIXME + if (operation() == QNetworkAccessManager::PutOperation) { + if (hasUploadFinished) + return; -void QNetworkAccessDebugPipeBackend::socketReadyRead() -{ - if (bareProtocol) { - qint64 bytesToRead = socket.bytesAvailable(); - if (bytesToRead) { - QByteArray buffer; - buffer.resize(bytesToRead); - qint64 bytesRead = socket.read(buffer.data(), bytesToRead); - if (bytesRead < bytesToRead) - buffer.truncate(bytesRead); - writeDownstreamData(buffer); - readyReadEmitted = true; + forever { + if (socket.bytesToWrite() >= WriteBufferSize) + return; + + qint64 haveRead; + const char *readPointer = uploadByteDevice->readPointer(WriteBufferSize, haveRead); + if (haveRead == -1) { + // EOF + hasUploadFinished = true; + emitReplyUploadProgress(bytesUploaded, bytesUploaded); + possiblyFinish(); + break; + } else if (haveRead == 0 || readPointer == 0) { + // nothing to read right now, we will be called again later + break; + } else { + qint64 haveWritten; + haveWritten = socket.write(readPointer, haveRead); + + if (haveWritten < 0) { + // write error! + QString msg = QCoreApplication::translate("QNetworkAccessDebugPipeBackend", "Write error writing to %1: %2") + .arg(url().toString(), socket.errorString()); + error(QNetworkReply::ProtocolFailure, msg); + finished(); + return; + } else { + uploadByteDevice->advanceReadPointer(haveWritten); + bytesUploaded += haveWritten; + emitReplyUploadProgress(bytesUploaded, -1); + } + + //QCoreApplication::processEvents(); + + } } - return; } +} - while (canReceive() && - (socket.state() == QAbstractSocket::UnconnectedState || nextDownstreamBlockSize())) { - DataPacket packet; - if (receive(packet)) { - if (!packet.headers.isEmpty()) { - QList<QPair<QByteArray, QByteArray> >::ConstIterator - it = packet.headers.constBegin(), - end = packet.headers.constEnd(); - for ( ; it != end; ++it) - setRawHeader(it->first, it->second); - metaDataChanged(); - } +void QNetworkAccessDebugPipeBackend::possiblyFinish() +{ + if (hasEverythingFinished) + return; + hasEverythingFinished = true; - if (!packet.data.isEmpty()) { - writeDownstreamData(packet.data); - readyReadEmitted = true; - } + if ((operation() == QNetworkAccessManager::GetOperation) && hasDownloadFinished) { + socket.close(); + finished(); + } else if ((operation() == QNetworkAccessManager::PutOperation) && hasUploadFinished) { + socket.close(); + finished(); + } - if (packet.headers.isEmpty() && packet.data.isEmpty()) { - // it's an eof - socket.close(); - readyReadEmitted = true; - } - } else { - // got an error - QString msg = QObject::tr("Read error reading from %1: %2") - .arg(url().toString(), socket.errorString()); - error(QNetworkReply::ProtocolFailure, msg); - finished(); - return; - } - } } -void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64) +void QNetworkAccessDebugPipeBackend::closeDownstreamChannel() { - upstreamReadyRead(); + qWarning() << "QNetworkAccessDebugPipeBackend::closeDownstreamChannel()" << operation(); + //if (operation() == QNetworkAccessManager::GetOperation) + // socket.disconnectFromHost(); } + void QNetworkAccessDebugPipeBackend::socketError() { + qWarning() << "QNetworkAccessDebugPipeBackend::socketError()" << socket.error(); QNetworkReply::NetworkError code; switch (socket.error()) { case QAbstractSocket::RemoteHostClosedError: @@ -269,76 +257,27 @@ void QNetworkAccessDebugPipeBackend::socketError() void QNetworkAccessDebugPipeBackend::socketDisconnected() { - socketReadyRead(); - if (incomingPacketSize == 0 && socket.bytesToWrite() == 0) { + pushFromSocketToDownstream(); + + if (socket.bytesToWrite() == 0) { // normal close - finished(); } else { // abnormal close QString msg = QObject::tr("Remote host closed the connection prematurely on %1") .arg(url().toString()); error(QNetworkReply::RemoteHostClosedError, msg); - finished(); } } -bool QNetworkAccessDebugPipeBackend::send(const DataPacket &packet) -{ - QByteArray ba; - { - QDataStream stream(&ba, QIODevice::WriteOnly); - stream.setVersion(QDataStream::Qt_4_4); - - stream << packet.headers << packet.data; - } - - qint32 outgoingPacketSize = ba.size(); - qint64 written = socket.write((const char*)&outgoingPacketSize, sizeof outgoingPacketSize); - written += socket.write(ba); - return quint64(written) == (outgoingPacketSize + sizeof outgoingPacketSize); -} - -bool QNetworkAccessDebugPipeBackend::receive(DataPacket &packet) +void QNetworkAccessDebugPipeBackend::socketConnected() { - if (!canReceive()) - return false; - - // canReceive() does the setting up for us - Q_ASSERT(socket.bytesAvailable() >= incomingPacketSize); - QByteArray incomingPacket = socket.read(incomingPacketSize); - QDataStream stream(&incomingPacket, QIODevice::ReadOnly); - stream.setVersion(QDataStream::Qt_4_4); - stream >> packet.headers >> packet.data; - - // reset for next packet: - incomingPacketSize = 0; - socket.setReadBufferSize(ReadBufferSize); - return true; } -bool QNetworkAccessDebugPipeBackend::canReceive() +bool QNetworkAccessDebugPipeBackend::waitForDownstreamReadyRead(int ms) { - if (incomingPacketSize == 0) { - // read the packet size - if (quint64(socket.bytesAvailable()) >= sizeof incomingPacketSize) - socket.read((char*)&incomingPacketSize, sizeof incomingPacketSize); - else - return false; - } - - if (incomingPacketSize == 0) { - QString msg = QObject::tr("Protocol error: packet of size 0 received"); - error(QNetworkReply::ProtocolFailure, msg); - finished(); - - socket.blockSignals(true); - socket.abort(); - socket.blockSignals(false); - return false; - } - - return socket.bytesAvailable() >= incomingPacketSize; + qCritical("QNetworkAccess: Debug pipe backend does not support waitForReadyRead()"); + return false; } #endif diff --git a/src/network/access/qnetworkaccessdebugpipebackend_p.h b/src/network/access/qnetworkaccessdebugpipebackend_p.h index 73a35cf..a13edc4 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend_p.h +++ b/src/network/access/qnetworkaccessdebugpipebackend_p.h @@ -66,35 +66,38 @@ class QNetworkAccessDebugPipeBackend: public QNetworkAccessBackend { Q_OBJECT public: - struct DataPacket; QNetworkAccessDebugPipeBackend(); virtual ~QNetworkAccessDebugPipeBackend(); virtual void open(); virtual void closeDownstreamChannel(); - virtual void closeUpstreamChannel(); virtual bool waitForDownstreamReadyRead(int msecs); - virtual bool waitForUpstreamBytesWritten(int msecs); - virtual void upstreamReadyRead(); virtual void downstreamReadyWrite(); +protected: + void pushFromSocketToDownstream(); + void pushFromUpstreamToSocket(); + void possiblyFinish(); + QNonContiguousByteDevice *uploadByteDevice; + private slots: + void uploadReadyReadSlot(); void socketReadyRead(); void socketBytesWritten(qint64 bytes); void socketError(); void socketDisconnected(); + void socketConnected(); private: QTcpSocket socket; - qint32 incomingPacketSize; - bool readyReadEmitted; - bool bytesWrittenEmitted; bool bareProtocol; + bool hasUploadFinished; + bool hasDownloadFinished; + bool hasEverythingFinished; - bool send(const DataPacket &packet); - bool canReceive(); - bool receive(DataPacket &packet); + qint64 bytesDownloaded; + qint64 bytesUploaded; }; class QNetworkAccessDebugPipeBackendFactory: public QNetworkAccessBackendFactory diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp index 8a5a665..d905b70 100644 --- a/src/network/access/qnetworkaccessfilebackend.cpp +++ b/src/network/access/qnetworkaccessfilebackend.cpp @@ -43,6 +43,7 @@ #include "qfileinfo.h" #include "qurlinfo.h" #include "qdir.h" +#include "private/qnoncontiguousbytedevice_p.h" #include <QtCore/QCoreApplication> @@ -77,7 +78,7 @@ QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op, } QNetworkAccessFileBackend::QNetworkAccessFileBackend() - : totalBytes(0) + : uploadByteDevice(0), totalBytes(0), hasUploadFinished(false) { } @@ -108,7 +109,7 @@ void QNetworkAccessFileBackend::open() QString fileName = url.toLocalFile(); if (fileName.isEmpty()) { if (url.scheme() == QLatin1String("qrc")) - fileName = QLatin1String(":") + url.path(); + fileName = QLatin1Char(':') + url.path(); else fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery); } @@ -126,6 +127,9 @@ void QNetworkAccessFileBackend::open() break; case QNetworkAccessManager::PutOperation: mode = QIODevice::WriteOnly | QIODevice::Truncate; + uploadByteDevice = createUploadByteDevice(); + QObject::connect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot())); + QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection); break; default: Q_ASSERT_X(false, "QNetworkAccessFileBackend::open", @@ -152,19 +156,50 @@ void QNetworkAccessFileBackend::open() } } -void QNetworkAccessFileBackend::closeDownstreamChannel() +void QNetworkAccessFileBackend::uploadReadyReadSlot() { - if (operation() == QNetworkAccessManager::GetOperation) { - file.close(); - //downstreamChannelClosed(); + if (hasUploadFinished) + return; + + forever { + qint64 haveRead; + const char *readPointer = uploadByteDevice->readPointer(-1, haveRead); + if (haveRead == -1) { + // EOF + hasUploadFinished = true; + file.flush(); + file.close(); + finished(); + break; + } else if (haveRead == 0 || readPointer == 0) { + // nothing to read right now, we will be called again later + break; + } else { + qint64 haveWritten; + haveWritten = file.write(readPointer, haveRead); + + if (haveWritten < 0) { + // write error! + QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Write error writing to %1: %2") + .arg(url().toString(), file.errorString()); + error(QNetworkReply::ProtocolFailure, msg); + + finished(); + return; + } else { + uploadByteDevice->advanceReadPointer(haveWritten); + } + + + file.flush(); + } } } -void QNetworkAccessFileBackend::closeUpstreamChannel() +void QNetworkAccessFileBackend::closeDownstreamChannel() { - if (operation() == QNetworkAccessManager::PutOperation) { + if (operation() == QNetworkAccessManager::GetOperation) { file.close(); - finished(); } } @@ -174,40 +209,6 @@ bool QNetworkAccessFileBackend::waitForDownstreamReadyRead(int) return readMoreFromFile(); } -bool QNetworkAccessFileBackend::waitForUpstreamBytesWritten(int) -{ - Q_ASSERT_X(false, "QNetworkAccessFileBackend::waitForUpstreamBytesWritten", - "This function should never have been called, since there is never anything " - "left to be written!"); - return false; -} - -void QNetworkAccessFileBackend::upstreamReadyRead() -{ - Q_ASSERT_X(operation() == QNetworkAccessManager::PutOperation, "QNetworkAccessFileBackend", - "We're being told to upload data but operation isn't PUT!"); - - // there's more data to be written to the file - while (upstreamBytesAvailable()) { - // write everything and let QFile handle it - int written = file.write(readUpstream()); - - if (written < 0) { - // write error! - QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Write error writing to %1: %2") - .arg(url().toString(), file.errorString()); - error(QNetworkReply::ProtocolFailure, msg); - - finished(); - return; - } - - // successful write - file.flush(); - upstreamBytesConsumed(written); - } -} - void QNetworkAccessFileBackend::downstreamReadyWrite() { Q_ASSERT_X(operation() == QNetworkAccessManager::GetOperation, "QNetworkAccessFileBackend", diff --git a/src/network/access/qnetworkaccessfilebackend_p.h b/src/network/access/qnetworkaccessfilebackend_p.h index ce7d351..4615c5f 100644 --- a/src/network/access/qnetworkaccessfilebackend_p.h +++ b/src/network/access/qnetworkaccessfilebackend_p.h @@ -62,22 +62,25 @@ QT_BEGIN_NAMESPACE class QNetworkAccessFileBackend: public QNetworkAccessBackend { + Q_OBJECT public: QNetworkAccessFileBackend(); virtual ~QNetworkAccessFileBackend(); virtual void open(); virtual void closeDownstreamChannel(); - virtual void closeUpstreamChannel(); virtual bool waitForDownstreamReadyRead(int msecs); - virtual bool waitForUpstreamBytesWritten(int msecs); - virtual void upstreamReadyRead(); virtual void downstreamReadyWrite(); +public slots: + void uploadReadyReadSlot(); +protected: + QNonContiguousByteDevice *uploadByteDevice; private: QFile file; qint64 totalBytes; + bool hasUploadFinished; bool loadFileInfo(); bool readMoreFromFile(); diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index ea39dec..ad55b85 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -42,6 +42,7 @@ #include "qnetworkaccessftpbackend_p.h" #include "qnetworkaccessmanager_p.h" #include "QtNetwork/qauthenticator.h" +#include "private/qnoncontiguousbytedevice_p.h" #ifndef QT_NO_FTP @@ -81,41 +82,6 @@ QNetworkAccessFtpBackendFactory::create(QNetworkAccessManager::Operation op, return 0; } -class QNetworkAccessFtpIODevice: public QIODevice -{ - //Q_OBJECT -public: - QNetworkAccessFtpBackend *backend; - bool eof; - - inline QNetworkAccessFtpIODevice(QNetworkAccessFtpBackend *parent) - : QIODevice(parent), backend(parent), eof(false) - { open(ReadOnly); } - - bool isSequential() const { return true; } - bool atEnd() const { return backend->upstreamBytesAvailable() == 0; } - - qint64 bytesAvailable() const { return backend->upstreamBytesAvailable(); } - qint64 bytesToWrite() const { return backend->downstreamBytesToConsume(); } -protected: - qint64 readData(char *data, qint64 maxlen) - { - const QByteArray toSend = backend->readUpstream(); - maxlen = qMin<qint64>(maxlen, toSend.size()); - if (!maxlen) - return eof ? -1 : 0; - - backend->upstreamBytesConsumed(maxlen); - memcpy(data, toSend.constData(), maxlen); - return maxlen; - } - - qint64 writeData(const char *, qint64) - { return -1; } - - friend class QNetworkAccessFtpBackend; -}; - class QNetworkAccessFtpFtp: public QFtp, public QNetworkAccessCache::CacheableObject { // Q_OBJECT @@ -198,7 +164,11 @@ void QNetworkAccessFtpBackend::open() ftpConnectionReady(ftp); } - uploadDevice = new QNetworkAccessFtpIODevice(this); + // Put operation + if (operation() == QNetworkAccessManager::PutOperation) { + uploadDevice = QNonContiguousByteDeviceFactory::wrap(createUploadByteDevice()); + uploadDevice->setParent(this); + } } void QNetworkAccessFtpBackend::closeDownstreamChannel() @@ -212,16 +182,6 @@ void QNetworkAccessFtpBackend::closeDownstreamChannel() #endif } -void QNetworkAccessFtpBackend::closeUpstreamChannel() -{ - if (operation() == QNetworkAccessManager::PutOperation) { - Q_ASSERT(uploadDevice); - uploadDevice->eof = true; - if (!upstreamBytesAvailable()) - emit uploadDevice->readyRead(); - } -} - bool QNetworkAccessFtpBackend::waitForDownstreamReadyRead(int ms) { if (!ftp) @@ -239,18 +199,6 @@ bool QNetworkAccessFtpBackend::waitForDownstreamReadyRead(int ms) return false; } -bool QNetworkAccessFtpBackend::waitForUpstreamBytesWritten(int ms) -{ - Q_UNUSED(ms); - qCritical("QNetworkAccess: FTP backend does not support waitForBytesWritten()"); - return false; -} - -void QNetworkAccessFtpBackend::upstreamReadyRead() -{ - // uh... how does QFtp operate? -} - void QNetworkAccessFtpBackend::downstreamReadyWrite() { if (state == Transferring && ftp && ftp->bytesAvailable()) diff --git a/src/network/access/qnetworkaccessftpbackend_p.h b/src/network/access/qnetworkaccessftpbackend_p.h index 9ec2dd8..1bb7ff2 100644 --- a/src/network/access/qnetworkaccessftpbackend_p.h +++ b/src/network/access/qnetworkaccessftpbackend_p.h @@ -87,11 +87,8 @@ public: virtual void open(); virtual void closeDownstreamChannel(); - virtual void closeUpstreamChannel(); virtual bool waitForDownstreamReadyRead(int msecs); - virtual bool waitForUpstreamBytesWritten(int msecs); - virtual void upstreamReadyRead(); virtual void downstreamReadyWrite(); void disconnectFromFtp(); @@ -105,7 +102,7 @@ public slots: private: friend class QNetworkAccessFtpIODevice; QPointer<QNetworkAccessFtpFtp> ftp; - QNetworkAccessFtpIODevice *uploadDevice; + QIODevice *uploadDevice; qint64 totalBytes; int helpId, sizeId, mdtmId; bool supportsSize, supportsMdtm; diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index a52b5a0..bd364cb 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -286,37 +286,6 @@ public: } }; -class QNetworkAccessHttpBackendIODevice: public QIODevice -{ - // Q_OBJECT -public: - bool eof; - QNetworkAccessHttpBackendIODevice(QNetworkAccessHttpBackend *parent) - : QIODevice(parent), eof(false) - { - setOpenMode(ReadOnly); - } - bool isSequential() const { return true; } - qint64 bytesAvailable() const - { return static_cast<QNetworkAccessHttpBackend *>(parent())->upstreamBytesAvailable(); } - -protected: - virtual qint64 readData(char *buffer, qint64 maxlen) - { - qint64 ret = static_cast<QNetworkAccessHttpBackend *>(parent())->deviceReadData(buffer, maxlen); - if (!ret && eof) - return -1; - return ret; - } - - virtual qint64 writeData(const char *, qint64) - { - return -1; // cannot write - } - - friend class QNetworkAccessHttpBackend; -}; - QNetworkAccessHttpBackend::QNetworkAccessHttpBackend() : QNetworkAccessBackend(), httpReply(0), http(0), uploadDevice(0) #ifndef QT_NO_OPENSSL @@ -507,20 +476,19 @@ void QNetworkAccessHttpBackend::postRequest() case QNetworkAccessManager::PostOperation: invalidateCache(); httpRequest.setOperation(QHttpNetworkRequest::Post); - uploadDevice = new QNetworkAccessHttpBackendIODevice(this); + httpRequest.setUploadByteDevice(createUploadByteDevice()); break; case QNetworkAccessManager::PutOperation: invalidateCache(); httpRequest.setOperation(QHttpNetworkRequest::Put); - uploadDevice = new QNetworkAccessHttpBackendIODevice(this); + httpRequest.setUploadByteDevice(createUploadByteDevice()); break; default: break; // can't happen } - httpRequest.setData(uploadDevice); httpRequest.setUrl(url()); QList<QByteArray> headers = request().rawHeaderList(); @@ -528,7 +496,9 @@ void QNetworkAccessHttpBackend::postRequest() httpRequest.setHeaderField(header, request().rawHeader(header)); if (loadedFromCache) { - QNetworkAccessBackend::finished(); + // commented this out since it will be called later anyway + // by copyFinished() + //QNetworkAccessBackend::finished(); return; // no need to send the request! :) } @@ -624,14 +594,6 @@ void QNetworkAccessHttpBackend::closeDownstreamChannel() // this indicates that the user closed the stream while the reply isn't finished yet } -void QNetworkAccessHttpBackend::closeUpstreamChannel() -{ - // this indicates that the user finished uploading the data for POST - Q_ASSERT(uploadDevice); - uploadDevice->eof = true; - emit uploadDevice->readChannelFinished(); -} - bool QNetworkAccessHttpBackend::waitForDownstreamReadyRead(int msecs) { Q_ASSERT(http); @@ -651,38 +613,6 @@ bool QNetworkAccessHttpBackend::waitForDownstreamReadyRead(int msecs) return false; } -bool QNetworkAccessHttpBackend::waitForUpstreamBytesWritten(int msecs) -{ - - // ### FIXME: not implemented in QHttpNetworkAccess - Q_UNUSED(msecs); - qCritical("QNetworkAccess: HTTP backend does not support waitForBytesWritten()"); - return false; -} - -void QNetworkAccessHttpBackend::upstreamReadyRead() -{ - // There is more data available from the user to be uploaded - // QHttpNetworkAccess implements the upload rate control: - // we simply tell QHttpNetworkAccess that there is more data available - // it'll pull from us when it can (through uploadDevice) - - Q_ASSERT(uploadDevice); - emit uploadDevice->readyRead(); -} - -qint64 QNetworkAccessHttpBackend::deviceReadData(char *buffer, qint64 maxlen) -{ - QByteArray toBeUploaded = readUpstream(); - if (toBeUploaded.isEmpty()) - return 0; // nothing to be uploaded - - maxlen = qMin<qint64>(maxlen, toBeUploaded.length()); - - memcpy(buffer, toBeUploaded.constData(), maxlen); - upstreamBytesConsumed(maxlen); - return maxlen; -} void QNetworkAccessHttpBackend::downstreamReadyWrite() { @@ -904,7 +834,14 @@ bool QNetworkAccessHttpBackend::sendCacheContents(const QNetworkCacheMetaData &m checkForRedirect(status); - writeDownstreamData(contents); + emit metaDataChanged(); + + // invoke this asynchronously, else Arora/QtDemoBrowser don't like cached downloads + // see task 250221 / 251801 + qRegisterMetaType<QIODevice*>("QIODevice*"); + QMetaObject::invokeMethod(this, "writeDownstreamData", Qt::QueuedConnection, Q_ARG(QIODevice*, contents)); + + #if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) qDebug() << "Successfully sent cache:" << url() << contents->size() << "bytes"; #endif @@ -1036,21 +973,39 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo if (it != cacheHeaders.rawHeaders.constEnd()) metaData.setLastModified(QNetworkHeadersPrivate::fromHttpDate(it->second)); - bool canDiskCache = true; // Everything defaults to being cacheable on disk + bool canDiskCache; + // only cache GET replies by default, all other replies (POST, PUT, DELETE) + // are not cacheable by default (according to RFC 2616 section 9) + if (httpReply->request().operation() == QHttpNetworkRequest::Get) { + + canDiskCache = true; + // 14.32 + // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client + // had sent "Cache-Control: no-cache". + it = cacheHeaders.findRawHeader("pragma"); + if (it != cacheHeaders.rawHeaders.constEnd() + && it->second == "no-cache") + canDiskCache = false; + + // HTTP/1.1. Check the Cache-Control header + if (cacheControl.contains("no-cache")) + canDiskCache = false; + else if (cacheControl.contains("no-store")) + canDiskCache = false; + + // responses to POST might be cacheable + } else if (httpReply->request().operation() == QHttpNetworkRequest::Post) { - // 14.32 - // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client - // had sent "Cache-Control: no-cache". - it = cacheHeaders.findRawHeader("pragma"); - if (it != cacheHeaders.rawHeaders.constEnd() - && it->second == "no-cache") canDiskCache = false; + // some pages contain "expires:" and "cache-control: no-cache" field, + // so we only might cache POST requests if we get "cache-control: max-age ..." + if (cacheControl.contains("max-age")) + canDiskCache = true; - // HTTP/1.1. Check the Cache-Control header - if (cacheControl.contains("no-cache")) - canDiskCache = false; - else if (cacheControl.contains("no-store")) + // responses to PUT and DELETE are not cacheable + } else { canDiskCache = false; + } metaData.setSaveToDisk(canDiskCache); int statusCode = httpReply->statusCode(); diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h index 02915e7..225f944 100644 --- a/src/network/access/qnetworkaccesshttpbackend_p.h +++ b/src/network/access/qnetworkaccesshttpbackend_p.h @@ -79,11 +79,8 @@ public: virtual void open(); virtual void closeDownstreamChannel(); - virtual void closeUpstreamChannel(); virtual bool waitForDownstreamReadyRead(int msecs); - virtual bool waitForUpstreamBytesWritten(int msecs); - virtual void upstreamReadyRead(); virtual void downstreamReadyWrite(); virtual void copyFinished(QIODevice *); #ifndef QT_NO_OPENSSL @@ -96,6 +93,9 @@ public: qint64 deviceReadData(char *buffer, qint64 maxlen); + // we return true since HTTP needs to send PUT/POST data again after having authenticated + bool needsResetableUploadData() {return true;}; + private slots: void replyReadyRead(); void replyFinished(); @@ -108,7 +108,8 @@ private: QHttpNetworkReply *httpReply; QPointer<QNetworkAccessHttpBackendCache> http; QByteArray cacheKey; - QNetworkAccessHttpBackendIODevice *uploadDevice; + QNetworkAccessBackendUploadIODevice *uploadDevice; + #ifndef QT_NO_OPENSSL QSslConfiguration *pendingSslConfiguration; bool pendingIgnoreSslErrors; @@ -122,8 +123,6 @@ private: void postRequest(); void readFromHttp(); void checkForRedirect(const int statusCode); - - friend class QNetworkAccessHttpBackendIODevice; }; class QNetworkAccessHttpBackendFactory : public QNetworkAccessBackendFactory diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index bcbeef1..bf06ede 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -686,7 +686,10 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera priv->urlForLastAuthentication = url; } - // third step: setup the reply + // third step: find a backend + priv->backend = d->findBackend(op, request); + + // fourth step: setup the reply priv->setup(op, request, outgoingData); if (request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt() != QNetworkRequest::AlwaysNetwork) @@ -695,9 +698,6 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera QList<QNetworkProxy> proxyList = d->queryProxy(QNetworkProxyQuery(request.url())); priv->proxyList = proxyList; #endif - - // fourth step: find a backend - priv->backend = d->findBackend(op, request); if (priv->backend) { priv->backend->setParent(reply); priv->backend->reply = priv; diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp index aaa5075..29bf042 100644 --- a/src/network/access/qnetworkcookie.cpp +++ b/src/network/access/qnetworkcookie.cpp @@ -913,6 +913,17 @@ static QDateTime parseDateString(const QByteArray &dateString) */ QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieString) { + // cookieString can be a number of set-cookie header strings joined together + // by \n, parse each line separately. + QList<QNetworkCookie> cookies; + QList<QByteArray> list = cookieString.split('\n'); + for (int a = 0; a < list.size(); a++) + cookies += QNetworkCookiePrivate::parseSetCookieHeaderLine(list.at(a)); + return cookies; +} + +QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByteArray &cookieString) +{ // According to http://wp.netscape.com/newsref/std/cookie_spec.html,< // the Set-Cookie response header is of the format: // @@ -930,12 +941,6 @@ QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieStrin while (position < length) { QNetworkCookie cookie; - // When there are multiple SetCookie headers they are join with a new line - // \n will always be the start of a new cookie - int endOfSetCookie = cookieString.indexOf('\n', position); - if (endOfSetCookie == -1) - endOfSetCookie = length; - // The first part is always the "NAME=VALUE" part QPair<QByteArray,QByteArray> field = nextField(cookieString, position); if (field.first.isEmpty() || field.second.isNull()) @@ -946,7 +951,7 @@ QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieStrin position = nextNonWhitespace(cookieString, position); bool endOfCookie = false; - while (!endOfCookie && position < endOfSetCookie) + while (!endOfCookie && position < length) { switch (cookieString.at(position++)) { case ',': // end of the cookie @@ -969,9 +974,7 @@ QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieStrin position = end; QDateTime dt = parseDateString(dateString.toLower()); if (!dt.isValid()) { - cookie = QNetworkCookie(); - endOfCookie = true; - continue; + return result; } cookie.setExpirationDate(dt); } else if (field.first == "domain") { @@ -988,8 +991,7 @@ QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieStrin bool ok = false; int secs = field.second.toInt(&ok); if (!ok) - // invalid cookie string - return QList<QNetworkCookie>(); + return result; cookie.setExpirationDate(now.addSecs(secs)); } else if (field.first == "path") { QString path = QUrl::fromPercentEncoding(field.second); @@ -1003,9 +1005,7 @@ QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieStrin } else if (field.first == "version") { if (field.second != "1") { // oops, we don't know how to handle this cookie - cookie = QNetworkCookie(); - endOfCookie = true; - continue; + return result; } } else { // got an unknown field in the cookie @@ -1013,9 +1013,8 @@ QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieStrin } position = nextNonWhitespace(cookieString, position); - if (position > endOfSetCookie) - endOfCookie = true; } + } if (!cookie.name().isEmpty()) result += cookie; @@ -1027,7 +1026,7 @@ QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieStrin #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug s, const QNetworkCookie &cookie) { - s.nospace() << "QNetworkCookie(" << cookie.toRawForm(QNetworkCookie::Full) << ")"; + s.nospace() << "QNetworkCookie(" << cookie.toRawForm(QNetworkCookie::Full) << ')'; return s.space(); } #endif @@ -1197,6 +1196,13 @@ bool QNetworkCookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieLis || isParentDomain(defaultDomain, domain))) { continue; // not accepted } + + // reject if domain is like ".com" + // (i.e., reject if domain does not contain embedded dots, see RFC 2109 section 4.3.2) + // this is just a rudimentary check and does not cover all cases + if (domain.lastIndexOf(QLatin1Char('.')) == 0) + continue; // not accepted + } QList<QNetworkCookie>::Iterator it = d->allCookies.begin(), diff --git a/src/network/access/qnetworkcookie_p.h b/src/network/access/qnetworkcookie_p.h index 83ef14a..0c41322 100644 --- a/src/network/access/qnetworkcookie_p.h +++ b/src/network/access/qnetworkcookie_p.h @@ -61,6 +61,7 @@ class QNetworkCookiePrivate: public QSharedData { public: inline QNetworkCookiePrivate() : secure(false), httpOnly(false) { } + static QList<QNetworkCookie> parseSetCookieHeaderLine(const QByteArray &cookieString); QDateTime expirationDate; QString domain; diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp index 14a04f1..0ca6b13 100644 --- a/src/network/access/qnetworkdiskcache.cpp +++ b/src/network/access/qnetworkdiskcache.cpp @@ -193,7 +193,11 @@ QIODevice *QNetworkDiskCache::prepare(const QNetworkCacheMetaData &metaData) } else { QString templateName = d->tmpCacheFileName(); cacheItem->file = new QTemporaryFile(templateName, &cacheItem->data); - cacheItem->file->open(); + if (!cacheItem->file->open()) { + qWarning() << "QNetworkDiskCache::prepare() unable to open temporary file"; + delete cacheItem; + return 0; + } cacheItem->writeHeader(cacheItem->file); device = cacheItem->file; } @@ -231,7 +235,7 @@ void QNetworkDiskCachePrivate::storeItem(QCacheItem *cacheItem) if (QFile::exists(fileName)) { if (!QFile::remove(fileName)) { - qWarning() << "QNetworkDiskCache: could't remove the cache file " << fileName; + qWarning() << "QNetworkDiskCache: couldn't remove the cache file " << fileName; return; } } @@ -492,21 +496,21 @@ qint64 QNetworkDiskCache::expire() QDir::Filters filters = QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot; QDirIterator it(cacheDirectory(), filters, QDirIterator::Subdirectories); - QMap<QDateTime, QString> cacheItems; + QMultiMap<QDateTime, QString> cacheItems; qint64 totalSize = 0; while (it.hasNext()) { QString path = it.next(); QFileInfo info = it.fileInfo(); QString fileName = info.fileName(); if (fileName.endsWith(CACHE_POSTFIX) && fileName.startsWith(CACHE_PREFIX)) { - cacheItems[info.created()] = path; + cacheItems.insert(info.created(), path); totalSize += info.size(); } } int removedFiles = 0; qint64 goal = (maximumCacheSize() * 9) / 10; - QMap<QDateTime, QString>::const_iterator i = cacheItems.constBegin(); + QMultiMap<QDateTime, QString>::const_iterator i = cacheItems.constBegin(); while (i != cacheItems.constEnd()) { if (totalSize < goal) break; diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index f4dad3c..0990b17 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -151,6 +151,10 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() authentication to serve the content but the credentials provided were not accepted (if any) + \value ContentReSendError the request needed to be sent + again, but this failed for example because the upload data + could not be read a second time. + \value ProtocolUnknownError the Network Access API cannot honor the request because the protocol is not known diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h index 6f763b3..2f864fe 100644 --- a/src/network/access/qnetworkreply.h +++ b/src/network/access/qnetworkreply.h @@ -92,6 +92,7 @@ public: ContentOperationNotPermittedError, ContentNotFoundError, AuthenticationRequiredError, + ContentReSendError, UnknownContentError = 299, // protocol errors diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 79c3d1a..a146358 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -46,13 +46,15 @@ #include "QtCore/qcoreapplication.h" #include "QtCore/qdatetime.h" #include "QtNetwork/qsslconfiguration.h" +#include "qnetworkaccesshttpbackend_p.h" #include <QtCore/QCoreApplication> QT_BEGIN_NAMESPACE inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate() - : copyDevice(0), networkCache(0), + : backend(0), outgoingData(0), outgoingDataBuffer(0), + copyDevice(0), networkCache(0), cacheEnabled(false), cacheSaveDevice(0), bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1), state(Idle) @@ -61,8 +63,13 @@ inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate() void QNetworkReplyImplPrivate::_q_startOperation() { - // This function is called exactly once + // ensure this function is only being called once + if (state == Working) { + qDebug("QNetworkReplyImpl::_q_startOperation was called more than once"); + return; + } state = Working; + if (!backend) { error(QNetworkReplyImpl::ProtocolUnknownError, QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown").arg(url.scheme())); // not really true!; @@ -74,57 +81,11 @@ void QNetworkReplyImplPrivate::_q_startOperation() if (state != Finished) { if (operation == QNetworkAccessManager::GetOperation) pendingNotifications.append(NotifyDownstreamReadyWrite); - if (outgoingData) { - _q_sourceReadyRead(); -#if 0 // ### FIXME - if (outgoingData->atEndOfStream() && writeBuffer.isEmpty()) - // empty upload - emit q->uploadProgress(0, 0); -#endif - } handleNotifications(); } } -void QNetworkReplyImplPrivate::_q_sourceReadyRead() -{ - // read data from the outgoingData QIODevice into our internal buffer - enum { DesiredBufferSize = 32 * 1024 }; - - if (writeBuffer.size() >= DesiredBufferSize) - return; // don't grow the buffer too much - - // read as many bytes are available or up until we fill up the buffer - // but always read at least one byte - qint64 bytesToRead = qBound<qint64>(1, outgoingData->bytesAvailable(), - DesiredBufferSize - writeBuffer.size()); - char *ptr = writeBuffer.reserve(bytesToRead); - qint64 bytesActuallyRead = outgoingData->read(ptr, bytesToRead); - if (bytesActuallyRead == -1) { - // EOF - writeBuffer.chop(bytesToRead); - backendNotify(NotifyCloseUpstreamChannel); - return; - } - - if (bytesActuallyRead < bytesToRead) - writeBuffer.chop(bytesToRead - bytesActuallyRead); - - // if we did read anything, let the backend know and handle it - if (bytesActuallyRead) - backendNotify(NotifyUpstreamReadyRead); - - // check for EOF again - if (!outgoingData->isSequential() && outgoingData->atEnd()) - backendNotify(NotifyCloseUpstreamChannel); -} - -void QNetworkReplyImplPrivate::_q_sourceReadChannelFinished() -{ - _q_sourceReadyRead(); -} - void QNetworkReplyImplPrivate::_q_copyReadyRead() { Q_Q(QNetworkReplyImpl); @@ -143,7 +104,7 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead() if (bytesActuallyRead == -1) { readBuffer.chop(bytesToRead); backendNotify(NotifyCopyFinished); - return; + break; } if (bytesActuallyRead != bytesToRead) @@ -151,6 +112,7 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead() if (!copyDevice->isSequential() && copyDevice->atEnd()) { backendNotify(NotifyCopyFinished); + bytesDownloaded += bytesActuallyRead; break; } @@ -174,6 +136,67 @@ void QNetworkReplyImplPrivate::_q_copyReadChannelFinished() _q_copyReadyRead(); } +void QNetworkReplyImplPrivate::_q_bufferOutgoingDataFinished() +{ + Q_Q(QNetworkReplyImpl); + + // make sure this is only called once, ever. + //_q_bufferOutgoingData may call it or the readChannelFinished emission + if (state != Buffering) + return; + + // disconnect signals + QObject::disconnect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); + QObject::disconnect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); + + // finally, start the request + QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); +} + +void QNetworkReplyImplPrivate::_q_bufferOutgoingData() +{ + Q_Q(QNetworkReplyImpl); + + if (!outgoingDataBuffer) { + // first call, create our buffer + outgoingDataBuffer = new QRingBuffer(); + + QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); + QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); + } + + qint64 bytesBuffered = 0; + qint64 bytesToBuffer = 0; + + // read data into our buffer + forever { + bytesToBuffer = outgoingData->bytesAvailable(); + // unknown? just try 2 kB, this also ensures we always try to read the EOF + if (bytesToBuffer <= 0) + bytesToBuffer = 2*1024; + + char *dst = outgoingDataBuffer->reserve(bytesToBuffer); + bytesBuffered = outgoingData->read(dst, bytesToBuffer); + + if (bytesBuffered == -1) { + // EOF has been reached. + outgoingDataBuffer->chop(bytesToBuffer); + + _q_bufferOutgoingDataFinished(); + break; + } else if (bytesBuffered == 0) { + // nothing read right now, just wait until we get called again + outgoingDataBuffer->chop(bytesToBuffer); + + break; + } else { + // don't break, try to read() again + outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered); + } + } +} + + void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *data) { @@ -184,13 +207,42 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const url = request.url(); operation = op; - if (outgoingData) { - q->connect(outgoingData, SIGNAL(readyRead()), SLOT(_q_sourceReadyRead())); - q->connect(outgoingData, SIGNAL(readChannelFinished()), SLOT(_q_sourceReadChannelFinished())); + if (outgoingData && backend) { + // there is data to be uploaded, e.g. HTTP POST. + + if (!backend->needsResetableUploadData() || !outgoingData->isSequential()) { + // backend does not need upload buffering or + // fixed size non-sequential + // just start the operation + QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); + } else { + bool bufferingDisallowed = + req.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, + false).toBool(); + + if (bufferingDisallowed) { + // if a valid content-length header for the request was supplied, we can disable buffering + // if not, we will buffer anyway + if (req.header(QNetworkRequest::ContentLengthHeader).isValid()) { + QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); + } else { + state = Buffering; + QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection); + } + } else { + // _q_startOperation will be called when the buffering has finished. + state = Buffering; + QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection); + } + } + } else { + // No outgoing data (e.g. HTTP GET request) + // or no backend + // if no backend, _q_startOperation will handle the error of this + QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); } q->QIODevice::open(QIODevice::ReadOnly); - QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); } void QNetworkReplyImplPrivate::setNetworkCache(QAbstractNetworkCache *nc) @@ -226,18 +278,10 @@ void QNetworkReplyImplPrivate::handleNotifications() backend->downstreamReadyWrite(); break; - case NotifyUpstreamReadyRead: - backend->upstreamReadyRead(); - break; - case NotifyCloseDownstreamChannel: backend->closeDownstreamChannel(); break; - case NotifyCloseUpstreamChannel: - backend->closeUpstreamChannel(); - break; - case NotifyCopyFinished: { QIODevice *dev = copyDevice; copyDevice = 0; @@ -299,29 +343,14 @@ void QNetworkReplyImplPrivate::completeCacheSave() cacheEnabled = false; } -void QNetworkReplyImplPrivate::consume(qint64 count) +void QNetworkReplyImplPrivate::emitUploadProgress(qint64 bytesSent, qint64 bytesTotal) { Q_Q(QNetworkReplyImpl); - if (count <= 0) { - qWarning("QNetworkConnection: backend signalled that it consumed %ld bytes", long(count)); - return; - } - - if (outgoingData) - // schedule another read from the source - QMetaObject::invokeMethod(q_func(), "_q_sourceReadyRead", Qt::QueuedConnection); - - writeBuffer.skip(count); - if (bytesUploaded == -1) - bytesUploaded = count; - else - bytesUploaded += count; - - QVariant totalSize = request.header(QNetworkRequest::ContentLengthHeader); - emit q->uploadProgress(bytesUploaded, - totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); + bytesUploaded = bytesSent; + emit q->uploadProgress(bytesSent, bytesTotal); } + qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const { enum { DesiredBufferSize = 32 * 1024 }; @@ -331,7 +360,9 @@ qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const return qMax<qint64>(0, readBufferMaxSize - readBuffer.size()); } -void QNetworkReplyImplPrivate::feed(const QByteArray &data) +// we received downstream data and send this to the cache +// and to our readBuffer (which in turn gets read by the user of QNetworkReply) +void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data) { Q_Q(QNetworkReplyImpl); if (!q->isOpen()) @@ -379,10 +410,12 @@ void QNetworkReplyImplPrivate::feed(const QByteArray &data) } } -void QNetworkReplyImplPrivate::feed(QIODevice *data) +// this is used when it was fetched from the cache, right? +void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data) { Q_Q(QNetworkReplyImpl); - Q_ASSERT(q->isOpen()); + if (!q->isOpen()) + return; // read until EOF from data if (copyDevice) { @@ -409,9 +442,11 @@ void QNetworkReplyImplPrivate::finished() pendingNotifications.clear(); QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); - if (bytesDownloaded != lastBytesDownloaded || totalSize.isNull()) + if (totalSize.isNull() || totalSize == -1) { emit q->downloadProgress(bytesDownloaded, bytesDownloaded); - if (bytesUploaded == -1 && outgoingData) + } + + if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer)) emit q->uploadProgress(0, 0); completeCacheSave(); diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index ad06f78..8d3c90e 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -59,6 +59,7 @@ #include "qnetworkproxy.h" #include "QtCore/qmap.h" #include "QtCore/qqueue.h" +#include "QtCore/qbuffer.h" #include "private/qringbuffer_p.h" QT_BEGIN_NAMESPACE @@ -91,10 +92,10 @@ public: Q_DECLARE_PRIVATE(QNetworkReplyImpl) Q_PRIVATE_SLOT(d_func(), void _q_startOperation()) - Q_PRIVATE_SLOT(d_func(), void _q_sourceReadyRead()) - Q_PRIVATE_SLOT(d_func(), void _q_sourceReadChannelFinished()) Q_PRIVATE_SLOT(d_func(), void _q_copyReadyRead()) Q_PRIVATE_SLOT(d_func(), void _q_copyReadChannelFinished()) + Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingData()) + Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingDataFinished()) }; class QNetworkReplyImplPrivate: public QNetworkReplyPrivate @@ -102,15 +103,13 @@ class QNetworkReplyImplPrivate: public QNetworkReplyPrivate public: enum InternalNotifications { NotifyDownstreamReadyWrite, - NotifyUpstreamReadyRead, NotifyCloseDownstreamChannel, - NotifyCloseUpstreamChannel, NotifyCopyFinished }; enum State { Idle, - Opening, + Buffering, Working, Finished, Aborted @@ -125,6 +124,8 @@ public: void _q_sourceReadChannelFinished(); void _q_copyReadyRead(); void _q_copyReadChannelFinished(); + void _q_bufferOutgoingData(); + void _q_bufferOutgoingDataFinished(); void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData); @@ -138,9 +139,10 @@ public: void setCachingEnabled(bool enable); bool isCachingEnabled() const; void consume(qint64 count); + void emitUploadProgress(qint64 bytesSent, qint64 bytesTotal); qint64 nextDownstreamBlockSize() const; - void feed(const QByteArray &data); - void feed(QIODevice *data); + void appendDownstreamData(const QByteArray &data); + void appendDownstreamData(QIODevice *data); void finished(); void error(QNetworkReply::NetworkError code, const QString &errorString); void metaDataChanged(); @@ -149,6 +151,7 @@ public: QNetworkAccessBackend *backend; QIODevice *outgoingData; + QRingBuffer *outgoingDataBuffer; QIODevice *copyDevice; QAbstractNetworkCache *networkCache; diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 56b793d..8b1afba 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -162,6 +162,13 @@ QT_BEGIN_NAMESPACE Indicates whether the data was obtained from cache or not. + \value DoNotBufferUploadDataAttribute + Requests only, type: QVariant::Bool (default: false) + Indicates whether the QNetworkAccessManager code is + allowed to buffer the upload data, e.g. when doing a HTTP POST. + When using this flag with sequential upload data, the ContentLengthHeader + header must be set. + \value User Special type. Additional information can be passed in QVariants with types ranging from User to UserMax. The default diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index 6f34bce..5dea1df 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -75,6 +75,7 @@ public: CacheLoadControlAttribute, CacheSaveControlAttribute, SourceIsFromCacheAttribute, + DoNotBufferUploadDataAttribute, User = 1000, UserMax = 32767 diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index c9161f8..b672765 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -73,6 +73,15 @@ static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phas authentication information to the socket when accessing services that require authentication. + QAuthenticator supports the following authentication methods: + \list + \o Basic + \o NTLM version 1 + \o Digest-MD5 + \endlist + + Note that, in particular, NTLM version 2 is not supported. + \sa QSslSocket */ @@ -502,13 +511,13 @@ QByteArray QAuthenticatorPrivate::digestMd5Response(const QByteArray &challenge, credentials += "uri=\"" + path + "\", "; if (!opaque.isEmpty()) credentials += "opaque=\"" + opaque + "\", "; - credentials += "response=\"" + response + "\""; + credentials += "response=\"" + response + '\"'; if (!options.value("algorithm").isEmpty()) credentials += ", algorithm=" + options.value("algorithm"); if (!options.value("qop").isEmpty()) { credentials += ", qop=" + qop + ", "; credentials += "nc=" + nonceCountString + ", "; - credentials += "cnonce=\"" + cnonce + "\""; + credentials += "cnonce=\"" + cnonce + '\"'; } return credentials; diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index b225c17..c2fb690 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -1078,7 +1078,7 @@ QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet) #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const QHostAddress &address) { - d.maybeSpace() << "QHostAddress(" << address.toString() << ")"; + d.maybeSpace() << "QHostAddress(" << address.toString() << ')'; return d.space(); } #endif diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp index 0a34e2b..472bc4b 100644 --- a/src/network/kernel/qhostinfo_win.cpp +++ b/src/network/kernel/qhostinfo_win.cpp @@ -72,21 +72,6 @@ struct qt_addrinfo qt_addrinfo *ai_next; }; -// sockaddr_in6 size changed between old and new SDK -// Only the new version is the correct one, so always -// use this structure. -struct qt_in6_addr { - uchar qt_s6_addr[16]; -}; - -struct qt_sockaddr_in6 { - short sin6_family; /* AF_INET6 */ - u_short sin6_port; /* Transport level port number */ - u_long sin6_flowinfo; /* IPv6 flow information */ - struct qt_in6_addr sin6_addr; /* IPv6 address */ - u_long sin6_scope_id; /* set of interfaces for a scope */ -}; - //### #define QT_SOCKLEN_T int #ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h? diff --git a/src/network/kernel/qnetworkinterface.cpp b/src/network/kernel/qnetworkinterface.cpp index 670745b..f12b0c0 100644 --- a/src/network/kernel/qnetworkinterface.cpp +++ b/src/network/kernel/qnetworkinterface.cpp @@ -397,7 +397,7 @@ QNetworkInterface::~QNetworkInterface() } /*! - Creates a copy of the the QNetworkInterface object contained in \a + Creates a copy of the QNetworkInterface object contained in \a other. */ QNetworkInterface::QNetworkInterface(const QNetworkInterface &other) @@ -594,7 +594,7 @@ static inline QDebug operator<<(QDebug debug, const QNetworkAddressEntry &entry) debug.nospace() << ", netmask = " << entry.netmask(); if (!entry.broadcast().isNull()) debug.nospace() << ", broadcast = " << entry.broadcast(); - debug.nospace() << ")"; + debug.nospace() << ')'; return debug.space(); } diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp index f4ece97..fd3a85a 100644 --- a/src/network/kernel/qnetworkproxy.cpp +++ b/src/network/kernel/qnetworkproxy.cpp @@ -86,10 +86,11 @@ The SOCKS5 support in Qt 4 is based on \l{RFC 1928} and \l{RFC 1929}. The supported authentication methods are no authentication and username/password authentication. Both IPv4 and IPv6 are - supported, but domain name resolution via the SOCKS server is not - supported; i.e. all domain names are resolved locally. There are - several things to remember when using SOCKS5 with QUdpSocket and - QTcpServer: + supported. Domain names are resolved through the SOCKS5 server if + the QNetworkProxy::HostNameLookupCapability is enabled, otherwise + they are resolved locally and the IP address is sent to the + server. There are several things to remember when using SOCKS5 + with QUdpSocket and QTcpServer: With QUdpSocket, a call to \l {QUdpSocket::bind()}{bind()} may fail with a timeout error. If a port number other than 0 is passed to @@ -365,7 +366,8 @@ static QNetworkProxy::Capabilities defaultCapabilitiesForType(QNetworkProxy::Pro int(QNetworkProxy::HostNameLookupCapability)), }; - Q_ASSERT(int(type) >= 0 && int(type) <= int(QNetworkProxy::FtpCachingProxy)); + if (int(type) < 0 && int(type) > int(QNetworkProxy::FtpCachingProxy)) + type = QNetworkProxy::DefaultProxy; return QNetworkProxy::Capabilities(defaults[int(type)]); } @@ -378,6 +380,7 @@ public: QNetworkProxy::Capabilities capabilities; quint16 port; QNetworkProxy::ProxyType type; + bool capabilitiesSet; inline QNetworkProxyPrivate(QNetworkProxy::ProxyType t = QNetworkProxy::DefaultProxy, const QString &h = QString(), quint16 p = 0, @@ -387,7 +390,8 @@ public: password(pw), capabilities(defaultCapabilitiesForType(t)), port(p), - type(t) + type(t), + capabilitiesSet(false) { } inline bool operator==(const QNetworkProxyPrivate &other) const @@ -490,13 +494,16 @@ QNetworkProxy &QNetworkProxy::operator=(const QNetworkProxy &other) Sets the proxy type for this instance to be \a type. Note that changing the type of a proxy does not change - the set of capabilities this QNetworkProxy object holds. + the set of capabilities this QNetworkProxy object holds if any + capabilities have been set with setCapabilities(). \sa type(), setCapabilities() */ void QNetworkProxy::setType(QNetworkProxy::ProxyType type) { d->type = type; + if (!d->capabilitiesSet) + d->capabilities = defaultCapabilitiesForType(type); } /*! @@ -519,6 +526,7 @@ QNetworkProxy::ProxyType QNetworkProxy::type() const void QNetworkProxy::setCapabilities(Capabilities capabilities) { d->capabilities = capabilities; + d->capabilitiesSet = true; } /*! @@ -1250,6 +1258,6 @@ QList<QNetworkProxy> QNetworkProxyFactory::proxyForQuery(const QNetworkProxyQuer return globalNetworkProxy()->proxyForQuery(query); } -#endif // QT_NO_NETWORKPROXY - QT_END_NAMESPACE + +#endif // QT_NO_NETWORKPROXY diff --git a/src/network/kernel/qurlinfo.cpp b/src/network/kernel/qurlinfo.cpp index 255c9ea..d90c480 100644 --- a/src/network/kernel/qurlinfo.cpp +++ b/src/network/kernel/qurlinfo.cpp @@ -726,6 +726,6 @@ bool QUrlInfo::isValid() const return d != 0; } -#endif // QT_NO_URLINFO - QT_END_NAMESPACE + +#endif // QT_NO_URLINFO diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index f9750f2..2d37e2e 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -99,7 +99,7 @@ the client has read the data). Note that Qt does not limit the write buffer size. You can monitor its size by listening to this signal. - + The readyRead() signal is emitted every time a new chunk of data has arrived. bytesAvailable() then returns the number of bytes that are available for reading. Typically, you would connect the @@ -199,9 +199,10 @@ parameter describes the type of error that occurred. QAbstractSocket::SocketError is not a registered metatype, so for queued - connections, you will have to register it with Q_REGISTER_METATYPE. + connections, you will have to register it with Q_DECLARE_METATYPE() and + qRegisterMetaType(). - \sa error(), errorString() + \sa error(), errorString(), {Creating Custom Qt Types} */ /*! @@ -211,9 +212,10 @@ The \a socketState parameter is the new state. QAbstractSocket::SocketState is not a registered metatype, so for queued - connections, you will have to register it with Q_REGISTER_METATYPE. + connections, you will have to register it with Q_REGISTER_METATYPE() and + qRegisterMetaType(). - \sa state() + \sa state(), {Creating Custom Qt Types} */ /*! @@ -850,7 +852,7 @@ void QAbstractSocketPrivate::_q_startConnecting(const QHostInfo &hostInfo) if (i != 0) s += ", "; s += addresses.at(i).toString(); } - s += "}"; + s += '}'; qDebug("QAbstractSocketPrivate::_q_startConnecting(hostInfo == %s)", s.toLatin1().constData()); #endif @@ -1127,7 +1129,7 @@ bool QAbstractSocketPrivate::readFromSocket() /*! \internal - Sets up the the internal state after the connection has succeeded. + Sets up the internal state after the connection has succeeded. */ void QAbstractSocketPrivate::fetchConnectionParameters() { @@ -1864,9 +1866,9 @@ bool QAbstractSocket::waitForDisconnected(int msecs) } /*! - Aborts the current connection and resets the socket. Unlike - disconnectFromHost(), this function immediately closes the socket, discarding - any pending data in the write buffer. + Aborts the current connection and resets the socket. Unlike disconnectFromHost(), + this function immediately closes the socket, discarding any pending data in the + write buffer. \sa disconnectFromHost(), close() */ @@ -2163,7 +2165,12 @@ void QAbstractSocket::setPeerName(const QString &name) } /*! - Disconnects the socket's connection with the host. + Closes the I/O device for the socket, disconnects the socket's connection with the + host, closes the socket, and resets the name, address, port number and underlying + socket descriptor. + + See QIODevice::close() for a description of the actions that occur when an I/O + device is closed. \sa abort() */ @@ -2456,7 +2463,8 @@ QNetworkProxy QAbstractSocket::proxy() const #endif // QT_NO_NETWORKPROXY #ifdef QT3_SUPPORT -/*! \enum QAbstractSocket::Error +/*! + \enum QAbstractSocket::Error \compat Use QAbstractSocket::SocketError instead. @@ -2588,7 +2596,7 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QAbstractSocket::SocketError er debug << "QAbstractSocket::ProxyProtocolError"; break; default: - debug << "QAbstractSocket::SocketError(" << int(error) << ")"; + debug << "QAbstractSocket::SocketError(" << int(error) << ')'; break; } return debug; @@ -2619,7 +2627,7 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QAbstractSocket::SocketState st debug << "QAbstractSocket::ClosingState"; break; default: - debug << "QAbstractSocket::SocketState(" << int(state) << ")"; + debug << "QAbstractSocket::SocketState(" << int(state) << ')'; break; } return debug; diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 540c443..5a2a746 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -768,6 +768,6 @@ QAbstractSocketEngine *QHttpSocketEngineHandler::createSocketEngine(int, QObject return 0; } -#endif - QT_END_NAMESPACE + +#endif diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp index d6b1507..77a999b 100644 --- a/src/network/socket/qlocalserver.cpp +++ b/src/network/socket/qlocalserver.cpp @@ -276,9 +276,13 @@ QLocalSocket *QLocalServer::nextPendingConnection() if (d->pendingConnections.isEmpty()) return 0; QLocalSocket *nextSocket = d->pendingConnections.dequeue(); +#ifndef QT_LOCALSOCKET_TCP + if (d->pendingConnections.size() <= d->maxPendingConnections) #ifndef Q_OS_WIN - d->socketNotifier->setEnabled(d->pendingConnections.size() - <= d->maxPendingConnections); + d->socketNotifier->setEnabled(true); +#else + d->connectionEventNotifier->setEnabled(true); +#endif #endif return nextSocket; } diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h index 8e8babd..1488a75 100644 --- a/src/network/socket/qlocalserver.h +++ b/src/network/socket/qlocalserver.h @@ -86,15 +86,7 @@ protected: private: Q_DISABLE_COPY(QLocalServer) -#if defined(QT_LOCALSOCKET_TCP) Q_PRIVATE_SLOT(d_func(), void _q_onNewConnection()) -#elif defined(Q_OS_WIN) - Q_PRIVATE_SLOT(d_func(), void _q_openSocket(HANDLE handle)) - Q_PRIVATE_SLOT(d_func(), void _q_stoppedListening()) - Q_PRIVATE_SLOT(d_func(), void _q_setError(QAbstractSocket::SocketError error, const QString &errorString)) -#else - Q_PRIVATE_SLOT(d_func(), void _q_socketActivated()) -#endif }; #endif // QT_NO_LOCALSERVER diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h index 8e96401..7b31082 100644 --- a/src/network/socket/qlocalserver_p.h +++ b/src/network/socket/qlocalserver_p.h @@ -63,7 +63,7 @@ # include <qtcpserver.h> #elif defined(Q_OS_WIN) # include <qt_windows.h> -# include <qthread.h> +# include <private/qwineventnotifier_p.h> #else # include <private/qnativesocketengine_p.h> # include <qsocketnotifier.h> @@ -71,52 +71,13 @@ QT_BEGIN_NAMESPACE -#if defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP) - -/*! - \internal - QLocalServerThread exists because Windows does not have a - way to provide notifications when there is a new connections to - the server. - */ -class QLocalServerThread : public QThread -{ - Q_OBJECT - -Q_SIGNALS: - void connected(HANDLE newSocket); - void error(QAbstractSocket::SocketError error, const QString &errorString); - -public: - QLocalServerThread(QObject *parent = 0); - ~QLocalServerThread(); - void closeServer(); - -public: - QString setName(const QString &name); - void run(); - void stop(); - bool makeHandle(); - - HANDLE gotConnectionEvent; - QQueue<HANDLE> pendingHandles; - int maxPendingConnections; -private: - HANDLE stopEvent; - QString fullServerName; -}; - -#endif - class QLocalServerPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QLocalServer) public: QLocalServerPrivate() : -#if defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP) - inWaitingFunction(false), -#elif !defined(QT_LOCALSOCKET_TCP) +#if !defined(QT_LOCALSOCKET_TCP) && !defined(Q_OS_WIN) listenSocket(-1), socketNotifier(0), #endif maxPendingConnections(30), error(QAbstractSocket::UnknownSocketError) @@ -128,22 +89,26 @@ public: static bool removeServer(const QString &name); void closeServer(); void waitForNewConnection(int msec, bool *timedOut); + void _q_onNewConnection(); #if defined(QT_LOCALSOCKET_TCP) - void _q_onNewConnection(); QTcpServer tcpServer; QMap<quintptr, QTcpSocket*> socketMap; #elif defined(Q_OS_WIN) - void _q_openSocket(HANDLE socket); - void _q_stoppedListening(); - void _q_setError(QAbstractSocket::SocketError error, const QString &errorString); + struct Listener { + HANDLE handle; + OVERLAPPED overlapped; + }; + + void setError(const QString &function); + bool addListener(); - QLocalServerThread waitForConnection; - bool inWaitingFunction; + QList<Listener> listeners; + HANDLE eventHandle; + QWinEventNotifier *connectionEventNotifier; #else void setError(const QString &function); - void _q_socketActivated(); int listenSocket; QSocketNotifier *socketNotifier; diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index e7d2252..53ee6b6 100644 --- a/src/network/socket/qlocalserver_unix.cpp +++ b/src/network/socket/qlocalserver_unix.cpp @@ -132,7 +132,7 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) socketNotifier = new QSocketNotifier(listenSocket, QSocketNotifier::Read, q); q->connect(socketNotifier, SIGNAL(activated(int)), - q, SLOT(_q_socketActivated())); + q, SLOT(_q_onNewConnection())); socketNotifier->setEnabled(maxPendingConnections > 0); return true; } @@ -164,7 +164,7 @@ void QLocalServerPrivate::closeServer() We have received a notification that we can read on the listen socket. Accept the new socket. */ -void QLocalServerPrivate::_q_socketActivated() +void QLocalServerPrivate::_q_onNewConnection() { Q_Q(QLocalServer); if (-1 == listenSocket) @@ -209,7 +209,7 @@ void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut) break; } if (result > 0) - _q_socketActivated(); + _q_onNewConnection(); } if (timedOut) *timedOut = (result == 0); diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp index 880cd7e..b14bbf7 100644 --- a/src/network/socket/qlocalserver_win.cpp +++ b/src/network/socket/qlocalserver_win.cpp @@ -44,68 +44,26 @@ #include "qlocalsocket.h" #include <qdebug.h> -#include <qdatetime.h> -#include <qcoreapplication.h> -#include <QMetaType> // The buffer size need to be 0 otherwise data could be // lost if the socket that has written data closes the connection // before it is read. Pipewriter is used for write buffering. #define BUFSIZE 0 -QT_BEGIN_NAMESPACE - -QLocalServerThread::QLocalServerThread(QObject *parent) : QThread(parent), - maxPendingConnections(1) -{ - stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - gotConnectionEvent = CreateEvent(NULL, TRUE, FALSE, NULL); -} +// ###: This should be a property. Should replace the insane 50 on unix as well. +#define SYSTEM_MAX_PENDING_SOCKETS 8 -QLocalServerThread::~QLocalServerThread() -{ - stop(); - closeServer(); - CloseHandle(stopEvent); - CloseHandle(gotConnectionEvent); -} - -void QLocalServerThread::stop() -{ - if (isRunning()) { - SetEvent(stopEvent); - wait(); - ResetEvent(stopEvent); - } -} - -void QLocalServerThread::closeServer() -{ - while (!pendingHandles.isEmpty()) - CloseHandle(pendingHandles.dequeue()); -} - -QString QLocalServerThread::setName(const QString &name) -{ - QString pipePath = QLatin1String("\\\\.\\pipe\\"); - if (name.startsWith(pipePath)) - fullServerName = name; - else - fullServerName = pipePath + name; - for (int i = pendingHandles.count(); i < maxPendingConnections; ++i) - if (!makeHandle()) - break; - return fullServerName; -} +QT_BEGIN_NAMESPACE -bool QLocalServerThread::makeHandle() +bool QLocalServerPrivate::addListener() { - if (pendingHandles.count() >= maxPendingConnections) - return false; + // The object must not change its address once the + // contained OVERLAPPED struct is passed to Windows. + listeners << Listener(); + Listener &listener = listeners.last(); - HANDLE handle = INVALID_HANDLE_VALUE; QT_WA({ - handle = CreateNamedPipeW( + listener.handle = CreateNamedPipeW( (TCHAR*)fullServerName.utf16(), // pipe name PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access PIPE_TYPE_MESSAGE | // message type pipe @@ -117,7 +75,7 @@ bool QLocalServerThread::makeHandle() 3000, // client time-out NULL); }, { - handle = CreateNamedPipeA( + listener.handle = CreateNamedPipeA( fullServerName.toLocal8Bit().constData(), // pipe name PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access PIPE_TYPE_MESSAGE | // message type pipe @@ -129,68 +87,43 @@ bool QLocalServerThread::makeHandle() 3000, // client time-out NULL); }); - - if (INVALID_HANDLE_VALUE == handle) { + if (listener.handle == INVALID_HANDLE_VALUE) { + setError(QLatin1String("QLocalServerPrivate::addListener")); + listeners.removeLast(); return false; } - pendingHandles.enqueue(handle); + + memset(&listener.overlapped, 0, sizeof(listener.overlapped)); + listener.overlapped.hEvent = eventHandle; + if (!ConnectNamedPipe(listener.handle, &listener.overlapped)) { + switch (GetLastError()) { + case ERROR_IO_PENDING: + break; + case ERROR_PIPE_CONNECTED: + SetEvent(eventHandle); + break; + default: + CloseHandle(listener.handle); + setError(QLatin1String("QLocalServerPrivate::addListener")); + listeners.removeLast(); + return false; + } + } else { + Q_ASSERT_X(false, "QLocalServerPrivate::addListener", "The impossible happened"); + SetEvent(eventHandle); + } return true; } -void QLocalServerThread::run() +void QLocalServerPrivate::setError(const QString &function) { - OVERLAPPED op; - HANDLE handleArray[2]; - memset(&op, 0, sizeof(op)); - handleArray[0] = op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - handleArray[1] = stopEvent; - HANDLE handle = INVALID_HANDLE_VALUE; - - forever { - if (INVALID_HANDLE_VALUE == handle) { - makeHandle(); - if (!pendingHandles.isEmpty()) - handle = pendingHandles.dequeue(); - } - if (INVALID_HANDLE_VALUE == handle) { - int windowsError = GetLastError(); - QString function = QLatin1String("QLocalServer::run"); - QString errorString = QLocalServer::tr("%1: Unknown error %2").arg(function).arg(windowsError); - emit error(QAbstractSocket::UnknownSocketError, errorString); - CloseHandle(handleArray[0]); - SetEvent(gotConnectionEvent); - return; - } - - BOOL isConnected = ConnectNamedPipe(handle, &op) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); - if (!isConnected) { - switch (WaitForMultipleObjects(2, handleArray, FALSE, INFINITE)) - { - case WAIT_OBJECT_0 + 1: - CloseHandle(handle); - CloseHandle(handleArray[0]); - return; - } - } - emit connected(handle); - handle = INVALID_HANDLE_VALUE; - ResetEvent(handleArray[0]); - SetEvent(gotConnectionEvent); - } + int windowsError = GetLastError(); + errorString = QString::fromLatin1("%1: %2").arg(function).arg(qt_error_string(windowsError)); + error = QAbstractSocket::UnknownSocketError; } void QLocalServerPrivate::init() { - Q_Q(QLocalServer); - qRegisterMetaType<HANDLE>("HANDLE"); - q->connect(&waitForConnection, SIGNAL(connected(HANDLE)), - q, SLOT(_q_openSocket(HANDLE)), Qt::QueuedConnection); - q->connect(&waitForConnection, SIGNAL(finished()), - q, SLOT(_q_stoppedListening()), Qt::QueuedConnection); - q->connect(&waitForConnection, SIGNAL(terminated()), - q, SLOT(_q_stoppedListening()), Qt::QueuedConnection); - q->connect(&waitForConnection, SIGNAL(error(QAbstractSocket::SocketError, const QString &)), - q, SLOT(_q_setError(QAbstractSocket::SocketError, const QString &))); } bool QLocalServerPrivate::removeServer(const QString &name) @@ -201,35 +134,71 @@ bool QLocalServerPrivate::removeServer(const QString &name) bool QLocalServerPrivate::listen(const QString &name) { - fullServerName = waitForConnection.setName(name); - serverName = name; - waitForConnection.start(); - return true; -} + Q_Q(QLocalServer); -void QLocalServerPrivate::_q_setError(QAbstractSocket::SocketError e, const QString &eString) -{ - error = e; - errorString = eString; -} + QString pipePath = QLatin1String("\\\\.\\pipe\\"); + if (name.startsWith(pipePath)) + fullServerName = name; + else + fullServerName = pipePath + name; -void QLocalServerPrivate::_q_stoppedListening() -{ - Q_Q(QLocalServer); - if (!inWaitingFunction) - q->close(); + // Use only one event for all listeners of one socket. + // The idea is that listener events are rare, so polling all listeners once in a while is + // cheap compared to waiting for N additional events in each iteration of the main loop. + eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL); + connectionEventNotifier = new QWinEventNotifier(eventHandle , q); + q->connect(connectionEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onNewConnection())); + + for (int i = 0; i < SYSTEM_MAX_PENDING_SOCKETS; ++i) + if (!addListener()) + return false; + return true; } -void QLocalServerPrivate::_q_openSocket(HANDLE handle) +void QLocalServerPrivate::_q_onNewConnection() { Q_Q(QLocalServer); - q->incomingConnection((int)handle); + DWORD dummy; + + // Reset first, otherwise we could reset an event which was asserted + // immediately after we checked the conn status. + ResetEvent(eventHandle); + + // Testing shows that there is indeed absolutely no guarantee which listener gets + // a client connection first, so there is no way around polling all of them. + for (int i = 0; i < listeners.size(); ) { + HANDLE handle = listeners[i].handle; + if (GetOverlappedResult(handle, &listeners[i].overlapped, &dummy, FALSE)) { + listeners.removeAt(i); + + addListener(); + + if (pendingConnections.size() > maxPendingConnections) + connectionEventNotifier->setEnabled(false); + + // Make this the last thing so connected slots can wreak the least havoc + q->incomingConnection((quintptr)handle); + } else { + if (GetLastError() != ERROR_IO_INCOMPLETE) { + setError(QLatin1String("QLocalServerPrivate::_q_onNewConnection")); + closeServer(); + return; + } + + ++i; + } + } } void QLocalServerPrivate::closeServer() { - waitForConnection.stop(); - waitForConnection.closeServer(); + connectionEventNotifier->setEnabled(false); // Otherwise, closed handle is checked before deleter runs + connectionEventNotifier->deleteLater(); + connectionEventNotifier = 0; + CloseHandle(eventHandle); + for (int i = 0; i < listeners.size(); ++i) + CloseHandle(listeners[i].handle); + listeners.clear(); } void QLocalServerPrivate::waitForNewConnection(int msecs, bool *timedOut) @@ -238,14 +207,12 @@ void QLocalServerPrivate::waitForNewConnection(int msecs, bool *timedOut) if (!pendingConnections.isEmpty() || !q->isListening()) return; - DWORD result = WaitForSingleObject(waitForConnection.gotConnectionEvent, - (msecs == -1) ? INFINITE : msecs); + DWORD result = WaitForSingleObject(eventHandle, (msecs == -1) ? INFINITE : msecs); if (result == WAIT_TIMEOUT) { if (timedOut) *timedOut = true; } else { - ResetEvent(waitForConnection.gotConnectionEvent); - QCoreApplication::instance()->processEvents(); + _q_onNewConnection(); } } diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp index 327bfc6..9411130 100644 --- a/src/network/socket/qlocalsocket.cpp +++ b/src/network/socket/qlocalsocket.cpp @@ -468,7 +468,7 @@ QDebug operator<<(QDebug debug, QLocalSocket::LocalSocketError error) debug << "QLocalSocket::UnknownSocketError"; break; default: - debug << "QLocalSocket::SocketError(" << int(error) << ")"; + debug << "QLocalSocket::SocketError(" << int(error) << ')'; break; } return debug; @@ -490,7 +490,7 @@ QDebug operator<<(QDebug debug, QLocalSocket::LocalSocketState state) debug << "QLocalSocket::ClosingState"; break; default: - debug << "QLocalSocket::SocketState(" << int(state) << ")"; + debug << "QLocalSocket::SocketState(" << int(state) << ')'; break; } return debug; diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 3366f2d..eb031d3 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -56,7 +56,9 @@ #include "QtNetwork/qhostaddress.h" #include "private/qabstractsocketengine_p.h" #ifndef Q_OS_WIN -#include "qplatformdefs.h" +# include "qplatformdefs.h" +#else +# include <winsock2.h> #endif QT_BEGIN_NAMESPACE @@ -90,6 +92,39 @@ static inline int qt_socket_socket(int domain, int type, int protocol) #endif +// Use our own defines and structs which we know are correct +# define QT_SS_MAXSIZE 128 +# define QT_SS_ALIGNSIZE (sizeof(qint64)) +# define QT_SS_PAD1SIZE (QT_SS_ALIGNSIZE - sizeof (short)) +# define QT_SS_PAD2SIZE (QT_SS_MAXSIZE - (sizeof (short) + QT_SS_PAD1SIZE + QT_SS_ALIGNSIZE)) +struct qt_sockaddr_storage { + short ss_family; + char __ss_pad1[QT_SS_PAD1SIZE]; + qint64 __ss_align; + char __ss_pad2[QT_SS_PAD2SIZE]; +}; + +// sockaddr_in6 size changed between old and new SDK +// Only the new version is the correct one, so always +// use this structure. +struct qt_in6_addr { + quint8 qt_s6_addr[16]; +}; +struct qt_sockaddr_in6 { + short sin6_family; /* AF_INET6 */ + quint16 sin6_port; /* Transport level port number */ + quint32 sin6_flowinfo; /* IPv6 flow information */ + struct qt_in6_addr sin6_addr; /* IPv6 address */ + quint32 sin6_scope_id; /* set of interfaces for a scope */ +}; + +union qt_sockaddr { + sockaddr a; + sockaddr_in a4; + qt_sockaddr_in6 a6; + qt_sockaddr_storage storage; +}; + class QNativeSocketEnginePrivate; class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index cc372a6..75b5a64 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -114,36 +114,34 @@ static void qt_ignore_sigpipe() Extracts the port and address from a sockaddr, and stores them in \a port and \a addr if they are non-null. */ -static inline void qt_socket_getPortAndAddress(struct sockaddr *sa, quint16 *port, QHostAddress *addr) +static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *port, QHostAddress *addr) { #if !defined(QT_NO_IPV6) - if (sa->sa_family == AF_INET6) { - struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; + if (s->a.sa_family == AF_INET6) { Q_IPV6ADDR tmp; - memcpy(&tmp, &sa6->sin6_addr.s6_addr, sizeof(tmp)); + memcpy(&tmp, &s->a6.sin6_addr, sizeof(tmp)); if (addr) { QHostAddress tmpAddress; tmpAddress.setAddress(tmp); *addr = tmpAddress; #ifndef QT_NO_IPV6IFNAME char scopeid[IFNAMSIZ]; - if (::if_indextoname(sa6->sin6_scope_id, scopeid) > 0) { + if (::if_indextoname(s->a6.sin6_scope_id, scopeid) > 0) { addr->setScopeId(QLatin1String(scopeid)); } else #endif - addr->setScopeId(QString::number(sa6->sin6_scope_id)); + addr->setScopeId(QString::number(s->a6.sin6_scope_id)); } if (port) - *port = ntohs(sa6->sin6_port); + *port = ntohs(s->a6.sin6_port); return; } #endif - struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; if (port) - *port = ntohs(sa4->sin_port); + *port = ntohs(s->a4.sin_port); if (addr) { QHostAddress tmpAddress; - tmpAddress.setAddress(ntohl(sa4->sin_addr.s_addr)); + tmpAddress.setAddress(ntohl(s->a4.sin_addr.s_addr)); *addr = tmpAddress; } } @@ -521,26 +519,16 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const { // Create a sockaddr struct and reset its port number. -#if !defined(QT_NO_IPV6) - struct sockaddr_storage storage; - sockaddr_in6 *storagePtrIPv6 = reinterpret_cast<sockaddr_in6 *>(&storage); - storagePtrIPv6->sin6_port = 0; -#else - struct sockaddr storage; -#endif - sockaddr *storagePtr = reinterpret_cast<sockaddr *>(&storage); - storagePtr->sa_family = 0; - - sockaddr_in *storagePtrIPv4 = reinterpret_cast<sockaddr_in *>(&storage); - storagePtrIPv4->sin_port = 0; + qt_sockaddr storage; QT_SOCKLEN_T storageSize = sizeof(storage); + memset(&storage, 0, storageSize); // Peek 0 bytes into the next message. The size of the message may // well be 0, so we can't check recvfrom's return value. ssize_t readBytes; do { char c; - readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, storagePtr, &storageSize); + readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize); } while (readBytes == -1 && errno == EINTR); // If there's no error, or if our buffer was too small, there must be a @@ -583,11 +571,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port) { -#if !defined(QT_NO_IPV6) - struct sockaddr_storage aa; -#else - struct sockaddr_in aa; -#endif + qt_sockaddr aa; memset(&aa, 0, sizeof(aa)); QT_SOCKLEN_T sz; sz = sizeof(aa); @@ -596,13 +580,13 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS do { char c; recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, - 0, (struct sockaddr *)&aa, &sz); + 0, &aa.a, &sz); } while (recvFromResult == -1 && errno == EINTR); if (recvFromResult == -1) { setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); } else if (port || address) { - qt_socket_getPortAndAddress((struct sockaddr *) &aa, port, address); + qt_socket_getPortAndAddress(&aa, port, address); } #if defined (QNATIVESOCKETENGINE_DEBUG) @@ -682,21 +666,16 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() if (socketDescriptor == -1) return false; -#if !defined(QT_NO_IPV6) - struct sockaddr_storage sa; -#else - struct sockaddr_in sa; -#endif - struct sockaddr *sockAddrPtr = (struct sockaddr *) &sa; + qt_sockaddr sa; QT_SOCKLEN_T sockAddrSize = sizeof(sa); // Determine local address memset(&sa, 0, sizeof(sa)); - if (::getsockname(socketDescriptor, sockAddrPtr, &sockAddrSize) == 0) { - qt_socket_getPortAndAddress(sockAddrPtr, &localPort, &localAddress); + if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) { + qt_socket_getPortAndAddress(&sa, &localPort, &localAddress); // Determine protocol family - switch (sockAddrPtr->sa_family) { + switch (sa.a.sa_family) { case AF_INET: socketProtocol = QAbstractSocket::IPv4Protocol; break; @@ -716,8 +695,8 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() } // Determine the remote address - if (!::getpeername(socketDescriptor, sockAddrPtr, &sockAddrSize)) - qt_socket_getPortAndAddress(sockAddrPtr, &peerPort, &peerAddress); + if (!::getpeername(socketDescriptor, &sa.a, &sockAddrSize)) + qt_socket_getPortAndAddress(&sa, &peerPort, &peerAddress); // Determine the socket type (UDP/TCP) int value = 0; diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index d140be2..b08d7b0 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -149,41 +149,6 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxLength) #endif -#if !defined (QT_NO_IPV6) - -// Use our own defines and structs which we know are correct -# define QT_SS_MAXSIZE 128 -# define QT_SS_ALIGNSIZE (sizeof(__int64)) -# define QT_SS_PAD1SIZE (QT_SS_ALIGNSIZE - sizeof (short)) -# define QT_SS_PAD2SIZE (QT_SS_MAXSIZE - (sizeof (short) + QT_SS_PAD1SIZE + QT_SS_ALIGNSIZE)) -struct qt_sockaddr_storage { - short ss_family; - char __ss_pad1[QT_SS_PAD1SIZE]; - __int64 __ss_align; - char __ss_pad2[QT_SS_PAD2SIZE]; -}; - -// sockaddr_in6 size changed between old and new SDK -// Only the new version is the correct one, so always -// use this structure. -struct qt_in6_addr { - u_char qt_s6_addr[16]; -}; -typedef struct { - short sin6_family; /* AF_INET6 */ - u_short sin6_port; /* Transport level port number */ - u_long sin6_flowinfo; /* IPv6 flow information */ - struct qt_in6_addr sin6_addr; /* IPv6 address */ - u_long sin6_scope_id; /* set of interfaces for a scope */ -} qt_sockaddr_in6; - -#else - -typedef void * qt_sockaddr_in6 ; - - -#endif - #ifndef AF_INET6 #define AF_INET6 23 /* Internetwork Version 6 */ #endif diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index c41e32d..40d86ac 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -153,7 +153,7 @@ static inline QString dump(const QByteArray &) { return QString(); } */ static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, quint16 port, QByteArray *pBuf) { - QSOCKS5_DEBUG << "setting [" << address << ":" << port << "]"; + QSOCKS5_DEBUG << "setting [" << address << ':' << port << ']'; union { quint16 port; @@ -186,7 +186,7 @@ static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, qui */ static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 port, QByteArray *pBuf) { - QSOCKS5_DEBUG << "setting [" << hostname << ":" << port << "]"; + QSOCKS5_DEBUG << "setting [" << hostname << ':' << port << ']'; QByteArray encodedHostName = QUrl::toAce(hostname); QByteArray &buf = *pBuf; @@ -265,7 +265,7 @@ static bool qt_socks5_get_host_address_and_port(const QByteArray &buf, QHostAddr } if (ret) { - QSOCKS5_DEBUG << "got [" << address << ":" << port << "]"; + QSOCKS5_DEBUG << "got [" << address << ':' << port << ']'; *pAddress = address; *pPort = port; *pPos = pos; @@ -1124,7 +1124,7 @@ bool QSocks5SocketEngine::connectInternal() bool QSocks5SocketEngine::connectToHost(const QHostAddress &address, quint16 port) { Q_D(QSocks5SocketEngine); - QSOCKS5_DEBUG << "connectToHost" << address << ":" << port; + QSOCKS5_DEBUG << "connectToHost" << address << ':' << port; setPeerAddress(address); setPeerPort(port); @@ -1379,7 +1379,7 @@ bool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port) //### reset and error return false; } - QSOCKS5_DEBUG << "udp actual address and port" << d->localAddress << ":" << d->localPort; + QSOCKS5_DEBUG << "udp actual address and port" << d->localAddress << ':' << d->localPort; return true; #endif // QT_NO_UDPSOCKET } @@ -1478,7 +1478,7 @@ qint64 QSocks5SocketEngine::bytesAvailable() const qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen) { Q_D(QSocks5SocketEngine); - QSOCKS5_Q_DEBUG << "read( , maxlen = " << maxlen << ")"; + QSOCKS5_Q_DEBUG << "read( , maxlen = " << maxlen << ')'; if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) { if (d->connectData->readBuffer.size() == 0) { if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) { @@ -1766,7 +1766,7 @@ void QSocks5SocketEngine::setReadNotificationEnabled(bool enable) { Q_D(QSocks5SocketEngine); - QSOCKS5_Q_DEBUG << "setReadNotificationEnabled(" << enable << ")"; + QSOCKS5_Q_DEBUG << "setReadNotificationEnabled(" << enable << ')'; bool emitSignal = false; if (!d->readNotificationEnabled diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index a2ba644..7ee0f07 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -267,7 +267,7 @@ QByteArray QSslCertificate::serialNumber() const /*! Returns a cryptographic digest of this certificate. By default, - and MD5 digest will be generated, but you can also specify a + an MD5 digest will be generated, but you can also specify a custom \a algorithm. */ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) const @@ -766,16 +766,16 @@ QDebug operator<<(QDebug debug, const QSslCertificate &certificate) { debug << "QSslCertificate(" << certificate.version() - << "," << certificate.serialNumber() - << "," << certificate.digest().toBase64() - << "," << certificate.issuerInfo(QSslCertificate::Organization) - << "," << certificate.subjectInfo(QSslCertificate::Organization) - << "," << certificate.alternateSubjectNames() + << ',' << certificate.serialNumber() + << ',' << certificate.digest().toBase64() + << ',' << certificate.issuerInfo(QSslCertificate::Organization) + << ',' << certificate.subjectInfo(QSslCertificate::Organization) + << ',' << certificate.alternateSubjectNames() #ifndef QT_NO_TEXTSTREAM - << "," << certificate.effectiveDate() - << "," << certificate.expiryDate() + << ',' << certificate.effectiveDate() + << ',' << certificate.expiryDate() #endif - << ")"; + << ')'; return debug; } QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info) diff --git a/src/network/ssl/qsslcipher.cpp b/src/network/ssl/qsslcipher.cpp index 505c662..696db1e 100644 --- a/src/network/ssl/qsslcipher.cpp +++ b/src/network/ssl/qsslcipher.cpp @@ -64,9 +64,9 @@ #ifndef QT_NO_DEBUG_STREAM #include <QtCore/qdebug.h> +#endif QT_BEGIN_NAMESPACE -#endif /*! Constructs an empty QSslCipher object. @@ -231,7 +231,7 @@ QDebug operator<<(QDebug debug, const QSslCipher &cipher) debug << "QSslCipher(name=" << qPrintable(cipher.name()) << ", bits=" << cipher.usedBits() << ", proto=" << qPrintable(cipher.protocolString()) - << ")"; + << ')'; return debug; } #endif diff --git a/src/network/ssl/qsslkey.cpp b/src/network/ssl/qsslkey.cpp index 8d550c0..6dbdc29 100644 --- a/src/network/ssl/qsslkey.cpp +++ b/src/network/ssl/qsslkey.cpp @@ -460,7 +460,7 @@ QDebug operator<<(QDebug debug, const QSslKey &key) << (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey") << ", " << (key.algorithm() == QSsl::Rsa ? "RSA" : "DSA") << ", " << key.length() - << ")"; + << ')'; return debug; } #endif diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 39ac5da..16033b6 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -113,8 +113,8 @@ readLine(), or getChar() to read decrypted data from QSslSocket's internal buffer, and you can call write() or putChar() to write data back to the peer. QSslSocket will automatically encrypt the - written data for you, and emit bytesWritten() once the data has - been written to the peer. + written data for you, and emit encryptedBytesWritten() once + the data has been written to the peer. As a convenience, QSslSocket supports QTcpSocket's blocking functions waitForConnected(), waitForReadyRead(), @@ -442,8 +442,8 @@ bool QSslSocket::setSocketDescriptor(int socketDescriptor, SocketState state, Op { Q_D(QSslSocket); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::setSocketDescriptor(" << socketDescriptor << "," - << state << "," << openMode << ")"; + qDebug() << "QSslSocket::setSocketDescriptor(" << socketDescriptor << ',' + << state << ',' << openMode << ')'; #endif if (!d->plainSocket) d->createPlainSocket(openMode); @@ -1608,7 +1608,7 @@ void QSslSocket::connectToHostImplementation(const QString &hostName, quint16 po #ifdef QSSLSOCKET_DEBUG qDebug() << "QSslSocket::connectToHostImplementation(" - << hostName << "," << port << "," << openMode << ")"; + << hostName << ',' << port << ',' << openMode << ')'; #endif if (!d->plainSocket) { #ifdef QSSLSOCKET_DEBUG @@ -1682,7 +1682,7 @@ qint64 QSslSocket::readData(char *data, qint64 maxlen) } while (!d->readBuffer.isEmpty() && readBytes < maxlen); } #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::readData(" << (void *)data << "," << maxlen << ") ==" << readBytes; + qDebug() << "QSslSocket::readData(" << (void *)data << ',' << maxlen << ") ==" << readBytes; #endif return readBytes; } @@ -1694,7 +1694,7 @@ qint64 QSslSocket::writeData(const char *data, qint64 len) { Q_D(QSslSocket); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::writeData(" << (void *)data << "," << len << ")"; + qDebug() << "QSslSocket::writeData(" << (void *)data << ',' << len << ')'; #endif if (d->mode == UnencryptedMode && !d->autoStartHandshake) return d->plainSocket->write(data, len); @@ -1999,7 +1999,7 @@ void QSslSocketPrivate::_q_stateChangedSlot(QAbstractSocket::SocketState state) { Q_Q(QSslSocket); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::_q_stateChangedSlot(" << state << ")"; + qDebug() << "QSslSocket::_q_stateChangedSlot(" << state << ')'; #endif q->setSocketState(state); emit q->stateChanged(state); @@ -2012,7 +2012,7 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error) { Q_Q(QSslSocket); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::_q_errorSlot(" << error << ")"; + qDebug() << "QSslSocket::_q_errorSlot(" << error << ')'; qDebug() << "\tstate =" << q->state(); qDebug() << "\terrorString =" << q->errorString(); #endif @@ -2047,7 +2047,7 @@ void QSslSocketPrivate::_q_bytesWrittenSlot(qint64 written) { Q_Q(QSslSocket); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::_q_bytesWrittenSlot(" << written << ")"; + qDebug() << "QSslSocket::_q_bytesWrittenSlot(" << written << ')'; #endif if (mode == QSslSocket::UnencryptedMode) diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 827f461..4017c4d 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -276,7 +276,7 @@ init_context: if (first) first = false; else - cipherString.append(":"); + cipherString.append(':'); cipherString.append(cipher.name().toLatin1()); } @@ -482,30 +482,7 @@ void QSslSocketPrivate::resetDefaultCiphers() QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() { -#ifdef QQ_OS_UNIX - // Check known locations for the system's default bundle. ### On Windows, - // we should use CAPI to find the bundle, and not rely on default unix - // locations. - const char *standardLocations[] = {"/etc/ssl/certs/", -#if 0 - // KDE uses KConfig for its SSL store, - // but it also stores the bundle at - // this location - "$HOME/.kde/share/apps/kssl/ca-bundle.crt", -#endif - 0}; - const char **it = standardLocations; - QStringList nameFilter; - nameFilter << QLatin1String("*.pem") << QLatin1String("*.crt"); - while (*it) { - if (QDirIterator(QLatin1String(*it), nameFilter).hasNext()) - return certificatesFromPath(QLatin1String(*it)); - ++it; - } -#endif - - // Qt provides a default bundle when we cannot detect the system's default - // bundle. + // Qt provides a default bundle of certificates QFile caBundle(QLatin1String(":/trolltech/network/ssl/qt-ca-bundle.crt")); if (caBundle.open(QIODevice::ReadOnly | QIODevice::Text)) return QSslCertificate::fromDevice(&caBundle); @@ -523,7 +500,7 @@ void QSslSocketBackendPrivate::startClientEncryption() // Start connecting. This will place outgoing data in the BIO, so we // follow up with calling transmit(). - testConnection(); + startHandshake(); transmit(); } @@ -536,7 +513,7 @@ void QSslSocketBackendPrivate::startServerEncryption() // Start connecting. This will place outgoing data in the BIO, so we // follow up with calling transmit(). - testConnection(); + startHandshake(); transmit(); } @@ -624,7 +601,7 @@ void QSslSocketBackendPrivate::transmit() #ifdef QSSLSOCKET_DEBUG qDebug() << "QSslSocketBackendPrivate::transmit: testing encryption"; #endif - if (testConnection()) { + if (startHandshake()) { #ifdef QSSLSOCKET_DEBUG qDebug() << "QSslSocketBackendPrivate::transmit: encryption established"; #endif @@ -643,7 +620,7 @@ void QSslSocketBackendPrivate::transmit() } // If the request is small and the remote host closes the transmission - // after sending, there's a chance that testConnection() will already + // after sending, there's a chance that startHandshake() will already // have triggered a shutdown. if (!ssl) continue; @@ -743,7 +720,7 @@ static QSslError _q_OpenSSL_to_QSslError(int errorCode, const QSslCertificate &c return error; } -bool QSslSocketBackendPrivate::testConnection() +bool QSslSocketBackendPrivate::startHandshake() { Q_Q(QSslSocket); @@ -784,7 +761,7 @@ bool QSslSocketBackendPrivate::testConnection() q->setErrorString(QSslSocket::tr("Error during SSL handshake: %1").arg(SSL_ERRORSTR())); q->setSocketError(QAbstractSocket::SslHandshakeFailedError); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocketBackendPrivate::testConnection: error!" << q->errorString(); + qDebug() << "QSslSocketBackendPrivate::startHandshake: error!" << q->errorString(); #endif emit q->error(QAbstractSocket::SslHandshakeFailedError); q->abort(); diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index b3be42a..f53d4e8 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -102,7 +102,7 @@ public: void startClientEncryption(); void startServerEncryption(); void transmit(); - bool testConnection(); + bool startHandshake(); void disconnectFromHost(); void disconnected(); QSslCipher sessionCipher() const; diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index e09e764..42c09f5 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -364,11 +364,14 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl() // DT_RPATH tags on our library header as well as other system-specific search // paths. See the man page for dlopen(3) on your system for more information. +#ifdef Q_OS_OPENBSD + libcrypto->setLoadHints(QLibrary::ExportExternalSymbolsHint); +#endif #ifdef SHLIB_VERSION_NUMBER // first attempt: the canonical name is libssl.so.<SHLIB_VERSION_NUMBER> libssl->setFileNameAndVersion(QLatin1String("ssl"), QLatin1String(SHLIB_VERSION_NUMBER)); libcrypto->setFileNameAndVersion(QLatin1String("crypto"), QLatin1String(SHLIB_VERSION_NUMBER)); - if (libssl->load() && libcrypto->load()) { + if (libcrypto->load() && libssl->load()) { // libssl.so.<SHLIB_VERSION_NUMBER> and libcrypto.so.<SHLIB_VERSION_NUMBER> found return pair; } else { @@ -380,7 +383,7 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl() // second attempt: find the development files libssl.so and libcrypto.so libssl->setFileNameAndVersion(QLatin1String("ssl"), -1); libcrypto->setFileNameAndVersion(QLatin1String("crypto"), -1); - if (libssl->load() && libcrypto->load()) { + if (libcrypto->load() && libssl->load()) { // libssl.so.0 and libcrypto.so.0 found return pair; } else { @@ -395,7 +398,7 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl() crypto.replace(QLatin1String("ssl"), QLatin1String("crypto")); libssl->setFileNameAndVersion(ssl, -1); libcrypto->setFileNameAndVersion(crypto, -1); - if (libssl->load() && libcrypto->load()) { + if (libcrypto->load() && libssl->load()) { // libssl.so.0 and libcrypto.so.0 found return pair; } else { diff --git a/src/opengl/gl2paintengineex/glgc_shader_source.h b/src/opengl/gl2paintengineex/glgc_shader_source.h deleted file mode 100644 index 5b9d28b..0000000 --- a/src/opengl/gl2paintengineex/glgc_shader_source.h +++ /dev/null @@ -1,289 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef GLGC_SHADER_SOURCE_H -#define GLGC_SHADER_SOURCE_H - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(OpenGL) - -static const char* qglslImageVertexShader = "\ - attribute highp vec4 inputVertex; \ - attribute lowp vec2 textureCoord; \ - uniform highp mat4 pmvMatrix; \ - varying lowp vec2 fragTextureCoord; \ - void main(void) \ - {\ - gl_Position = pmvMatrix * inputVertex;\ - fragTextureCoord = textureCoord; \ - }"; - -static const char* qglslImageFragmentShader = "\ - varying lowp vec2 fragTextureCoord;\ - uniform sampler2D textureSampler;\ - uniform lowp float opacity; \ - void main(void) \ - {\ - gl_FragColor = texture2D(textureSampler, fragTextureCoord) * opacity; \ - }"; - -static const char* qglslTextFragmentShader = "\ - varying lowp vec2 fragTextureCoord;\ - uniform mediump vec4 fragmentColor;\ - uniform sampler2D textureSampler;\ - void main(void) \ - {\ - highp vec4 tex = texture2D(textureSampler, fragTextureCoord); \ - tex = fragmentColor * tex.r; \ - gl_FragColor = tex; \ - }"; - -static const char* qglslDefaultVertexShader = "\ - attribute highp vec4 inputVertex;\ - uniform highp mat4 pmvMatrix;\ - void main(void)\ - {\ - gl_Position = pmvMatrix * inputVertex;\ - }"; - -static const char* qglslSimpleFragmentShader = "\ - void main (void)\ - {\ - gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\ - }"; - - -/**** FRAGMENT SHADER MAIN FUNCTIONS ****/ -// NOTE: Currently, the engine assumes brushes return colors already in pre-multiplied -// format. However, this may change if we add support for non-premultiplied - -static const char* qglslNoOpacityFragmentShaderMain = "\n\ - mediump vec4 brush();\ - void main (void)\ - {\ - gl_FragColor = brush();\ - }\n"; - -static const char* qglslFragmentShaderMain = "\n\ - mediump vec4 brush();\ - uniform lowp float opacity; \ - void main (void)\ - {\ - gl_FragColor = brush() * opacity;\ - }\n"; - - - -/**** BRUSH SHADERS ****/ - -// This should never actually be used -static const char* qglslNoBrushFragmentShader = "\n\ - mediump vec4 brush() { \ - discard; \ - return vec4(1.0, 0.8, 0.8, 1.0);\ - }\n"; - -// Solid Fill Brush -static const char* qglslSolidBrushFragmentShader = "\n\ - uniform mediump vec4 fragmentColor; \ - mediump vec4 brush() { \ - return fragmentColor;\ - }\n"; - -// Texture Brush -static const char* qglslTextureBrushVertexShader = "\ - attribute highp vec4 inputVertex; \ - uniform highp mat4 pmvMatrix; \ - uniform mediump vec2 halfViewportSize; \ - uniform mediump vec2 invertedTextureSize; \ - uniform mediump mat3 brushTransform; \ - varying mediump vec2 texCoords; \ - void main(void) { \ - gl_Position = pmvMatrix * inputVertex;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ - texCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \ - texCoords.y = -texCoords.y; \ - }"; - -static const char* qglslTextureBrushFragmentShader = "\n\ - varying mediump vec2 texCoords;\ - uniform sampler2D brushTexture;\ - mediump vec4 brush() { \ - return texture2D(brushTexture, texCoords); \ - }\n"; - - -// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125 -static const char* qglslPatternBrushVertexShader = "\ - attribute highp vec4 inputVertex; \ - uniform highp mat4 pmvMatrix; \ - uniform mediump vec2 halfViewportSize; \ - uniform mediump vec2 invertedTextureSize; \ - uniform mediump mat3 brushTransform; \ - varying mediump vec2 texCoords; \ - void main(void) { \ - gl_Position = pmvMatrix * inputVertex;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ - texCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \ - texCoords.y = -texCoords.y; \ - }"; - -static const char* qglslPatternBrushFragmentShader = "\n\ - uniform sampler2D brushTexture;\ - uniform lowp vec4 patternColor; \ - varying mediump vec2 texCoords;\ - mediump vec4 brush() { \ - return patternColor * texture2D(brushTexture, texCoords).r; \ - }\n"; - - -// Linear Gradient Brush -static const char* qglslLinearGradientBrushVertexShader = "\ - attribute highp vec4 inputVertex; \ - uniform highp mat4 pmvMatrix; \ - uniform mediump vec2 halfViewportSize; \ - uniform highp vec3 linearData; \ - uniform mediump mat3 brushTransform; \ - varying mediump float index ; \ - void main() { \ - gl_Position = pmvMatrix * inputVertex;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ - index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \ - }"; - -static const char* qglslLinearGradientBrushFragmentShader = "\n\ - uniform sampler2D brushTexture; \ - varying mediump float index; \ - mediump vec4 brush() { \ - mediump vec2 val = vec2(index, 0.5); \ - return texture2D(brushTexture, val); \ - }\n"; - - -static const char* qglslRadialGradientBrushVertexShader = "\ - attribute highp vec4 inputVertex;\ - uniform highp mat4 pmvMatrix;\ - uniform mediump vec2 halfViewportSize; \ - uniform highp mat3 brushTransform; \ - uniform highp vec2 fmp; \ - varying highp float b; \ - varying highp vec2 A; \ - void main(void) \ - {\ - gl_Position = pmvMatrix * inputVertex;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ - A = hTexCoords.xy * invertedHTexCoordsZ; \ - b = 2.0 * fmp * (A.x + A.y); \ -\ - }"; - -static const char* qglslRadialGradientBrushFragmentShader = "\n\ - uniform sampler2D brushTexture; \ - uniform highp float fmp2_m_radius2; \ - uniform highp float inverse_2_fmp2_m_radius2; \ - varying highp float b; \ - varying highp vec2 A; \ -\ - mediump vec4 brush() { \ - highp float c = -dot(A, A); \ - highp vec2 val = vec2((-b + sqrt(b*b - 4.0*fmp2_m_radius2*c)) * inverse_2_fmp2_m_radius2, 0.5); \ - return texture2D(brushTexture, val); \ - }\n"; - -static const char* qglslConicalGradientBrushVertexShader = "\ - attribute highp vec4 inputVertex;\ - uniform highp mat4 pmvMatrix;\ - uniform mediump vec2 halfViewportSize; \ - uniform highp mat3 brushTransform; \ - varying highp vec2 A; \ - void main(void)\ - {\ - gl_Position = pmvMatrix * inputVertex;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ - A = hTexCoords.xy * invertedHTexCoordsZ; \ - }"; - -static const char* qglslConicalGradientBrushFragmentShader = "\n\ - #define INVERSE_2PI 0.1591549430918953358 \n\ - uniform sampler2D brushTexture; \ - uniform mediump float angle; \ - varying highp vec2 A; \ - mediump vec4 brush() { \ - if (abs(A.y) == abs(A.x)) \ - A.y += 0.002; \ - highp float t = (atan2(-A.y, A.x) + angle) * INVERSE_2PI; \ - return texture2D(brushTexture, vec2(t - floor(t), 0.5)); \ - }\n"; - - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // GLGC_SHADER_SOURCE_H diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp index 0352d39..560ad3a 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp @@ -43,6 +43,8 @@ #include <private/qbezier_p.h> +QT_BEGIN_NAMESPACE + void QGL2PEXVertexArray::clear() { vertexArray.reset(); @@ -59,6 +61,12 @@ QGLRect QGL2PEXVertexArray::boundingRect() const return QGLRect(minX, minY, maxX, maxY); } +void QGL2PEXVertexArray::addRect(const QRectF &rect) +{ + vertexArray << rect.topLeft() << rect.topRight() << rect.bottomRight() + << rect.bottomRight() << rect.bottomLeft() << rect.topLeft(); +} + void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale) { const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); @@ -154,3 +162,5 @@ void QGL2PEXVertexArray::curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, } } } + +QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h index c205022..d7a9f73 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h @@ -50,19 +50,24 @@ // We mean it. // +#ifndef QGL2PEXVERTEXARRAY_P_H +#define QGL2PEXVERTEXARRAY_P_H + #include <QRectF> #include <private/qdatabuffer_p.h> #include <private/qvectorpath_p.h> #include <private/qgl_p.h> +QT_BEGIN_NAMESPACE + class QGLPoint { public: QGLPoint(GLfloat new_x, GLfloat new_y) : x(new_x), y(new_y) {}; - QGLPoint(QPointF p) : + QGLPoint(const QPointF &p) : x(p.x()), y(p.y()) {}; QGLPoint(const QPointF* p) : @@ -77,7 +82,7 @@ public: struct QGLRect { - QGLRect(QRectF r) + QGLRect(const QRectF &r) : left(r.left()), top(r.top()), right(r.right()), bottom(r.bottom()) {} QGLRect(GLfloat l, GLfloat t, GLfloat r, GLfloat b) @@ -98,6 +103,7 @@ public: maxX(-2e10), maxY(-2e10), minX(2e10), minY(2e10), boundingRectDirty(true) {} + void addRect(const QRectF &rect); void addPath(const QVectorPath &path, GLfloat curveInverseScale); void clear(); @@ -119,3 +125,7 @@ private: inline void curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale); }; + +QT_END_NAMESPACE + +#endif diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp new file mode 100644 index 0000000..f64af85 --- /dev/null +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -0,0 +1,467 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglengineshadermanager_p.h" +#include "qglengineshadersource_p.h" + +#if defined(QT_DEBUG) +#include <QMetaEnum> +#endif + + +QT_BEGIN_NAMESPACE + +const char* QGLEngineShaderManager::qglEngineShaderSourceCode[] = { + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0 +}; + +QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context) + : ctx(context), + shaderProgNeedsChanging(true), + srcPixelType(Qt::NoBrush), + useGlobalOpacity(false), + maskType(NoMask), + useTextureCoords(false), + compositionMode(QPainter::CompositionMode_SourceOver), + simpleShaderProg(0), + currentShaderProg(0) +{ + memset(compiledShaders, 0, sizeof(compiledShaders)); + +/* + Rather than having the shader source array statically initialised, it is initialised + here instead. This is to allow new shader names to be inserted or existing names moved + around without having to change the order of the glsl strings. It is hoped this will + make future hard-to-find runtime bugs more obvious and generally give more solid code. +*/ + static bool qglEngineShaderSourceCodePopulated = false; + if (!qglEngineShaderSourceCodePopulated) { + + const char** code = qglEngineShaderSourceCode; // shortcut + + code[MainVertexShader] = qglslMainVertexShader; + code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader; + + code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader; + code[PositionWithPatternBrushVertexShader] = qglslPositionWithPatternBrushVertexShader; + code[PositionWithLinearGradientBrushVertexShader] = qglslPositionWithLinearGradientBrushVertexShader; + code[PositionWithConicalGradientBrushVertexShader] = qglslPositionWithConicalGradientBrushVertexShader; + code[PositionWithRadialGradientBrushVertexShader] = qglslPositionWithRadialGradientBrushVertexShader; + code[PositionWithTextureBrushVertexShader] = qglslPositionWithTextureBrushVertexShader; + code[AffinePositionWithPatternBrushVertexShader] = qglslAffinePositionWithPatternBrushVertexShader; + code[AffinePositionWithLinearGradientBrushVertexShader] = qglslAffinePositionWithLinearGradientBrushVertexShader; + code[AffinePositionWithConicalGradientBrushVertexShader] = qglslAffinePositionWithConicalGradientBrushVertexShader; + code[AffinePositionWithRadialGradientBrushVertexShader] = qglslAffinePositionWithRadialGradientBrushVertexShader; + code[AffinePositionWithTextureBrushVertexShader] = qglslAffinePositionWithTextureBrushVertexShader; + + code[MainFragmentShader_CMO] = qglslMainFragmentShader_CMO; + code[MainFragmentShader_CM] = qglslMainFragmentShader_CM; + code[MainFragmentShader_MO] = qglslMainFragmentShader_MO; + code[MainFragmentShader_M] = qglslMainFragmentShader_M; + code[MainFragmentShader_CO] = qglslMainFragmentShader_CO; + code[MainFragmentShader_C] = qglslMainFragmentShader_C; + code[MainFragmentShader_O] = qglslMainFragmentShader_O; + code[MainFragmentShader] = qglslMainFragmentShader; + + code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader; + code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader; + code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader; + code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader; + code[PatternBrushSrcFragmentShader] = qglslPatternBrushSrcFragmentShader; + code[LinearGradientBrushSrcFragmentShader] = qglslLinearGradientBrushSrcFragmentShader; + code[RadialGradientBrushSrcFragmentShader] = qglslRadialGradientBrushSrcFragmentShader; + code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader; + code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader; + + code[MaskFragmentShader] = qglslMaskFragmentShader; + code[RgbMaskFragmentShader] = ""; //### + code[RgbMaskWithGammaFragmentShader] = ""; //### + + code[MultiplyCompositionModeFragmentShader] = ""; //### + code[ScreenCompositionModeFragmentShader] = ""; //### + code[OverlayCompositionModeFragmentShader] = ""; //### + code[DarkenCompositionModeFragmentShader] = ""; //### + code[LightenCompositionModeFragmentShader] = ""; //### + code[ColorDodgeCompositionModeFragmentShader] = ""; //### + code[ColorBurnCompositionModeFragmentShader] = ""; //### + code[HardLightCompositionModeFragmentShader] = ""; //### + code[SoftLightCompositionModeFragmentShader] = ""; //### + code[DifferenceCompositionModeFragmentShader] = ""; //### + code[ExclusionCompositionModeFragmentShader] = ""; //### + +#if defined(QT_DEBUG) + // Check that all the elements have been filled: + for (int i = 0; i < TotalShaderCount; ++i) { + if (qglEngineShaderSourceCode[i] == 0) { + int enumIndex = staticMetaObject.indexOfEnumerator("ShaderName"); + QMetaEnum m = staticMetaObject.enumerator(enumIndex); + + qCritical() << "qglEngineShaderSourceCode: Source for" << m.valueToKey(i) + << "(shader" << i << ") missing!"; + } + } +#endif + qglEngineShaderSourceCodePopulated = true; + } + + // Compile up the simple shader: + simpleShaderProg = new QGLShaderProgram(ctx, this); + compileNamedShader(MainVertexShader, QGLShader::PartialVertexShader); + compileNamedShader(PositionOnlyVertexShader, QGLShader::PartialVertexShader); + compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader); + compileNamedShader(ShockingPinkSrcFragmentShader, QGLShader::PartialFragmentShader); + simpleShaderProg->addShader(compiledShaders[MainVertexShader]); + simpleShaderProg->addShader(compiledShaders[PositionOnlyVertexShader]); + simpleShaderProg->addShader(compiledShaders[MainFragmentShader]); + simpleShaderProg->addShader(compiledShaders[ShockingPinkSrcFragmentShader]); + simpleShaderProg->link(); + if (!simpleShaderProg->isLinked()) { + qCritical() << "Errors linking simple shader:" + << simpleShaderProg->log(); + } +} + +QGLEngineShaderManager::~QGLEngineShaderManager() +{ + //### +} + + + + + +void QGLEngineShaderManager::optimiseForBrushTransform(const QTransform &transform) +{ + Q_UNUSED(transform); // Currently ignored +} + +void QGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style) +{ + srcPixelType = style; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setSrcPixelType(PixelSrcType type) +{ + srcPixelType = type; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setTextureCoordsEnabled(bool enabled) +{ + useTextureCoords = enabled; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setUseGlobalOpacity(bool useOpacity) +{ + useGlobalOpacity = useOpacity; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setMaskType(MaskType type) +{ + maskType = type; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode) +{ + compositionMode = mode; + shaderProgNeedsChanging = true; //### +} + +QGLShaderProgram* QGLEngineShaderManager::currentProgram() +{ + return currentShaderProg; +} + +QGLShaderProgram* QGLEngineShaderManager::simpleProgram() +{ + return simpleShaderProg; +} + + + + +// Select & use the correct shader program using the current state. +// Returns true if program needed changing. +bool QGLEngineShaderManager::useCorrectShaderProg() +{ + if (!shaderProgNeedsChanging) + return false; + + QGLEngineShaderProg requiredProgram; + requiredProgram.program = 0; + + // Choose vertex shader main function + QGLEngineShaderManager::ShaderName mainVertexShaderName = InvalidShaderName; + if (useTextureCoords) + mainVertexShaderName = MainWithTexCoordsVertexShader; + else + mainVertexShaderName = MainVertexShader; + compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader); + requiredProgram.mainVertexShader = compiledShaders[mainVertexShaderName]; + + // Choose vertex shader shader position function (which typically also sets + // varyings) and the source pixel (srcPixel) fragment shader function: + QGLEngineShaderManager::ShaderName positionVertexShaderName = InvalidShaderName; + QGLEngineShaderManager::ShaderName srcPixelFragShaderName = InvalidShaderName; + bool isAffine = brushTransform.isAffine(); + if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) { + if (isAffine) + positionVertexShaderName = AffinePositionWithPatternBrushVertexShader; + else + positionVertexShaderName = PositionWithPatternBrushVertexShader; + + srcPixelFragShaderName = PatternBrushSrcFragmentShader; + } + else switch (srcPixelType) { + default: + case Qt::NoBrush: + qCritical("QGLEngineShaderManager::useCorrectShaderProg() - I'm scared, Qt::NoBrush style is set"); + break; + case QGLEngineShaderManager::ImageSrc: + srcPixelFragShaderName = ImageSrcFragmentShader; + positionVertexShaderName = PositionOnlyVertexShader; + break; + case QGLEngineShaderManager::NonPremultipliedImageSrc: + srcPixelFragShaderName = NonPremultipliedImageSrcFragmentShader; + positionVertexShaderName = PositionOnlyVertexShader; + break; + case Qt::SolidPattern: + srcPixelFragShaderName = SolidBrushSrcFragmentShader; + positionVertexShaderName = PositionOnlyVertexShader; + break; + case Qt::LinearGradientPattern: + srcPixelFragShaderName = LinearGradientBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithLinearGradientBrushVertexShader + : PositionWithLinearGradientBrushVertexShader; + break; + case Qt::ConicalGradientPattern: + srcPixelFragShaderName = ConicalGradientBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithConicalGradientBrushVertexShader + : PositionWithConicalGradientBrushVertexShader; + break; + case Qt::RadialGradientPattern: + srcPixelFragShaderName = RadialGradientBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithRadialGradientBrushVertexShader + : PositionWithRadialGradientBrushVertexShader; + break; + case Qt::TexturePattern: + srcPixelFragShaderName = TextureBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithTextureBrushVertexShader + : PositionWithTextureBrushVertexShader; + break; + }; + compileNamedShader(positionVertexShaderName, QGLShader::PartialVertexShader); + compileNamedShader(srcPixelFragShaderName, QGLShader::PartialFragmentShader); + requiredProgram.positionVertexShader = compiledShaders[positionVertexShaderName]; + requiredProgram.srcPixelFragShader = compiledShaders[srcPixelFragShaderName]; + + + const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus; + const bool hasMask = maskType != QGLEngineShaderManager::NoMask; + + // Choose fragment shader main function: + QGLEngineShaderManager::ShaderName mainFragShaderName; + + if (hasCompose && hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_CMO; + if (hasCompose && hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader_CM; + if (!hasCompose && hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_MO; + if (!hasCompose && hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader_M; + if (hasCompose && !hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_CO; + if (hasCompose && !hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader_C; + if (!hasCompose && !hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_O; + if (!hasCompose && !hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader; + + compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader); + requiredProgram.mainFragShader = compiledShaders[mainFragShaderName]; + + if (hasMask) { + QGLEngineShaderManager::ShaderName maskShaderName = QGLEngineShaderManager::InvalidShaderName; + if (maskType == PixelMask) + maskShaderName = MaskFragmentShader; + else if (maskType == SubPixelMask) + maskShaderName = RgbMaskFragmentShader; + else if (maskType == SubPixelWithGammaMask) + maskShaderName = RgbMaskWithGammaFragmentShader; + else + qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type"); + + compileNamedShader(maskShaderName, QGLShader::PartialFragmentShader); + requiredProgram.maskFragShader = compiledShaders[maskShaderName]; + } + else + requiredProgram.maskFragShader = 0; + + if (hasCompose) { + QGLEngineShaderManager::ShaderName compositionShaderName = QGLEngineShaderManager::InvalidShaderName; + switch (compositionMode) { + case QPainter::CompositionMode_Multiply: + compositionShaderName = MultiplyCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Screen: + compositionShaderName = ScreenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Overlay: + compositionShaderName = OverlayCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Darken: + compositionShaderName = DarkenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Lighten: + compositionShaderName = LightenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_ColorDodge: + compositionShaderName = ColorDodgeCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_ColorBurn: + compositionShaderName = ColorBurnCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_HardLight: + compositionShaderName = HardLightCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_SoftLight: + compositionShaderName = SoftLightCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Difference: + compositionShaderName = DifferenceCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Exclusion: + compositionShaderName = ExclusionCompositionModeFragmentShader; + break; + default: + qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode"); + } + compileNamedShader(compositionShaderName, QGLShader::PartialFragmentShader); + requiredProgram.compositionFragShader = compiledShaders[compositionShaderName]; + } + else + requiredProgram.compositionFragShader = 0; + + + // At this point, requiredProgram is fully populated so try to find the program in the cache + foreach (const QGLEngineShaderProg &prog, cachedPrograms) { + if ( (prog.mainVertexShader == requiredProgram.mainVertexShader) + && (prog.positionVertexShader == requiredProgram.positionVertexShader) + && (prog.mainFragShader == requiredProgram.mainFragShader) + && (prog.srcPixelFragShader == requiredProgram.srcPixelFragShader) + && (prog.compositionFragShader == requiredProgram.compositionFragShader) ) + { + currentShaderProg = prog.program; + currentShaderProg->enable(); + shaderProgNeedsChanging = false; + return true; + } + } + + // Shader program not found in cache, create it now. + requiredProgram.program = new QGLShaderProgram(ctx, this); + requiredProgram.program->addShader(requiredProgram.mainVertexShader); + requiredProgram.program->addShader(requiredProgram.positionVertexShader); + requiredProgram.program->addShader(requiredProgram.mainFragShader); + requiredProgram.program->addShader(requiredProgram.srcPixelFragShader); + requiredProgram.program->addShader(requiredProgram.maskFragShader); + requiredProgram.program->addShader(requiredProgram.compositionFragShader); + + // We have to bind the vertex attribute names before the program is linked: + requiredProgram.program->bindAttributeLocation("inputVertex", QT_VERTEX_COORDS_ATTR); + if (useTextureCoords) + requiredProgram.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + + requiredProgram.program->link(); + if (!requiredProgram.program->isLinked()) { + QString error; + qWarning() << "Shader program failed to link," +#if defined(QT_DEBUG) + << '\n' + << " Shaders Used:" << '\n' + << " mainVertexShader = " << requiredProgram.mainVertexShader->objectName() << '\n' + << " positionVertexShader = " << requiredProgram.positionVertexShader->objectName() << '\n' + << " mainFragShader = " << requiredProgram.mainFragShader->objectName() << '\n' + << " srcPixelFragShader = " << requiredProgram.srcPixelFragShader->objectName() << '\n' + << " maskFragShader = " << requiredProgram.maskFragShader->objectName() << '\n' + << " compositionFragShader = "<< requiredProgram.compositionFragShader->objectName() << '\n' +#endif + << " Error Log:" << '\n' + << " " << requiredProgram.program->log(); + qWarning() << error; + } + else { + cachedPrograms.append(requiredProgram); + currentShaderProg = requiredProgram.program; + currentShaderProg->enable(); + } + shaderProgNeedsChanging = false; + return true; +} + +void QGLEngineShaderManager::compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type) +{ + if (compiledShaders[name]) + return; + + QGLShader *newShader = new QGLShader(type, ctx, this); + newShader->setSourceCode(qglEngineShaderSourceCode[name]); + // newShader->compile(); ### does not exist? + +#if defined(QT_DEBUG) + // Name the shader for easier debugging + QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName")); + newShader->setObjectName(QLatin1String(m.valueToKey(name))); +#endif + + compiledShaders[name] = newShader; +} + +QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h new file mode 100644 index 0000000..b8b2745 --- /dev/null +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -0,0 +1,385 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +/* + VERTEX SHADERS + ============== + + Vertex shaders are specified as multiple (partial) shaders. On desktop, + this works fine. On ES, QGLShader & QGLShaderProgram will make partial + shaders work by concatenating the source in each QGLShader and compiling + it as a single shader. This is abstracted nicely by QGLShaderProgram and + the GL2 engine doesn't need to worry about it. + + Generally, there's two vertex shader objects. The position shaders are + the ones which set gl_Position. There's also two "main" vertex shaders, + one which just calls the position shader and another which also passes + through some texture coordinates from a vertex attribute array to a + varying. These texture coordinates are used for mask position in text + rendering and for the source coordinates in drawImage/drawPixmap. There's + also a "Simple" vertex shader for rendering a solid colour (used to render + into the stencil buffer where the actual colour value is discarded). + + The position shaders for brushes look scary. This is because many of the + calculations which logically belong in the fragment shader have been moved + into the vertex shader to improve performance. This is why the position + calculation is in a seperate shader. Not only does it calculate the + position, but it also calculates some data to be passed to the fragment + shader as a varying. It is optimal to move as much of the calculation as + possible into the vertex shader as this is executed less often. + + The varyings passed to the fragment shaders are interpolated (which is + cheap). Unfortunately, GL will apply perspective correction to the + interpolation calusing errors. To get around this, the vertex shader must + apply perspective correction itself and set the w-value of gl_Position to + zero. That way, GL will be tricked into thinking it doesn't need to apply a + perspective correction and use linear interpolation instead (which is what + we want). Of course, if the brush transform is affeine, no perspective + correction is needed and a simpler vertex shader can be used instead. + + So there are the following "main" vertex shaders: + qglslMainVertexShader + qglslMainWithTexCoordsVertexShader + + And the the following position vertex shaders: + qglslPositionOnlyVertexShader + qglslPositionWithTextureBrushVertexShader + qglslPositionWithPatternBrushVertexShader + qglslPositionWithLinearGradientBrushVertexShader + qglslPositionWithRadialGradientBrushVertexShader + qglslPositionWithConicalGradientBrushVertexShader + qglslAffinePositionWithTextureBrushVertexShader + qglslAffinePositionWithPatternBrushVertexShader + qglslAffinePositionWithLinearGradientBrushVertexShader + qglslAffinePositionWithRadialGradientBrushVertexShader + qglslAffinePositionWithConicalGradientBrushVertexShader + + Leading to 23 possible vertex shaders + + + FRAGMENT SHADERS + ================ + + Fragment shaders are also specified as multiple (partial) shaders. The + different fragment shaders represent the different stages in Qt's fragment + pipeline. There are 1-3 stages in this pipeline: First stage is to get the + fragment's colour value. The next stage is to get the fragment's mask value + (coverage value for anti-aliasing) and the final stage is to blend the + incoming fragment with the background (for composition modes not supported + by GL). + + Of these, the first stage will always be present. If Qt doesn't need to + apply anti-aliasing (because it's off or handled by multisampling) then + the coverage value doesn't need to be applied. (Note: There are two types + of mask, one for regular anti-aliasing and one for sub-pixel anti- + aliasing.) If the composition mode is one which GL supports natively then + the blending stage doesn't need to be applied. + + As eash stage can have multiple implementations, they are abstracted as + GLSL function calls with the following signatures: + + Brushes & image drawing are implementations of "qcolorp vec4 srcPixel()": + qglslImageSrcFragShader + qglslNonPremultipliedImageSrcFragShader + qglslSolidBrushSrcFragShader + qglslTextureBrushSrcFragShader + qglslPatternBrushSrcFragShader + qglslLinearGradientBrushSrcFragShader + qglslRadialGradientBrushSrcFragShader + qglslConicalGradientBrushSrcFragShader + NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied + + Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)": + qglslMaskFragmentShader + qglslRgbMaskFragmentShader + qglslRgbMaskWithGammaFragmentShader + + Composition modes are "qcolorp vec4 compose(qcolorp vec4 src)": + qglslColorBurnCompositionModeFragmentShader + qglslColorDodgeCompositionModeFragmentShader + qglslDarkenCompositionModeFragmentShader + qglslDifferenceCompositionModeFragmentShader + qglslExclusionCompositionModeFragmentShader + qglslHardLightCompositionModeFragmentShader + qglslLightenCompositionModeFragmentShader + qglslMultiplyCompositionModeFragmentShader + qglslOverlayCompositionModeFragmentShader + qglslScreenCompositionModeFragmentShader + qglslSoftLightCompositionModeFragmentShader + + + Note: In the future, some GLSL compilers will support an extension allowing + a new 'color' precision specifier. To support this, qcolorp is used for + all color components so it can be defined to colorp or lowp depending upon + the implementation. + + So there are differnt frament shader main functions, depending on the + number & type of pipelines the fragment needs to go through. + + The choice of which main() fragment shader string to use depends on: + - Use of global opacity + - Brush style (some brushes apply opacity themselves) + - Use & type of mask (TODO: Need to support high quality anti-aliasing & text) + - Use of non-GL Composition mode + + Leading to the following fragment shader main functions: + gl_FragColor = compose(applyMask(srcPixel()*globalOpacity)); + gl_FragColor = compose(applyMask(srcPixel())); + gl_FragColor = applyMask(srcPixel()*globalOpacity); + gl_FragColor = applyMask(srcPixel()); + gl_FragColor = compose(srcPixel()*globalOpacity); + gl_FragColor = compose(srcPixel()); + gl_FragColor = srcPixel()*globalOpacity; + gl_FragColor = srcPixel(); + + Called: + qglslMainFragmentShader_CMO + qglslMainFragmentShader_CM + qglslMainFragmentShader_MO + qglslMainFragmentShader_M + qglslMainFragmentShader_CO + qglslMainFragmentShader_C + qglslMainFragmentShader_O + qglslMainFragmentShader + + Where: + M = Mask + C = Composition + O = Global Opacity + + + CUSTOM SHADER CODE (idea, depricated) + ================== + + The use of custom shader code is supported by the engine for drawImage and + drawPixmap calls. This is implemented via hooks in the fragment pipeline. + The custom shader is passed to the engine as a partial fragment shader + (QGLCustomizedShader). The shader will implement a pre-defined method name + which Qt's fragment pipeline will call. There are two different hooks which + can be implemented as custom shader code: + + mediump vec4 customShader(sampler2d src, vec2 srcCoords) + mediump vec4 customShaderWithDest(sampler2d dest, sampler2d src, vec2 srcCoords) + +*/ + +#ifndef QGLENGINE_SHADER_MANAGER_H +#define QGLENGINE_SHADER_MANAGER_H + +#include <QGLShader> +#include <QGLShaderProgram> +#include <QPainter> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(OpenGL) + + +struct QGLEngineShaderProg +{ + QGLShader* mainVertexShader; + QGLShader* positionVertexShader; + QGLShader* mainFragShader; + QGLShader* srcPixelFragShader; + QGLShader* maskFragShader; // Can be null for no mask + QGLShader* compositionFragShader; // Can be null for GL-handled mode + QGLShaderProgram* program; +}; + +/* +struct QGLEngineCachedShaderProg +{ + QGLEngineCachedShaderProg(QGLEngineShaderManager::ShaderName vertexMain, + QGLEngineShaderManager::ShaderName vertexPosition, + QGLEngineShaderManager::ShaderName fragMain, + QGLEngineShaderManager::ShaderName pixelSrc, + QGLEngineShaderManager::ShaderName mask, + QGLEngineShaderManager::ShaderName composition); + + int cacheKey; + QGLShaderProgram* program; +} +*/ + +static const GLuint QT_VERTEX_COORDS_ATTR = 0; +static const GLuint QT_TEXTURE_COORDS_ATTR = 1; + +class QGLEngineShaderManager : public QObject +{ + Q_OBJECT; +public: + QGLEngineShaderManager(QGLContext* context); + ~QGLEngineShaderManager(); + + enum MaskType {NoMask, PixelMask, SubPixelMask, SubPixelWithGammaMask}; + enum PixelSrcType { + ImageSrc = Qt::TexturePattern+1, + NonPremultipliedImageSrc = Qt::TexturePattern+2 + }; + + // There are optimisations we can do, depending on the brush transform: + // 1) May not have to apply perspective-correction + // 2) Can use lower precision for matrix + void optimiseForBrushTransform(const QTransform &transform); + void setSrcPixelType(Qt::BrushStyle); + void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images + void setTextureCoordsEnabled(bool); // For images & text glyphs + void setUseGlobalOpacity(bool); + void setMaskType(MaskType); + void setCompositionMode(QPainter::CompositionMode); + + bool useCorrectShaderProg(); // returns true if the shader program needed to be changed + + QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen + QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers + + enum ShaderName { + MainVertexShader, + MainWithTexCoordsVertexShader, + + PositionOnlyVertexShader, + PositionWithPatternBrushVertexShader, + PositionWithLinearGradientBrushVertexShader, + PositionWithConicalGradientBrushVertexShader, + PositionWithRadialGradientBrushVertexShader, + PositionWithTextureBrushVertexShader, + AffinePositionWithPatternBrushVertexShader, + AffinePositionWithLinearGradientBrushVertexShader, + AffinePositionWithConicalGradientBrushVertexShader, + AffinePositionWithRadialGradientBrushVertexShader, + AffinePositionWithTextureBrushVertexShader, + + MainFragmentShader_CMO, + MainFragmentShader_CM, + MainFragmentShader_MO, + MainFragmentShader_M, + MainFragmentShader_CO, + MainFragmentShader_C, + MainFragmentShader_O, + MainFragmentShader, + + ImageSrcFragmentShader, + NonPremultipliedImageSrcFragmentShader, + SolidBrushSrcFragmentShader, + TextureBrushSrcFragmentShader, + PatternBrushSrcFragmentShader, + LinearGradientBrushSrcFragmentShader, + RadialGradientBrushSrcFragmentShader, + ConicalGradientBrushSrcFragmentShader, + ShockingPinkSrcFragmentShader, + + MaskFragmentShader, + RgbMaskFragmentShader, + RgbMaskWithGammaFragmentShader, + + MultiplyCompositionModeFragmentShader, + ScreenCompositionModeFragmentShader, + OverlayCompositionModeFragmentShader, + DarkenCompositionModeFragmentShader, + LightenCompositionModeFragmentShader, + ColorDodgeCompositionModeFragmentShader, + ColorBurnCompositionModeFragmentShader, + HardLightCompositionModeFragmentShader, + SoftLightCompositionModeFragmentShader, + DifferenceCompositionModeFragmentShader, + ExclusionCompositionModeFragmentShader, + + TotalShaderCount, InvalidShaderName + }; + +/* + // These allow the ShaderName enum to be used as a cache key + const int mainVertexOffset = 0; + const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader; + const int mainFragOffset = (1<<6) - MainFragmentShader_CMO; + const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader; + const int maskOffset = (1<<14) - NoMaskShader; + const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader; +*/ + +#if defined (QT_DEBUG) + Q_ENUMS(ShaderName); +#endif + + +private: + QGLContext* ctx; + bool shaderProgNeedsChanging; + + // Current state variables which influence the choice of shader: + QTransform brushTransform; + int srcPixelType; + bool useGlobalOpacity; + MaskType maskType; + bool useTextureCoords; + QPainter::CompositionMode compositionMode; + + QGLShaderProgram* simpleShaderProg; + QGLShaderProgram* currentShaderProg; + + // TODO: Possibly convert to a LUT + QList<QGLEngineShaderProg> cachedPrograms; + + QGLShader* compiledShaders[TotalShaderCount]; + + void compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type); + + static const char* qglEngineShaderSourceCode[TotalShaderCount]; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QGLENGINE_SHADER_MANAGER_H diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h new file mode 100644 index 0000000..fdbba72 --- /dev/null +++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h @@ -0,0 +1,383 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QGL_ENGINE_SHADER_SOURCE_H +#define QGL_ENGINE_SHADER_SOURCE_H + +#include "qglengineshadermanager_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(OpenGL) + + +static const char* const qglslMainVertexShader = "\ + void setPosition();\ + void main(void)\ + {\ + setPosition();\ + }"; + +static const char* const qglslMainWithTexCoordsVertexShader = "\ + attribute lowp vec2 textureCoordArray; \ + varying lowp vec2 textureCoords; \ + void setPosition();\ + void main(void) \ + {\ + setPosition();\ + textureCoords = textureCoordArray; \ + }"; + + +static const char* const qglslPositionOnlyVertexShader = "\ + attribute highp vec4 vertexCoordsArray;\ + uniform highp mat4 pmvMatrix;\ + void setPosition(void)\ + {\ + gl_Position = pmvMatrix * vertexCoordsArray;\ + }"; + + +// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125 +static const char* const qglslPositionWithPatternBrushVertexShader = "\ + attribute highp vec4 vertexCoordsArray; \ + uniform highp mat4 pmvMatrix; \ + uniform mediump vec2 halfViewportSize; \ + uniform mediump vec2 invertedTextureSize; \ + uniform mediump mat3 brushTransform; \ + varying mediump vec2 patternTexCoords; \ + void setPosition(void) { \ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.xy = gl_Position.xy / gl_Position.w; \ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ + gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ + gl_Position.w = invertedHTexCoordsZ; \ + patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \ + patternTexCoords.y = -patternTexCoords.y; \ + }"; + +static const char* const qglslAffinePositionWithPatternBrushVertexShader + = qglslPositionWithPatternBrushVertexShader; + +static const char* const qglslPatternBrushSrcFragmentShader = "\ + uniform sampler2D brushTexture;\ + uniform lowp vec4 patternColor; \ + varying mediump vec2 patternTexCoords;\ + lowp vec4 srcPixel() { \ + return patternColor * texture2D(brushTexture, patternTexCoords).r; \ + }\n"; + + +// Linear Gradient Brush +static const char* const qglslPositionWithLinearGradientBrushVertexShader = "\ + attribute highp vec4 vertexCoordsArray; \ + uniform highp mat4 pmvMatrix; \ + uniform mediump vec2 halfViewportSize; \ + uniform highp vec3 linearData; \ + uniform highp mat3 brushTransform; \ + varying mediump float index ; \ + void setPosition() { \ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.xy = gl_Position.xy / gl_Position.w; \ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ + gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ + gl_Position.w = invertedHTexCoordsZ; \ + index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \ + }"; + +static const char* const qglslAffinePositionWithLinearGradientBrushVertexShader + = qglslPositionWithLinearGradientBrushVertexShader; + +static const char* const qglslLinearGradientBrushSrcFragmentShader = "\ + uniform sampler2D brushTexture; \ + varying mediump float index; \ + lowp vec4 srcPixel() { \ + mediump vec2 val = vec2(index, 0.5); \ + return texture2D(brushTexture, val); \ + }\n"; + + +// Conical Gradient Brush +static const char* const qglslPositionWithConicalGradientBrushVertexShader = "\ + attribute highp vec4 vertexCoordsArray;\ + uniform highp mat4 pmvMatrix;\ + uniform mediump vec2 halfViewportSize; \ + uniform highp mat3 brushTransform; \ + varying highp vec2 A; \ + void setPosition(void)\ + {\ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.xy = gl_Position.xy / gl_Position.w; \ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ + gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ + gl_Position.w = invertedHTexCoordsZ; \ + A = hTexCoords.xy * invertedHTexCoordsZ; \ + }"; + +static const char* const qglslAffinePositionWithConicalGradientBrushVertexShader + = qglslPositionWithConicalGradientBrushVertexShader; + +static const char* const qglslConicalGradientBrushSrcFragmentShader = "\n\ + #define INVERSE_2PI 0.1591549430918953358 \n\ + uniform sampler2D brushTexture; \n\ + uniform mediump float angle; \ + varying highp vec2 A; \ + lowp vec4 srcPixel() { \ + highp float t; \ + if (abs(A.y) == abs(A.x)) \ + t = (atan(-A.y + 0.002, A.x) + angle) * INVERSE_2PI; \ + else \ + t = (atan(-A.y, A.x) + angle) * INVERSE_2PI; \ + return texture2D(brushTexture, vec2(t - floor(t), 0.5)); \ + }"; + + +// Radial Gradient Brush +static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\ + attribute highp vec4 vertexCoordsArray;\ + uniform highp mat4 pmvMatrix;\ + uniform mediump vec2 halfViewportSize; \ + uniform highp mat3 brushTransform; \ + uniform highp vec2 fmp; \ + varying highp float b; \ + varying highp vec2 A; \ + void setPosition(void) \ + {\ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.xy = gl_Position.xy / gl_Position.w; \ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ + gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ + gl_Position.w = invertedHTexCoordsZ; \ + A = hTexCoords.xy * invertedHTexCoordsZ; \ + b = 2.0 * dot(A, fmp); \ + }"; + +static const char* const qglslAffinePositionWithRadialGradientBrushVertexShader + = qglslPositionWithRadialGradientBrushVertexShader; + +static const char* const qglslRadialGradientBrushSrcFragmentShader = "\ + uniform sampler2D brushTexture; \ + uniform highp float fmp2_m_radius2; \ + uniform highp float inverse_2_fmp2_m_radius2; \ + varying highp float b; \ + varying highp vec2 A; \ + lowp vec4 srcPixel() { \ + highp float c = -dot(A, A); \ + highp vec2 val = vec2((-b + sqrt(b*b - 4.0*fmp2_m_radius2*c)) * inverse_2_fmp2_m_radius2, 0.5); \ + return texture2D(brushTexture, val); \ + }"; + + +// Texture Brush +static const char* const qglslPositionWithTextureBrushVertexShader = "\ + attribute highp vec4 vertexCoordsArray; \ + uniform highp mat4 pmvMatrix; \ + uniform mediump vec2 halfViewportSize; \ + uniform mediump vec2 invertedTextureSize; \ + uniform mediump mat3 brushTransform; \ + varying mediump vec2 brushTextureCoords; \ + void setPosition(void) { \ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.xy = gl_Position.xy / gl_Position.w; \ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ + gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ + gl_Position.w = invertedHTexCoordsZ; \ + brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \ + brushTextureCoords.y = -brushTextureCoords.y; \ + }"; + +static const char* const qglslAffinePositionWithTextureBrushVertexShader + = qglslPositionWithTextureBrushVertexShader; + +static const char* const qglslTextureBrushSrcFragmentShader = "\ + varying mediump vec2 brushTextureCoords; \ + uniform sampler2D brushTexture; \ + lowp vec4 srcPixel() { \ + return texture2D(brushTexture, brushTextureCoords); \ + }"; + + +// Solid Fill Brush +static const char* const qglslSolidBrushSrcFragmentShader = "\ + uniform lowp vec4 fragmentColor; \ + lowp vec4 srcPixel() { \ + return fragmentColor; \ + }"; + +static const char* const qglslImageSrcFragmentShader = "\ + varying highp vec2 textureCoords; \ + uniform sampler2D imageTexture; \ + lowp vec4 srcPixel() { \ + return texture2D(imageTexture, textureCoords); \ + }"; + +static const char* const qglslNonPremultipliedImageSrcFragmentShader = "\ + varying highp vec2 textureCoords; \ + uniform sampler2D imageTexture; \ + lowp vec4 srcPixel() { \ + lowp vec4 sample = texture2D(imageTexture, textureCoords); \ + sample.rgb = sample.rgb * sample.a; \ + return sample; \ + }"; + +static const char* const qglslShockingPinkSrcFragmentShader = "\ + lowp vec4 srcPixel() { \ + return vec4(0.98, 0.06, 0.75, 1.0); \ + }"; + + +static const char* const qglslMainFragmentShader_CMO = "\ + uniform lowp float globalOpacity; \ + lowp vec4 srcPixel(); \ + lowp vec4 applyMask(lowp vec4); \ + lowp vec4 compose(lowp vec4); \ + void main() { \ + gl_FragColor = applyMask(compose(srcPixel()*globalOpacity))); \ + }"; + +static const char* const qglslMainFragmentShader_CM = "\ + lowp vec4 srcPixel(); \ + lowp vec4 applyMask(lowp vec4); \ + lowp vec4 compose(lowp vec4); \ + void main() { \ + gl_FragColor = applyMask(compose(srcPixel())); \ + }"; + +static const char* const qglslMainFragmentShader_MO = "\ + uniform lowp float globalOpacity; \ + lowp vec4 srcPixel(); \ + lowp vec4 applyMask(lowp vec4); \ + void main() { \ + gl_FragColor = applyMask(srcPixel()*globalOpacity); \ + }"; + +static const char* const qglslMainFragmentShader_M = "\ + lowp vec4 srcPixel(); \ + lowp vec4 applyMask(lowp vec4); \ + void main() { \ + gl_FragColor = applyMask(srcPixel()); \ + }"; + +static const char* const qglslMainFragmentShader_CO = "\ + uniform lowp float globalOpacity; \ + lowp vec4 srcPixel(); \ + lowp vec4 compose(lowp vec4); \ + void main() { \ + gl_FragColor = compose(srcPixel()*globalOpacity); \ + }"; + +static const char* const qglslMainFragmentShader_C = "\ + lowp vec4 srcPixel(); \ + lowp vec4 compose(lowp vec4); \ + void main() { \ + gl_FragColor = compose(srcPixel()); \ + }"; + +static const char* const qglslMainFragmentShader_O = "\ + uniform lowp float globalOpacity; \ + lowp vec4 srcPixel(); \ + void main() { \ + gl_FragColor = srcPixel()*globalOpacity; \ + }"; + +static const char* const qglslMainFragmentShader = "\ + lowp vec4 srcPixel(); \ + void main() { \ + gl_FragColor = srcPixel(); \ + }"; + +static const char* const qglslMaskFragmentShader = "\ + varying highp vec2 textureCoords;\ + uniform sampler2D maskTexture;\ + lowp vec4 applyMask(lowp vec4 src) \ + {\ + lowp vec4 mask = texture2D(maskTexture, textureCoords); \ + return src * mask.r; \ + }"; + +/* + Left to implement: + RgbMaskFragmentShader, + RgbMaskWithGammaFragmentShader, + + MultiplyCompositionModeFragmentShader, + ScreenCompositionModeFragmentShader, + OverlayCompositionModeFragmentShader, + DarkenCompositionModeFragmentShader, + LightenCompositionModeFragmentShader, + ColorDodgeCompositionModeFragmentShader, + ColorBurnCompositionModeFragmentShader, + HardLightCompositionModeFragmentShader, + SoftLightCompositionModeFragmentShader, + DifferenceCompositionModeFragmentShader, + ExclusionCompositionModeFragmentShader, +*/ + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // GLGC_SHADER_SOURCE_H diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp index b4591b2..f1a8850 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache.cpp +++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp @@ -44,7 +44,9 @@ #include "qglgradientcache_p.h" -void QGLGradientCache::cleanCache() { +QT_BEGIN_NAMESPACE + +void QGL2GradientCache::cleanCache() { QGLGradientColorTableHash::const_iterator it = cache.constBegin(); for (; it != cache.constEnd(); ++it) { const CacheInfo &cache_info = it.value(); @@ -53,7 +55,7 @@ void QGLGradientCache::cleanCache() { cache.clear(); } -GLuint QGLGradientCache::getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx) +GLuint QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx) { if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx)) cleanCache(); @@ -84,7 +86,7 @@ GLuint QGLGradientCache::getBuffer(const QGradient &gradient, qreal opacity, con } -GLuint QGLGradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) +GLuint QGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) { if (cache.size() == maxCacheSize()) { int elem_to_remove = qrand() % maxCacheSize(); @@ -109,34 +111,31 @@ GLuint QGLGradientCache::addCacheElement(quint64 hash_val, const QGradient &grad } -// GL's expects pixels in RGBA, bin-endian (ABGR on x86). -// Qt stores in ARGB using whatever byte-order the mancine uses. +// GL's expects pixels in RGBA (when using GL_RGBA), bin-endian (ABGR on x86). +// Qt always stores in ARGB reguardless of the byte-order the mancine uses. static inline uint qtToGlColor(uint c) { uint o; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - o = c & 0xFF00FF00; // alpha & green already in the right place - o |= (c >> 16) & 0x000000FF; // red - o |= (c << 16) & 0x00FF0000; // blue - + o = (c & 0xff00ff00) // alpha & green already in the right place + | ((c >> 16) & 0x000000ff) // red + | ((c << 16) & 0x00ff0000); // blue #else //Q_BIG_ENDIAN - o = c & 0x00FF00FF; // alpha & green already in the right place - o |= (c << 16) & 0xFF000000; // red - o |= (c >> 16) & 0x0000FF00; // blue -#error big endian not tested with QGLGraphicsContext + o = (c << 8) + | ((c >> 24) & 0x000000ff); #endif // Q_BYTE_ORDER return o; } //TODO: Let GL generate the texture using an FBO -void QGLGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const +void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const { int pos = 0; QGradientStops s = gradient.stops(); QVector<uint> colors(s.size()); for (int i = 0; i < s.size(); ++i) - colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB + colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB (on little-endian AND on big-endian) bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); @@ -183,3 +182,5 @@ void QGLGradientCache::generateGradientColorTable(const QGradient& gradient, uin // Make sure the last color stop is represented at the end of the table colorTable[size-1] = last_color; } + +QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h index 346ea13..9bf58c7 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache_p.h +++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h @@ -54,7 +54,9 @@ #include <QObject> #include <QtOpenGL> -class QGLGradientCache : public QObject +QT_BEGIN_NAMESPACE + +class QGL2GradientCache : public QObject { Q_OBJECT struct CacheInfo @@ -71,7 +73,7 @@ class QGLGradientCache : public QObject typedef QMultiHash<quint64, CacheInfo> QGLGradientColorTableHash; public: - QGLGradientCache() : QObject(), buffer_ctx(0) + QGL2GradientCache() : QObject(), buffer_ctx(0) { /* connect(QGLSignalProxy::instance(), @@ -104,5 +106,5 @@ public slots: } }; - +QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qglpexshadermanager.cpp b/src/opengl/gl2paintengineex/qglpexshadermanager.cpp deleted file mode 100644 index e460e08..0000000 --- a/src/opengl/gl2paintengineex/qglpexshadermanager.cpp +++ /dev/null @@ -1,450 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglpexshadermanager_p.h" - -#include "glgc_shader_source.h" - -QGLPEXShaderManager::QGLPEXShaderManager(const QGLContext* context) -{ - ctx = const_cast<QGLContext*>(context); - - defaultVertexShader= new QGLShader(QGLShader::VertexShader, context); - defaultVertexShader->addSource(QLatin1String(qglslDefaultVertexShader)); - if (!defaultVertexShader->compile()) - qWarning() << "Default vertex shader failed to compile: " << defaultVertexShader->log(); - - noBrushShader = new QGLShader(QGLShader::FragmentShader, context); - noBrushShader->addSource(QLatin1String(qglslFragmentShaderMain)); - noBrushShader->addSource(QLatin1String(qglslNoBrushFragmentShader)); - if (!noBrushShader->compile()) - qWarning() << "No brush shader failed to compile:" << noBrushShader->log(); - - - // Create a program for noBrush: - QGLShaderProgram* noBrushProg = new QGLShaderProgram(ctx); - noBrushProg->addShader(defaultVertexShader); - noBrushProg->addShader(noBrushShader); - if (!noBrushProg->link()) - qWarning() << "NoBrush shader program failed to link:" << noBrushProg->log(); - - // Add noBrush Program to cache: - QGLCachedShaderProg cachedProg; - cachedProg.vertexShader = defaultVertexShader; - cachedProg.brushShader = noBrushShader; - cachedProg.compositionShader = 0; - cachedProg.shader = noBrushProg; - cachedPrograms.append(cachedProg); - - - // Set state - useGlobalOpacity = true; - currentBrushStyle = Qt::NoBrush; - currentTransformType = FullTransform; - shaderProgNeedsChanging = false; - activeProgram = noBrushProg; - - solidBrushShader = 0; - - conicalBrushVertexShader = 0; - conicalBrushFragmentShader = 0; - - radialBrushVertexShader = 0; - radialBrushFragmentShader = 0; - - linearBrushVertexShader = 0; - linearBrushFragmentShader = 0; - - patternBrushVertexShader = 0; - patternBrushFragmentShader = 0; - - textureBrushFragmentShader = 0; - textureBrushVertexShader = 0; - - simpleFragmentShader = 0; - simpleShaderProgram = 0; - - imageVertexShader = 0; - imageFragmentShader = 0; - imageShaderProgram = 0; - - textVertexShader = 0; - textFragmentShader = 0; - textShaderProgram = 0; -} - -QGLPEXShaderManager::~QGLPEXShaderManager() -{ - delete defaultVertexShader; - delete imageVertexShader; - delete imageFragmentShader; - delete imageShaderProgram; - delete textVertexShader; - delete textFragmentShader; - delete textShaderProgram; - delete noBrushShader; - delete solidBrushShader; - - delete conicalBrushVertexShader; - delete conicalBrushFragmentShader; - - delete radialBrushVertexShader; - delete radialBrushFragmentShader; - - delete linearBrushFragmentShader; - delete linearBrushVertexShader; - - delete patternBrushFragmentShader; - delete patternBrushVertexShader; - - delete textureBrushFragmentShader; - delete textureBrushVertexShader; - - delete simpleFragmentShader; - delete simpleShaderProgram; -} - -void QGLPEXShaderManager::setUseGlobalOpacity(bool value) -{ - if (value != useGlobalOpacity) - shaderProgNeedsChanging = true; - - useGlobalOpacity = value; -} - -void QGLPEXShaderManager::setBrushStyle(Qt::BrushStyle style) -{ - if (currentBrushStyle != style) - shaderProgNeedsChanging = true; - - currentBrushStyle = style; -} - -void QGLPEXShaderManager::setAffineOnlyBrushTransform(bool value) -{ - Q_UNUSED(value); - // TODO -} - -bool QGLPEXShaderManager::useCorrectShaderProg() -{ - if (!shaderProgNeedsChanging) { - activeProgram->use(); - return false; - } - - const char* fragmentShaderMainSrc = qglslFragmentShaderMain; - QGLShader* vertexShader = defaultVertexShader; - QGLShader* fragmentShader = noBrushShader; - - // Make sure we compile up the correct brush shader - switch (currentBrushStyle) { - case Qt::NoBrush: - break; - case Qt::SolidPattern: - if (!solidBrushShader) { - qDebug("Compiling qglslSolidBrushFragmentShader"); - solidBrushShader = new QGLShader(QGLShader::FragmentShader, ctx); - solidBrushShader->addSource(QLatin1String(qglslNoOpacityFragmentShaderMain)); - solidBrushShader->addSource(QLatin1String(qglslSolidBrushFragmentShader)); - if (!solidBrushShader->compile()) - qWarning() << "qglslSolidBrush failed to compile:" << solidBrushShader->log(); - } - fragmentShader = solidBrushShader; - break; - case Qt::TexturePattern: - if (!textureBrushVertexShader) { - qDebug("Compiling qglslTextureBrushVertexShader"); - textureBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - textureBrushVertexShader->addSource(QLatin1String(qglslTextureBrushVertexShader)); - if (!textureBrushVertexShader->compile()) { - qWarning() << "qglslTextureBrushVertexShader failed to compile: " - << textureBrushVertexShader->log(); - } - } - vertexShader = textureBrushVertexShader; - - if (!textureBrushFragmentShader) { - qDebug("Compiling qglslTextureBrushFragmentShader"); - textureBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - textureBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); - textureBrushFragmentShader->addSource(QLatin1String(qglslTextureBrushFragmentShader)); - if (!textureBrushFragmentShader->compile()) { - qWarning() << "qglslTextureBrushFragmentShader failed to compile:" - << textureBrushFragmentShader->log(); - } - } - fragmentShader = textureBrushFragmentShader; - break; - case Qt::LinearGradientPattern: - if (!linearBrushVertexShader) { - qDebug("Compiling qglslLinearGradientBrushVertexShader"); - linearBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - linearBrushVertexShader->addSource(QLatin1String(qglslLinearGradientBrushVertexShader)); - if (!linearBrushVertexShader->compile()) { - qWarning() << "qglslLinearGradientBrushVertexShader failed to compile: " - << linearBrushVertexShader->log(); - } - } - vertexShader = linearBrushVertexShader; - - if (!linearBrushFragmentShader) { - qDebug("Compiling qglslLinearGradientBrushFragmentShader"); - linearBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - linearBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); - linearBrushFragmentShader->addSource(QLatin1String(qglslLinearGradientBrushFragmentShader)); - if (!linearBrushFragmentShader->compile()) { - qWarning() << "qglslLinearGradientBrushFragmentShader failed to compile:" - << linearBrushFragmentShader->log(); - } - } - fragmentShader = linearBrushFragmentShader; - break; - case Qt::RadialGradientPattern: - if (!radialBrushVertexShader) { - qDebug("Compiling qglslRadialGradientBrushVertexShader"); - radialBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - radialBrushVertexShader->addSource(QLatin1String(qglslRadialGradientBrushVertexShader)); - if (!radialBrushVertexShader->compile()) { - qWarning() << "qglslRadialGradientBrushVertexShader failed to compile: " - << radialBrushVertexShader->log(); - } - } - vertexShader = radialBrushVertexShader; - - if (!radialBrushFragmentShader) { - qDebug("Compiling qglslRadialGradientBrushFragmentShader"); - radialBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - radialBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); - radialBrushFragmentShader->addSource(QLatin1String(qglslRadialGradientBrushFragmentShader)); - if (!radialBrushFragmentShader->compile()) { - qWarning() << "qglslRadialGradientBrushFragmentShader failed to compile:" - << radialBrushFragmentShader->log(); - } - } - fragmentShader = radialBrushFragmentShader; - break; - case Qt::ConicalGradientPattern: - // FIXME: We currently use the same vertex shader as radial brush - if (!conicalBrushVertexShader) { - qDebug("Compiling qglslConicalGradientBrushVertexShader"); - conicalBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - conicalBrushVertexShader->addSource(QLatin1String(qglslConicalGradientBrushVertexShader)); - if (!conicalBrushVertexShader->compile()) { - qWarning() << "qglslConicalGradientBrushVertexShader failed to compile: " - << conicalBrushVertexShader->log(); - } - } - vertexShader = conicalBrushVertexShader; - - if (!conicalBrushFragmentShader) { - qDebug("Compiling qglslConicalGradientBrushFragmentShader"); - conicalBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - conicalBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); - conicalBrushFragmentShader->addSource(QLatin1String(qglslConicalGradientBrushFragmentShader)); - if (!conicalBrushFragmentShader->compile()) { - qWarning() << "qglslConicalGradientBrushFragmentShader failed to compile:" - << conicalBrushFragmentShader->log(); - } - } - fragmentShader = conicalBrushFragmentShader; - break; - case Qt::Dense1Pattern: - case Qt::Dense2Pattern: - case Qt::Dense3Pattern: - case Qt::Dense4Pattern: - case Qt::Dense5Pattern: - case Qt::Dense6Pattern: - case Qt::Dense7Pattern: - case Qt::HorPattern: - case Qt::VerPattern: - case Qt::CrossPattern: - case Qt::BDiagPattern: - case Qt::FDiagPattern: - case Qt::DiagCrossPattern: - if (!patternBrushVertexShader) { - qDebug("Compiling qglslPatternBrushVertexShader"); - patternBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - patternBrushVertexShader->addSource(QLatin1String(qglslPatternBrushVertexShader)); - if (!patternBrushVertexShader->compile()) { - qWarning() << "qglslPatternBrushVertexShader failed to compile: " - << patternBrushVertexShader->log(); - } - } - vertexShader = patternBrushVertexShader; - - if (!patternBrushFragmentShader) { - qDebug("Compiling qglslPatternBrushFragmentShader"); - patternBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - patternBrushFragmentShader->addSource(QLatin1String(qglslNoOpacityFragmentShaderMain)); - patternBrushFragmentShader->addSource(QLatin1String(qglslPatternBrushFragmentShader)); - if (!patternBrushFragmentShader->compile()) { - qWarning() << "qglslPatternBrushFragmentShader failed to compile:" - << patternBrushFragmentShader->log(); - } - } - fragmentShader = patternBrushFragmentShader; - break; - default: - qWarning("Unimplemented brush style (%d)", currentBrushStyle); - } - - // Now newBrushShader is set correctly, check to see if we already have the program - // already linked and ready to go in the cache: - bool foundProgram = false; - foreach (QGLCachedShaderProg cachedProg, cachedPrograms) { - if ((cachedProg.vertexShader == vertexShader) && - (cachedProg.brushShader == fragmentShader) && - (cachedProg.compositionShader == 0) ) { - - activeProgram = cachedProg.shader; - foundProgram = true; - break; - } - } - - if (!foundProgram) { - qDebug() << "Linking shader program for " << currentBrushStyle; - // Required program not found - create it. - QGLShaderProgram* newProg = new QGLShaderProgram(ctx); - - newProg->addShader(vertexShader); - newProg->addShader(fragmentShader); - - if (!newProg->link()) - qWarning() << "Shader program for " << currentBrushStyle << "failed to link:" << newProg->log(); - - QGLCachedShaderProg cachedProg; - cachedProg.vertexShader = vertexShader; - cachedProg.brushShader = fragmentShader; - cachedProg.compositionShader = 0; - cachedProg.shader = newProg; - - cachedPrograms.append(cachedProg); - activeProgram = newProg; - } - - activeProgram->use(); - shaderProgNeedsChanging = false; - return true; -} - -QGLShaderProgram* QGLPEXShaderManager::brushShader() -{ - return activeProgram; -} - -// The only uniform the simple shader has is the PMV matrix -QGLShaderProgram* QGLPEXShaderManager::simpleShader() -{ - if (!simpleShaderProgram) { - simpleShaderProgram = new QGLShaderProgram(ctx); - - if (!simpleFragmentShader) { - simpleFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - simpleFragmentShader->addSource(QLatin1String(qglslSimpleFragmentShader)); - if (!simpleFragmentShader->compile()) - qWarning() << "qglslSimpleFragmentShader failed to compile:" << simpleFragmentShader->log(); - } - - simpleShaderProgram->addShader(defaultVertexShader); - simpleShaderProgram->addShader(simpleFragmentShader); - if (!simpleShaderProgram->link()) - qWarning() << "Simple shader program failed to link:" << simpleShaderProgram->log(); - } - - return simpleShaderProgram; -} - -QGLShaderProgram* QGLPEXShaderManager::imageShader() -{ - if (!imageShaderProgram) { - if (!imageVertexShader) { - imageVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - imageVertexShader->addSource(QLatin1String(qglslImageVertexShader)); - if (!imageVertexShader->compile()) - qWarning() << "Image/Pixmap vertex shader failed to compile:" << imageVertexShader->log(); - } - - if (!imageFragmentShader) { - imageFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - imageFragmentShader->addSource(QLatin1String(qglslImageFragmentShader)); - if (!imageFragmentShader->compile()) - qWarning() << "Image/Pixmap fragment shader failed to compile:" << imageFragmentShader->log(); - } - - imageShaderProgram = new QGLShaderProgram(ctx); - imageShaderProgram->addShader(imageVertexShader); - imageShaderProgram->addShader(imageFragmentShader); - if (!imageShaderProgram->link()) - qWarning() << "Image/Pixmap shader program failed to link:" << imageShaderProgram->log(); - } - - return imageShaderProgram; -} - -QGLShaderProgram* QGLPEXShaderManager::textShader() -{ - if (!textShaderProgram) { - if (!textVertexShader) { - textVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - textVertexShader->addSource(QLatin1String(qglslImageVertexShader)); - if (!textVertexShader->compile()) - qWarning() << "Text vertex shader failed to compile:" << textVertexShader->log(); - } - - if (!textFragmentShader) { - textFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - textFragmentShader->addSource(QLatin1String(qglslTextFragmentShader)); - if (!textFragmentShader->compile()) - qWarning() << "Text fragment shader failed to compile:" << textFragmentShader->log(); - } - - textShaderProgram = new QGLShaderProgram(ctx); - textShaderProgram->addShader(textVertexShader); - textShaderProgram->addShader(textFragmentShader); - if (!textShaderProgram->link()) - qWarning() << "Text shader program failed to link:" << textShaderProgram->log(); - } - - return textShaderProgram; -} - diff --git a/src/opengl/gl2paintengineex/qglpexshadermanager_p.h b/src/opengl/gl2paintengineex/qglpexshadermanager_p.h deleted file mode 100644 index c8f47b2..0000000 --- a/src/opengl/gl2paintengineex/qglpexshadermanager_p.h +++ /dev/null @@ -1,156 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qglshader_p.h" - - -// Worstcase combo: Brush->Mask->Composition - -/* - Vertex shader source is specified with a single string. This string - contains the main function and sets the gl_Position. The choice of - which vertex shader to use depends on: - - Brush style - - Brush transform->isAffine() - - Fragment shaders are specified as multiple strings, one for the main - function, one for the brush calculation and optionally one for the - extended composition mode. Brushes are implementations of - "mediump vec4 brush()" - Composition modes are implemented as a - "mediump vec4 compose(mediump vec4 color)" - NOTE: Precision may change in future. - - The choice of which main() fragment shader string to use depends on: - - Global opacity - - Brush style (some brushes apply opacity themselves) - - Use of mask (TODO: Need to support high quality anti-aliasing & text) - - Composition mode - - The choice of which brush() fragment shader to use depends on: - - Brush style - -*/ - - -struct QGLCachedShaderProg -{ - QGLShader* vertexShader; - QGLShader* brushShader; - QGLShader* compositionShader; - QGLShaderProgram* shader; -}; - -class QGLPEXShaderManager -{ -public: - QGLPEXShaderManager(const QGLContext* context); - ~QGLPEXShaderManager(); - - enum TransformType {IdentityTransform, ScaleTransform, TranslateTransform, FullTransform}; - - void optimiseForBrushTransform(const QTransform& transform); - void setBrushStyle(Qt::BrushStyle style); - void setUseGlobalOpacity(bool value); - void setAffineOnlyBrushTransform(bool value); // I.e. Do we need to apply perspective-correction? - // Not doing so saves some vertex shader calculations. - - bool useCorrectShaderProg(); // returns true if the shader program has changed - - QGLShaderProgram* brushShader(); - QGLShaderProgram* simpleShader(); // Used to draw into e.g. stencil buffers - QGLShaderProgram* imageShader(); - QGLShaderProgram* textShader(); - -private: - QGLShader* defaultVertexShader; - - QGLShader* imageVertexShader; - QGLShader* imageFragmentShader; - QGLShaderProgram* imageShaderProgram; - - QGLShader* textVertexShader; - QGLShader* textFragmentShader; - QGLShaderProgram* textShaderProgram; - - QGLShader* noBrushShader; - QGLShader* solidBrushShader; - - QGLShader* conicalBrushVertexShader; - QGLShader* conicalBrushFragmentShader; - - QGLShader* radialBrushVertexShader; - QGLShader* radialBrushFragmentShader; - - QGLShader* linearBrushVertexShader; - QGLShader* linearBrushFragmentShader; - - QGLShader* patternBrushVertexShader; - QGLShader* patternBrushFragmentShader; - - QGLShader* textureBrushFragmentShader; - QGLShader* textureBrushVertexShader; - - QGLShader* simpleFragmentShader; - QGLShaderProgram* simpleShaderProgram; - - QGLShaderProgram* activeProgram; - - Qt::BrushStyle currentBrushStyle; - bool useGlobalOpacity; - TransformType currentTransformType; - bool shaderProgNeedsChanging; - - QList<QGLCachedShaderProg> cachedPrograms; - - QGLContext* ctx; -}; diff --git a/src/opengl/gl2paintengineex/qglshader.cpp b/src/opengl/gl2paintengineex/qglshader.cpp deleted file mode 100644 index 634be84..0000000 --- a/src/opengl/gl2paintengineex/qglshader.cpp +++ /dev/null @@ -1,605 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglshader_p.h" - - -// Windows needs to resolve OpenGL 2.0 function pointers for each context. The -// QGL OpenGL 2.0 functions are actually macros, which take a "ctx" parameter. -#define Q_CTX QGLContext* ctx = d->ctx; \ - if (!ctx) \ - return false; \ - ctx->makeCurrent(); \ - - - - -class QGLShaderPrivate -{ -public: - QGLShaderPrivate() : shaderId(0), valid(false), ctx(0) {} - - GLuint shaderId; - QString source; - bool valid; - QGLShader::ShaderType type; - QGLContext* ctx; -}; - - -QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext* ctx) - : d_ptr(new QGLShaderPrivate) -{ - Q_D(QGLShader); - - if (!ctx) - ctx = QGLContext::currentContext(); - - if (!ctx) { - qWarning("QGLShader being created without a context"); - return; - } - - d->ctx = const_cast<QGLContext*>(ctx); - d->ctx->makeCurrent(); - - if (type == QGLShader::FragmentShader) - d->shaderId = glCreateShader(GL_FRAGMENT_SHADER); - else - d->shaderId = glCreateShader(GL_VERTEX_SHADER); - - if (d->shaderId == 0) { - qWarning("Error creating shader object"); - return; - } - - d->type = type; -} - -GLuint QGLShader::id() -{ - Q_D(QGLShader); - return d->shaderId; -} - -const QGLContext* QGLShader::context() -{ - Q_D(QGLShader); - return d->ctx; -} - -void QGLShader::clearSource() -{ - Q_D(QGLShader); - d->source.clear(); - d->valid = false; -} - -void QGLShader::addSource(const QLatin1String& newSource) -{ - Q_D(QGLShader); - d->source += newSource; - d->valid = false; -} - - -bool QGLShader::compile() -{ - Q_D(QGLShader); - - d->valid = false; - - if (d->source.size() == 0) - return false; - - const QByteArray src_ba = d->source.toAscii(); - const char* src = src_ba.constData(); - - glShaderSource(d->shaderId, 1, &src, 0); - - glCompileShader(d->shaderId); - - GLint shaderCompiled; - glGetShaderiv(d->shaderId, GL_COMPILE_STATUS, &shaderCompiled); - if (!shaderCompiled) - return false; - - d->valid = true; - return true; -} - -bool QGLShader::isValid() -{ - Q_D(QGLShader); - return d->valid; -} - -QString QGLShader::log() -{ - Q_D(QGLShader); - - char* logData; - GLint logSize; - GLint logLength; - - glGetShaderiv(d->shaderId, GL_INFO_LOG_LENGTH, &logSize); - - if (!logSize) - return QString(); - - logData = new char[logSize]; - glGetShaderInfoLog(d->shaderId, logSize, &logLength, logData); - QString result = QString::fromAscii(logData); - delete [] logData; - - return result; -} - - - - - - - - - - - - -class QGLShaderProgramPrivate -{ -public: - QGLShaderProgramPrivate() : valid(false), programId(0), ctx(0) {} - void populateVariableLists(); - - QVector<QGLShader*> shaders; - QGLUniformList uniforms; - QGLVertexAttributeList attributeArrays; - bool valid; - GLuint programId; - QGLContext* ctx; -}; - - - -void QGLShaderProgramPrivate::populateVariableLists() -{ - attributeArrays.clear(); - uniforms.clear(); - - int count; - int sizeOfNameBuff; - char* name; - GLint nameLength; - GLenum type; - GLint size; - GLint location; - - glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &count); - glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &sizeOfNameBuff); - name = new char[sizeOfNameBuff]; - - for (int i = 0; i < count; ++i) { - nameLength = -1; - glGetActiveAttrib(programId, i, sizeOfNameBuff, &nameLength, &size, &type, name); - if (nameLength == -1) - continue; - - location = glGetAttribLocation(programId, name); - attributeArrays.insert(QString::fromAscii(name), QGLVertexAttribute(type, location, ctx)); - } - - delete [] name; - - - glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &count); - glGetProgramiv(programId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &sizeOfNameBuff); - - name = new char[sizeOfNameBuff]; - - for (int i = 0; i < count; ++i) { - nameLength = -1; - glGetActiveUniform(programId, i, sizeOfNameBuff, &nameLength, &size, &type, name); - if (nameLength == -1) - continue; - - location = glGetUniformLocation(programId, name); - uniforms.insert(QString::fromAscii(name), QGLUniform(type, location, ctx)); - } -} - - -QGLShaderProgram::QGLShaderProgram(const QGLContext* ctx) - : d_ptr(new QGLShaderProgramPrivate) -{ - Q_D(QGLShaderProgram); - if (!ctx) - ctx = QGLContext::currentContext(); - - if (!ctx) { - qWarning("QGLShaderProgram being created without a context"); - return; - } - - d->ctx = const_cast<QGLContext*>(ctx); - d->ctx->makeCurrent(); - - d->programId = glCreateProgram(); - - d->valid = false; -} - - -const QGLUniformList & QGLShaderProgram::uniforms() -{ - Q_D(QGLShaderProgram); - return const_cast<const QGLUniformList&>(d->uniforms); -} - - -const QGLVertexAttributeList& QGLShaderProgram::vertexAttributes() -{ - Q_D(QGLShaderProgram); - return const_cast<const QGLVertexAttributeList&>(d->attributeArrays); -} - - -bool QGLShaderProgram::addShader(QGLShader* newShader) -{ - Q_D(QGLShaderProgram); - if (!newShader || !d->ctx) - return false; - - if (newShader->context() != d->ctx) { - qWarning("Shader object's context does not match program's context"); - return false; - } - - if (!newShader->isValid()) - return false; - - QGLContext* ctx = d->ctx; - if (!ctx) - return false; - ctx->makeCurrent(); - - glAttachShader(d->programId, newShader->id()); - - d->shaders.append(newShader); - return true; -} - - -bool QGLShaderProgram::removeShader(QGLShader* oldShader) -{ - Q_D(QGLShaderProgram); - - int idx = d->shaders.indexOf(oldShader); - - if (idx == -1) - return false; - - d->shaders.remove(idx); - - QGLContext* ctx = d->ctx; - if (!ctx) - return false; - ctx->makeCurrent(); - - glDetachShader(d->programId, oldShader->id()); - return true; -} - - -bool QGLShaderProgram::removeAllShaders() -{ - Q_D(QGLShaderProgram); - - QGLContext* ctx = d->ctx; - if (!ctx) - return false; - ctx->makeCurrent(); - - foreach (QGLShader* shader, d->shaders) - glDetachShader(d->programId, shader->id()); - - d->shaders.clear(); - return true; -} - -#include <stdio.h> - -bool QGLShaderProgram::link() -{ - Q_D(QGLShaderProgram); - - QGLContext* ctx = d->ctx; - if (!ctx) - return false; - ctx->makeCurrent(); - - glLinkProgram(d->programId); - - - GLint linked; - glGetProgramiv(d->programId, GL_LINK_STATUS, &linked); - - if (!linked) - return false; - - d->populateVariableLists(); - - d->valid = true; - return true; -} - -void QGLShaderProgram::use() -{ - Q_D(QGLShaderProgram); - if (!d->valid) - return; - - glUseProgram(d->programId); -} - - -QString QGLShaderProgram::log() -{ - Q_D(QGLShaderProgram); - - QGLContext* ctx = d->ctx; - if (!ctx) - return QString(); - ctx->makeCurrent(); - - GLint logSize = -666; - glGetProgramiv(d->programId, GL_INFO_LOG_LENGTH, &logSize); - - char* logData = new char[logSize]; - GLint logLength; - - glGetProgramInfoLog(d->programId, logSize, &logLength, logData); - - QString result = QString::fromAscii(logData); - delete [] logData; - - return result; -} - -GLuint QGLShaderProgram::id() -{ - Q_D(QGLShaderProgram); - return d->programId; -} - -///////////////////////////////////////////////////////////////////////// - - - - -QGLUniform::QGLUniform() - : m_id(0), m_type(QGLInvalidType), ctx(0) -{ - qWarning("Unknown uniform! Either the uniform doesn't exist or it was removed at shader link"); -} - -const QGLUniform& QGLUniform::operator=(const GLfloat& rhs) const -{ - if (m_type != QGLFloatType) - return *this; - - glUniform1f(m_id, rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QGLVec2& rhs) const -{ - if (m_type != QGLVec2Type) - return *this; - - glUniform2fv(m_id, 1, (const GLfloat*)&rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QSizeF& rhs) const -{ - if (m_type != QGLVec2Type) - return *this; - - glUniform2f(m_id, rhs.width(), rhs.height()); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QPointF& rhs) const -{ - if (m_type != QGLVec2Type) - return *this; - - glUniform2f(m_id, rhs.x(), rhs.y()); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QGLVec3& rhs) const -{ - if (m_type != QGLVec3Type) - return *this; - - glUniform3fv(m_id, 1, (const GLfloat*)&rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QGLVec4& rhs) const -{ - if (m_type != QGLVec4Type) - return *this; - - glUniform4fv(m_id, 1, (const GLfloat*)&rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QColor& rhs) const -{ - if (m_type != QGLVec4Type) - return *this; - - glUniform4f(m_id, rhs.redF(), rhs.greenF(), rhs.blueF(), rhs.alphaF()); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const GLfloat rhs[2][2]) const -{ - if (m_type != QGLMat2Type) - return *this; - - glUniformMatrix2fv(m_id, 1, GL_FALSE, (GLfloat*)rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const GLfloat rhs[3][3]) const -{ - if (m_type != QGLMat3Type) - return *this; - - glUniformMatrix3fv(m_id, 1, GL_FALSE, (GLfloat*)rhs); - - return *this; -} - -// Transposes ready for GL -const QGLUniform& QGLUniform::operator=(const QTransform& rhs) const -{ - if (m_type != QGLMat3Type) - return *this; - - GLfloat mat3[3][3] = { - {rhs.m11(), rhs.m12(), rhs.m13()}, - {rhs.m21(), rhs.m22(), rhs.m23()}, - {rhs.m31(), rhs.m32(), rhs.m33()} - }; - - glUniformMatrix3fv(m_id, 1, GL_FALSE, (GLfloat*)mat3); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const GLfloat rhs[4][4]) const -{ - if (m_type != QGLMat4Type) - return *this; - - glUniformMatrix4fv(m_id, 1, GL_FALSE, (GLfloat*)rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const GLuint& rhs) const -{ - if ((m_type != QGLSampler2DType) || (m_type != QGLSamplerCubeType)) - return *this; - - glUniform1i(m_id, rhs); - - return *this; -} - - - - -///////////////////////////////////////////////////////////////////////// - -QGLVertexAttribute::QGLVertexAttribute() - : m_id(0), m_type(QGLInvalidType), ctx(0) -{ - qWarning("Unknown vertex attribute!"); -} - -void QGLVertexAttribute::enable() const -{ - glEnableVertexAttribArray(m_id); -} - -void QGLVertexAttribute::disable() const -{ - glDisableVertexAttribArray(m_id); -} - -// NOTE: Under PC emulation, QGLVec4Type is _always_ returned as the type, so this -// method isn't very useful. I.e. The datatypes are needed to distinguish the different -// sizes for the function signatures. -const QGLVertexAttribute& QGLVertexAttribute::operator=(const GLfloat* rhs) const -{ - int size = -1; - if (m_type == QGLFloatType) - size = 1; - else if (m_type == QGLVec2Type) - size = 2; - else if (m_type == QGLVec3Type) - size = 3; - else if (m_type == QGLVec4Type) - size = 4; - else if (m_type == QGLMat2Type) //### Not sure if this is right for matrix attributes... - size = 4; - else if (m_type == QGLMat3Type) //### Not sure if this is right for matrix attributes... - size = 9; - else if (m_type == QGLMat4Type) //### Not sure if this is right for matrix attributes... - size = 16; - else - return *this; - - glVertexAttribPointer(m_id, size, GL_FLOAT, GL_FALSE, 0, rhs); - - return *this; -} - -const QGLVertexAttribute& QGLVertexAttribute::operator=(const QGLVec3* rhs) const -{ - glVertexAttribPointer(m_id, 3, GL_FLOAT, GL_FALSE, 0, (GLfloat*)rhs); - - return *this; -} diff --git a/src/opengl/gl2paintengineex/qglshader_p.h b/src/opengl/gl2paintengineex/qglshader_p.h deleted file mode 100644 index 1625b84..0000000 --- a/src/opengl/gl2paintengineex/qglshader_p.h +++ /dev/null @@ -1,260 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -/* -Uniform Types in OpenGL ES 2.0 -============================== -GL_FLOAT GLfloat GLfloat -GL_FLOAT_VEC2 QGLVec2 GLfloat[2] -GL_FLOAT_VEC3 QGLVec3 GLfloat[3] -GL_FLOAT_VEC4 QGLVec4 GLfloat[4] -GL_INT GLint GLint -GL_INT_VEC2 QGLIVec2 GLint[2] -GL_INT_VEC3 QGLIVec3 GLint[3] -GL_INT_VEC4 QGLIVec4 GLint[4] -GL_BOOL GLbool GLbool -GL_BOOL_VEC2 QGLBVec2 GLbool[2] -GL_BOOL_VEC3 QGLBVec3 GLbool[3] -GL_BOOL_VEC4 QGLBVec4 GLbool[4] -GL_FLOAT_MAT2 QGLMat2 GLfloat[2][2] -GL_FLOAT_MAT3 QGLMat3 GLfloat[3][3] -GL_FLOAT_MAT4 QGLMat4 GLfloat[4][4] -GL_SAMPLER_2D QGLSampler2D GLuint -GL_SAMPLER_CUBE QGLSamplerCube GLuint - -Additional Types in Desktop OpenGL 2.0 -====================================== -SAMPLER_1D, -SAMPLER_3D, -SAMPLER_1D_SHADOW, -SAMPLER_2D_SHADOW. -*/ - -#include <QtOpenGL> - - -typedef struct { - GLfloat a; - GLfloat b; -} QGLVec2; - -typedef struct { - GLfloat a; - GLfloat b; - GLfloat c; -} QGLVec3; - -typedef struct { - GLfloat a; - GLfloat b; - GLfloat c; - GLfloat d; -} QGLVec4; - - -class QGLShaderProgram; - -class QGLShaderPrivate; - -class QGLShader : QObject -{ - Q_OBJECT -public: - enum ShaderType {VertexShader, FragmentShader}; - - QGLShader(ShaderType type, const QGLContext* ctx = 0); - - GLuint id(); - void clearSource(); - void addSource(const QLatin1String& newSource); - bool compile(); - bool isValid(); - QString log(); - const QGLContext* context(); //maybe make private with prog a friend? - -private: - QGLShaderPrivate* d_ptr; - Q_DECLARE_PRIVATE(QGLShader); - -/* -public slots: - void cleanupGLContextRefs(const QGLContext *context); -*/ -}; - - -enum QGLType { - QGLInvalidType = 0, - QGLFloatType = GL_FLOAT, - QGLVec2Type = GL_FLOAT_VEC2, - QGLVec3Type = GL_FLOAT_VEC3, - QGLVec4Type = GL_FLOAT_VEC4, - QGLIntType = GL_INT, - QGLIVec2Type = GL_INT_VEC2, - QGLIVec3Type = GL_INT_VEC3, - QGLIVec4Type = GL_INT_VEC4, - QGLBoolType = GL_BOOL, - QGLBVec2Type = GL_BOOL_VEC2, - QGLBVec3Type = GL_BOOL_VEC3, - QGLBVec4Type = GL_BOOL_VEC4, - QGLMat2Type = GL_FLOAT_MAT2, - QGLMat3Type = GL_FLOAT_MAT3, - QGLMat4Type = GL_FLOAT_MAT4, - QGLSampler2DType = GL_SAMPLER_2D, - QGLSamplerCubeType = GL_SAMPLER_CUBE -}; - -class QGLUniform -{ -public: - - QGLUniform(GLenum glType, GLint location, QGLContext* context) - : m_id(location), m_type(QGLType(glType)), ctx(context) {} - - QGLUniform(); // Called by QMap when there's no match on the name - - QGLType type() const {return m_type;} - GLuint id() const {return m_id;} - - // Seems odd to be const, but it doesn't actually modify any of the - // class members, only the GL state! - const QGLUniform& operator=(const GLfloat&) const; - - const QGLUniform& operator=(const QGLVec2&) const; - const QGLUniform& operator=(const QSizeF&) const; - const QGLUniform& operator=(const QPointF&) const; - - const QGLUniform& operator=(const QGLVec3&) const; - - const QGLUniform& operator=(const QGLVec4&) const; - const QGLUniform& operator=(const QColor&) const; - - const QGLUniform& operator=(const GLfloat[2][2]) const; - - const QGLUniform& operator=(const GLfloat[3][3]) const; - const QGLUniform& operator=(const QTransform&) const; - - const QGLUniform& operator=(const GLfloat[4][4]) const; - - const QGLUniform& operator=(const GLuint&) const; // sampler2d, specifying a texture unit - - -protected: - GLuint m_id; - QGLType m_type; - QGLContext* ctx; -}; - -typedef QMap<QString, QGLUniform> QGLUniformList; -typedef QMapIterator<QString, QGLUniform> QGLUniformListIterator; - - -class QGLVertexAttribute -{ -public: - QGLVertexAttribute(GLenum glType, GLuint location, QGLContext* context) - : m_id(location), m_type(QGLType(glType)), ctx(context) {} - - QGLVertexAttribute(); // Called by QMap when there's no match on the name - - QGLType type() const {return m_type;} - GLuint id() const {return m_id;} - void enable() const; - void disable() const; - - const QGLVertexAttribute& operator=(const GLfloat* rhs) const; - const QGLVertexAttribute& operator=(const QGLVec3* rhs) const; - -protected: - GLuint m_id; - QGLType m_type; - QGLContext* ctx; -}; - -//TODO: Convert into setter overloads on QGLShaderProgram -typedef QMap<QString, QGLVertexAttribute> QGLVertexAttributeList; -typedef QMapIterator<QString, QGLVertexAttribute> QGLVertexAttributeListIterator; - - - -class QGLShaderProgramPrivate; - -class QGLShaderProgram : QObject -{ - Q_OBJECT -public: - QGLShaderProgram(const QGLContext* ctx = 0); - - const QGLUniformList & uniforms(); - const QGLVertexAttributeList& vertexAttributes(); - - bool addShader(QGLShader* newShader); - bool removeShader(QGLShader* oldShader); - bool removeAllShaders(); - - bool link(); - QString log(); - bool isValid(); - void use(); - - GLuint id(); - -private: - QGLShaderProgramPrivate* d_ptr; - Q_DECLARE_PRIVATE(QGLShaderProgram); - -/* -public slots: - void cleanupGLContextRefs(const QGLContext *context); -*/ -}; - diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index a74f044..e7b6ee4 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -62,7 +62,6 @@ and use the correct program when we really need it. */ - #include "qpaintengineex_opengl2_p.h" #include <string.h> //for memcpy @@ -77,93 +76,20 @@ #include <private/qtextureglyphcache_p.h> #include "qglgradientcache_p.h" -#include "qglpexshadermanager_p.h" +#include "qglengineshadermanager_p.h" #include "qgl2pexvertexarray_p.h" -extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp - - #include <QDebug> +QT_BEGIN_NAMESPACE -static const GLuint QT_VERTEX_COORDS_ATTR = 0; -static const GLuint QT_TEXTURE_COORDS_ATTR = 1; -static const GLuint QT_BRUSH_TEXTURE_UNIT = 0; - -class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate -{ - Q_DECLARE_PUBLIC(QGL2PaintEngineEx) -public: - QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) : - q(q_ptr), - width(0), height(0), - ctx(0), - currentBrush( &(q->state()->brush) ), - inverseScale(1), - shaderManager(0) - { } - - ~QGL2PaintEngineExPrivate(); - - void updateBrushTexture(); - void updateBrushUniforms(); - void updateMatrix(); - void updateCompositionMode(); - void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform); - - void setBrush(const QBrush* brush); - - void drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight); - - void fill(const QVectorPath &path); - void drawOutline(const QVectorPath& path); - - void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive); - // ^ draws whatever is in the vertex array - void composite(const QGLRect& boundingRect); - // ^ Composites the bounding rect onto dest buffer - void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill); - // ^ Calls drawVertexArrays to render into stencil buffer - void cleanStencilBuffer(const QGLRect& area); - - void prepareForDraw(); - - inline void useSimpleShader(); - inline QColor premultiplyColor(QColor c, GLfloat opacity); - - QGL2PaintEngineEx* q; - - //### Move into QGLDrawable - int width, height; - QGLContext* ctx; - - // Dirty flags - bool matrixDirty; // Implies matrix uniforms are also dirty - bool compositionModeDirty; - bool brushTextureDirty; - bool brushUniformsDirty; - bool simpleShaderMatrixUniformDirty; - bool brushShaderMatrixUniformDirty; - bool imageShaderMatrixUniformDirty; - bool textShaderMatrixUniformDirty; - bool stencilBuferDirty; - - const QBrush* currentBrush; // May not be the state's brush! - - GLfloat inverseScale; - - QGL2PEXVertexArray pathVertexArray; - - GLfloat pmvMatrix[4][4]; - - QGLPEXShaderManager* shaderManager; - - // Clipping & state stuff stolen from QOpenGLPaintEngine: - void updateDepthClip(); - uint use_system_clip : 1; -}; +extern QImage qt_imageForBrush(int brushStyle, bool invert); +static const GLuint QT_BRUSH_TEXTURE_UNIT = 0; +static const GLuint QT_IMAGE_TEXTURE_UNIT = 0; //Can be the same as brush texture unit +static const GLuint QT_MASK_TEXTURE_UNIT = 1; +static const GLuint QT_BACKGROUND_TEXTURE_UNIT = 2; ////////////////////////////////// Private Methods ////////////////////////////////////////// @@ -177,7 +103,7 @@ QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate() void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform) { - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); +// glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit? if (smoothPixmapTransform) { glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -206,27 +132,27 @@ void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush) currentBrush = brush; brushTextureDirty = true; brushUniformsDirty = true; - shaderManager->setBrushStyle(currentBrush->style()); - shaderManager->setAffineOnlyBrushTransform(currentBrush->transform().isAffine()); + shaderManager->setSrcPixelType(currentBrush->style()); + shaderManager->optimiseForBrushTransform(currentBrush->transform()); } // Unless this gets used elsewhere, it's probably best to merge it into fillStencilWithVertexArray void QGL2PaintEngineExPrivate::useSimpleShader() { - shaderManager->simpleShader()->use(); + shaderManager->simpleProgram()->enable(); if (matrixDirty) updateMatrix(); if (simpleShaderMatrixUniformDirty) { - shaderManager->simpleShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix; + shaderManager->simpleProgram()->setUniformValue("pmvMatrix", pmvMatrix); simpleShaderMatrixUniformDirty = false; } } -Q_GLOBAL_STATIC(QGLGradientCache, qt_opengl_gradient_cache) +Q_GLOBAL_STATIC(QGL2GradientCache, qt_opengl_gradient_cache) void QGL2PaintEngineExPrivate::updateBrushTexture() { @@ -237,7 +163,7 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() // Get the image data for the pattern QImage texImage = qt_imageForBrush(style, true); - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true); } @@ -257,12 +183,13 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() else updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, true); + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); glBindTexture(GL_TEXTURE_2D, texId); } else if (style == Qt::TexturePattern) { const QPixmap& texPixmap = currentBrush->texture(); - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, true); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true); } @@ -278,17 +205,11 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() if (style == Qt::NoBrush) return; - GLfloat opacity = 1.0; - if (q->state()->opacity < 0.99f) - opacity = (GLfloat)q->state()->opacity; - bool setOpacity = true; - QTransform brushQTransform = currentBrush->transform(); if (style == Qt::SolidPattern) { - QColor col = premultiplyColor(currentBrush->color(), opacity); - shaderManager->brushShader()->uniforms()[QLatin1String("fragmentColor")] = col; - setOpacity = false; + QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); + shaderManager->currentProgram()->setUniformValue("fragmentColor", col); } else { // All other brushes have a transform and thus need the translation point: @@ -297,13 +218,12 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() if (style <= Qt::DiagCrossPattern) { translationPoint = q->state()->brushOrigin; - QColor col = premultiplyColor(currentBrush->color(), opacity); + QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); - shaderManager->brushShader()->uniforms()[QLatin1String("patternColor")] = col; - setOpacity = false; //So code below doesn't try to set the opacity uniform + shaderManager->currentProgram()->setUniformValue("patternColor", col); - QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; - shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue("halfViewportSize", halfViewportSize); } else if (style == Qt::LinearGradientPattern) { const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush->gradient()); @@ -314,17 +234,16 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() QPointF l = realFinal - realStart; - // ### - QGLVec3 linearData = { + QVector3D linearData( l.x(), l.y(), 1.0f / (l.x() * l.x() + l.y() * l.y()) - }; + ); - shaderManager->brushShader()->uniforms()[QLatin1String("linearData")] = linearData; + shaderManager->currentProgram()->setUniformValue("linearData", linearData); - QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; - shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue("halfViewportSize", halfViewportSize); } else if (style == Qt::ConicalGradientPattern) { const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush->gradient()); @@ -332,10 +251,10 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0; - shaderManager->brushShader()->uniforms()[QLatin1String("angle")] = angle; + shaderManager->currentProgram()->setUniformValue("angle", angle); - QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; - shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue("halfViewportSize", halfViewportSize); } else if (style == Qt::RadialGradientPattern) { const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush->gradient()); @@ -345,16 +264,15 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() translationPoint = realFocal; QPointF fmp = realCenter - realFocal; - shaderManager->brushShader()->uniforms()[QLatin1String("fmp")] = fmp; + shaderManager->currentProgram()->setUniformValue("fmp", fmp); GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius; - shaderManager->brushShader()->uniforms()[QLatin1String("fmp2_m_radius2")] = fmp2_m_radius2; + shaderManager->currentProgram()->setUniformValue("fmp2_m_radius2", fmp2_m_radius2); + shaderManager->currentProgram()->setUniformValue("inverse_2_fmp2_m_radius2", + GLfloat(1.0 / (2.0*fmp2_m_radius2))); - shaderManager->brushShader()->uniforms()[QLatin1String("inverse_2_fmp2_m_radius2")] = - GLfloat(1.0 / (2.0*fmp2_m_radius2)); - - QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; - shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue("halfViewportSize", halfViewportSize); } else if (style == Qt::TexturePattern) { translationPoint = q->state()->brushOrigin; @@ -362,10 +280,10 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() const QPixmap& texPixmap = currentBrush->texture(); QSizeF invertedTextureSize( 1.0 / texPixmap.width(), 1.0 / texPixmap.height() ); - shaderManager->brushShader()->uniforms()[QLatin1String("invertedTextureSize")] = invertedTextureSize; + shaderManager->currentProgram()->setUniformValue("invertedTextureSize", invertedTextureSize); - QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; - shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue("halfViewportSize", halfViewportSize); } else qWarning("QGL2PaintEngineEx: Unimplemented fill style"); @@ -374,11 +292,8 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() QTransform gl_to_qt(1, 0, 0, -1, 0, height); QTransform inv_matrix = gl_to_qt * (brushQTransform * q->state()->matrix).inverted() * translate; - shaderManager->brushShader()->uniforms()[QLatin1String("brushTransform")] = inv_matrix; - shaderManager->brushShader()->uniforms()[QLatin1String("brushTexture")] = QT_BRUSH_TEXTURE_UNIT; - - if (setOpacity) - shaderManager->brushShader()->uniforms()[QLatin1String("opacity")] = opacity; + shaderManager->currentProgram()->setUniformValue("brushTransform", inv_matrix); + shaderManager->currentProgram()->setUniformValue("brushTexture", QT_BRUSH_TEXTURE_UNIT); } brushUniformsDirty = false; } @@ -397,38 +312,51 @@ void QGL2PaintEngineExPrivate::updateMatrix() {0.0, 0.0, 0.0, 1.0} }; - // Use the (3x3) transform for the Model~View matrix: const QTransform& transform = q->state()->matrix; - GLfloat MV[4][4] = { - {transform.m11(), transform.m21(), 0.0, transform.dx() + 0.5}, - {transform.m12(), transform.m22(), 0.0, transform.dy() + 0.5}, - {0.0, 0.0, 1.0, 0.0}, - {transform.m13(), transform.m23(), 0.0, transform.m33()} - }; - // NOTE: OpenGL ES works with column-major matrices, so when we multiply the matrices, - // we also transpose them ready for GL. - for (int row = 0; row < 4; ++row) { - for (int col = 0; col < 4; ++col) { - pmvMatrix[col][row] = 0.0; - for (int n = 0; n < 4; ++n) - pmvMatrix[col][row] += P[row][n] * MV[n][col]; + if (mode == TextDrawingMode) { + // Text drawing mode is only used for non-scaling transforms + for (int row = 0; row < 4; ++row) + for (int col = 0; col < 4; ++col) + pmvMatrix[col][row] = P[row][col]; + + pmvMatrix[3][0] += P[0][0] * qRound(transform.dx()); + pmvMatrix[3][1] += P[1][1] * qRound(transform.dy()); + + inverseScale = 1; + } else { + // Use the (3x3) transform for the Model~View matrix: + GLfloat MV[4][4] = { + {transform.m11(), transform.m21(), 0.0, transform.dx()}, + {transform.m12(), transform.m22(), 0.0, transform.dy()}, + {0.0, 0.0, 1.0, 0.0}, + {transform.m13(), transform.m23(), 0.0, transform.m33()} + }; + + // NOTE: OpenGL ES works with column-major matrices, so when we multiply the matrices, + // we also transpose them ready for GL. + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + pmvMatrix[col][row] = 0.0; + + // P[row][n] is 0.0 for n < row + for (int n = row; n < 4; ++n) + pmvMatrix[col][row] += P[row][n] * MV[n][col]; + } } - } - // 1/10000 == 0.0001, so we have good enough res to cover curves - // that span the entire widget... - inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), - qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), - qreal(0.0001)); + // 1/10000 == 0.0001, so we have good enough res to cover curves + // that span the entire widget... + inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), + qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), + qreal(0.0001)); + } matrixDirty = false; // The actual data has been updated so both shader program's uniforms need updating simpleShaderMatrixUniformDirty = true; - brushShaderMatrixUniformDirty = true; - imageShaderMatrixUniformDirty = true; - textShaderMatrixUniformDirty = true; + shaderMatrixUniformDirty = true; } @@ -485,120 +413,140 @@ void QGL2PaintEngineExPrivate::updateCompositionMode() compositionModeDirty = false; } +static inline void setCoords(GLfloat *coords, const QGLRect &rect) +{ + coords[0] = rect.left; + coords[1] = rect.top; + coords[2] = rect.right; + coords[3] = rect.top; + coords[4] = rect.right; + coords[5] = rect.bottom; + coords[6] = rect.left; + coords[7] = rect.bottom; +} -void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight) +void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque) { -// qDebug("QGL2PaintEngineExPrivate::drawImage()"); + transferMode(ImageDrawingMode); - // We have a shader specifically for drawPixmap/drawImage... - shaderManager->imageShader()->use(); + updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); - updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); + // Setup for texture drawing + shaderManager->setSrcPixelType(QGLEngineShaderManager::ImageSrc); + shaderManager->setTextureCoordsEnabled(true); + prepareForDraw(opaque); - if (compositionModeDirty) - updateCompositionMode(); + shaderManager->currentProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); - if (matrixDirty) - updateMatrix(); + GLfloat dx = 1.0 / textureSize.width(); + GLfloat dy = 1.0 / textureSize.height(); - if (imageShaderMatrixUniformDirty) { - shaderManager->imageShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix; - imageShaderMatrixUniformDirty = false; - } + QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy); - shaderManager->imageShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT; + setCoords(staticVertexCoordinateArray, dest); + setCoords(staticTextureCoordinateArray, srcTextureRect); -// if (q->state()->opacity < 0.99f) - shaderManager->imageShader()->uniforms()[QLatin1String("opacity")] = (GLfloat)q->state()->opacity; + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} - GLfloat vertexCoords[] = { - dest.left, dest.top, - dest.left, dest.bottom, - dest.right, dest.bottom, - dest.right, dest.top - }; +void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) +{ + if (newMode == mode) + return; - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords); + if (mode == TextDrawingMode || mode == ImageDrawingMode) { + glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); + glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + } - GLfloat dx = 1.0 / txtWidth; - GLfloat dy = 1.0 / txtHeight; + if (mode == TextDrawingMode) + matrixDirty = true; - QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy); + if (newMode == TextDrawingMode) { + glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - GLfloat textureCoords[] = { - srcTextureRect.left, srcTextureRect.top, - srcTextureRect.left, srcTextureRect.bottom, - srcTextureRect.right, srcTextureRect.bottom, - srcTextureRect.right, srcTextureRect.top - }; + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); + glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); - glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); + matrixDirty = true; + } - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + if (newMode == ImageDrawingMode) { + glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); -} + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticVertexCoordinateArray); + glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray); + } + // This needs to change when we implement high-quality anti-aliasing... + if (newMode != TextDrawingMode) + shaderManager->setMaskType(QGLEngineShaderManager::NoMask); + + mode = newMode; +} void QGL2PaintEngineExPrivate::drawOutline(const QVectorPath& path) { -// qDebug("QGL2PaintEngineExPrivate::drawOutline()"); + transferMode(BrushDrawingMode); + + // Might need to call updateMatrix to re-calculate inverseScale if (matrixDirty) updateMatrix(); - pathVertexArray.clear(); - pathVertexArray.addPath(path, inverseScale); + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale); if (path.hasImplicitClose()) { // Close the path's outline - pathVertexArray.lineToArray(path.points()[0], path.points()[1]); - pathVertexArray.stops().last() += 1; + vertexCoordinateArray.lineToArray(path.points()[0], path.points()[1]); + vertexCoordinateArray.stops().last() += 1; } - prepareForDraw(); - drawVertexArrays(pathVertexArray, GL_LINE_STRIP); + prepareForDraw(currentBrush->isOpaque()); + drawVertexArrays(vertexCoordinateArray, GL_LINE_STRIP); } // Assumes everything is configured for the brush you want to use void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) { + transferMode(BrushDrawingMode); + + // Might need to call updateMatrix to re-calculate inverseScale if (matrixDirty) updateMatrix(); const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); - // Check to see if there's any hints if (path.shape() == QVectorPath::RectangleHint) { QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y()); - prepareForDraw(); + prepareForDraw(currentBrush->isOpaque()); composite(rect); } else if (path.shape() == QVectorPath::EllipseHint) { - pathVertexArray.clear(); - pathVertexArray.addPath(path, inverseScale); - prepareForDraw(); - drawVertexArrays(pathVertexArray, GL_TRIANGLE_FAN); + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale); + prepareForDraw(currentBrush->isOpaque()); + drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); } else { // The path is too complicated & needs the stencil technique - pathVertexArray.clear(); - pathVertexArray.addPath(path, inverseScale); + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale); - fillStencilWithVertexArray(pathVertexArray, path.hasWindingFill()); + fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); // Stencil the brush onto the dest buffer glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0 glEnable(GL_STENCIL_TEST); - prepareForDraw(); - composite(pathVertexArray.boundingRect()); + prepareForDraw(currentBrush->isOpaque()); + composite(vertexCoordinateArray.boundingRect()); glDisable(GL_STENCIL_TEST); - cleanStencilBuffer(pathVertexArray.boundingRect()); + cleanStencilBuffer(vertexCoordinateArray.boundingRect()); } } @@ -674,32 +622,54 @@ void QGL2PaintEngineExPrivate::cleanStencilBuffer(const QGLRect& area) glDisable(GL_STENCIL_TEST); } -void QGL2PaintEngineExPrivate::prepareForDraw() +void QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) { - if (brushTextureDirty) + if (brushTextureDirty && mode != ImageDrawingMode) updateBrushTexture(); if (compositionModeDirty) updateCompositionMode(); + if (matrixDirty) + updateMatrix(); + + const bool stateHasOpacity = q->state()->opacity < 0.99f; + if (q->state()->compositionMode() == QPainter::CompositionMode_Source + || (q->state()->compositionMode() == QPainter::CompositionMode_SourceOver + && srcPixelsAreOpaque && !stateHasOpacity)) + glDisable(GL_BLEND); + else + glEnable(GL_BLEND); + + bool useGlobalOpacityUniform = stateHasOpacity; + if (stateHasOpacity && (mode != ImageDrawingMode)) { + // Using a brush + bool brushIsPattern = (currentBrush->style() >= Qt::Dense1Pattern) && + (currentBrush->style() <= Qt::DiagCrossPattern); + + if ((currentBrush->style() == Qt::SolidPattern) || brushIsPattern) + useGlobalOpacityUniform = false; // Global opacity handled by srcPixel shader + } + shaderManager->setUseGlobalOpacity(useGlobalOpacityUniform); + + + // If the shader program needs changing, we change it and mark all uniforms as dirty if (shaderManager->useCorrectShaderProg()) { // The shader program has changed so mark all uniforms as dirty: brushUniformsDirty = true; - brushShaderMatrixUniformDirty = true; + shaderMatrixUniformDirty = true; } - if (brushUniformsDirty) + if (brushUniformsDirty && mode != ImageDrawingMode) updateBrushUniforms(); - if (brushShaderMatrixUniformDirty) { - shaderManager->brushShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix; - brushShaderMatrixUniformDirty = false; + if (shaderMatrixUniformDirty) { + shaderManager->currentProgram()->setUniformValue("pmvMatrix", pmvMatrix); + shaderMatrixUniformDirty = false; } - if ((q->state()->opacity < 0.99f) || !currentBrush->isOpaque()) - glEnable(GL_BLEND); - else - glDisable(GL_BLEND); + if (useGlobalOpacityUniform) + shaderManager->currentProgram()->setUniformValue("globalOpacity", (GLfloat)q->state()->opacity); } void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect) @@ -749,8 +719,6 @@ void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray, QGL2PaintEngineEx::QGL2PaintEngineEx() : QPaintEngineEx(*(new QGL2PaintEngineExPrivate(this))) { - qDebug("QGL2PaintEngineEx::QGL2PaintEngineEx()"); - } QGL2PaintEngineEx::~QGL2PaintEngineEx() @@ -761,8 +729,10 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush) { Q_D(QGL2PaintEngineEx); - QTime startTime = QTime::currentTime(); + if (brush.style() == Qt::NoBrush) + return; + ensureActive(); d->setBrush(&brush); d->fill(path); d->setBrush(&(state()->brush)); // reset back to the state's brush @@ -775,6 +745,8 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) if (pen.style() == Qt::NoPen) return; + ensureActive(); + if ( (pen.isCosmetic() && (pen.style() == Qt::SolidLine)) && (pen.widthF() < 2.5f) ) { // We only handle solid, cosmetic pens with a width of 1 pixel @@ -790,7 +762,6 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) d->setBrush(&(state()->brush)); } else return QPaintEngineEx::stroke(path, pen); - } void QGL2PaintEngineEx::penChanged() @@ -819,7 +790,6 @@ void QGL2PaintEngineEx::opacityChanged() Q_D(QGL2PaintEngineEx); Q_ASSERT(d->shaderManager); - d->shaderManager->setUseGlobalOpacity(state()->opacity > 0.999); d->brushUniformsDirty = true; } @@ -845,45 +815,42 @@ void QGL2PaintEngineEx::transformChanged() void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, const QRectF & src) { Q_D(QGL2PaintEngineEx); - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); + ensureActive(); + d->transferMode(ImageDrawingMode); - d->ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true); + QGLContext *ctx = d->ctx; + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true); //FIXME: we should use hasAlpha() instead, but that's SLOW at the moment - if ((state()->opacity < 0.99f) || pixmap.hasAlphaChannel()) - glEnable(GL_BLEND); - else - glDisable(GL_BLEND); - - d->drawTexture(dest, src, pixmap.width(), pixmap.height()); + d->drawTexture(dest, src, pixmap.size(), !pixmap.hasAlphaChannel()); } void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src, Qt::ImageConversionFlags) { Q_D(QGL2PaintEngineEx); - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); - d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); + ensureActive(); + d->transferMode(ImageDrawingMode); - if ((state()->opacity < 0.99f) || image.hasAlphaChannel()) - glEnable(GL_BLEND); - else - glDisable(GL_BLEND); + QGLContext *ctx = d->ctx; + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); - d->drawTexture(dest, src, image.width(), image.height()); + d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); } void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem) { - QOpenGLPaintEngineState *s = state(); + Q_D(QGL2PaintEngineEx); + + ensureActive(); + QOpenGL2PaintEngineState *s = state(); const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); bool drawCached = true; - if (state()->pen.brush().style() != Qt::SolidPattern) - drawCached = false; - if (s->matrix.type() > QTransform::TxTranslate) drawCached = false; @@ -892,17 +859,19 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem drawCached = false; if (drawCached) { - drawCachedGlyphs(p, ti); + d->drawCachedGlyphs(p, ti); return; } QPaintEngineEx::drawTextItem(p, ti); } -void QGL2PaintEngineEx::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti) +void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti) { - Q_D(QGL2PaintEngineEx); - QOpenGLPaintEngineState *s = state(); + transferMode(TextDrawingMode); + + Q_Q(QGL2PaintEngineEx); + QOpenGL2PaintEngineState *s = q->state(); QVarLengthArray<QFixedPoint> positions; QVarLengthArray<glyph_t> glyphs; @@ -910,10 +879,22 @@ void QGL2PaintEngineEx::drawCachedGlyphs(const QPointF &p, const QTextItemInt &t matrix.translate(p.x(), p.y()); ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : QFontEngineGlyphCache::Raster_A8; + GLenum maskFormat = GL_RGBA; + if (glyphType == QFontEngineGlyphCache::Raster_A8) { + shaderManager->setMaskType(QGLEngineShaderManager::PixelMask); +// maskFormat = GL_ALPHA; + } + else if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) + shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMask); + //### TODO: Gamma correction + shaderManager->setTextureCoordsEnabled(true); + + QImageTextureGlyphCache *cache = (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix); if (!cache) { @@ -926,66 +907,46 @@ void QGL2PaintEngineEx::drawCachedGlyphs(const QPointF &p, const QTextItemInt &t const QImage &image = cache->image(); int margin = cache->glyphMargin(); - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); - d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); - - glEnable(GL_BLEND); - - d->shaderManager->textShader()->use(); - d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); - - if (d->compositionModeDirty) - d->updateCompositionMode(); - - if (d->matrixDirty) - d->updateMatrix(); - - if (d->textShaderMatrixUniformDirty) { - d->shaderManager->textShader()->uniforms()[QLatin1String("pmvMatrix")] = d->pmvMatrix; - d->textShaderMatrixUniformDirty = false; - } - - d->shaderManager->textShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT; - QColor col = d->premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity); - d->shaderManager->textShader()->uniforms()[QLatin1String("fragmentColor")] = col; + if (image.isNull()) + return; GLfloat dx = 1.0 / image.width(); GLfloat dy = 1.0 / image.height(); - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); + QGLPoint *oldVertexCoordinateDataPtr = vertexCoordinateArray.data(); + QGLPoint *oldTextureCoordinateDataPtr = textureCoordinateArray.data(); + + vertexCoordinateArray.clear(); + textureCoordinateArray.clear(); + for (int i=0; i<glyphs.size(); ++i) { const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]); int x = positions[i].x.toInt() + c.baseLineX - margin; int y = positions[i].y.toInt() - c.baseLineY - margin; - QGLRect dest = QRectF(x, y, c.w, c.h); - QGLRect src = QRectF(c.x, c.y, c.w, c.h); + vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); + textureCoordinateArray.addRect(QRectF(c.x*dx, 1 - c.y*dy, c.w * dx, -c.h * dy)); + } - GLfloat vertexCoords[] = { - dest.left, dest.top, - dest.left, dest.bottom, - dest.right, dest.bottom, - dest.right, dest.top - }; + glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); + ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); + updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords); + QBrush pensBrush = q->state()->pen.brush(); + setBrush(&pensBrush); - QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy); + prepareForDraw(false); // Text always causes src pixels to be transparent - GLfloat textureCoords[] = { - srcTextureRect.left, srcTextureRect.top, - srcTextureRect.left, srcTextureRect.bottom, - srcTextureRect.right, srcTextureRect.bottom, - srcTextureRect.right, srcTextureRect.top - }; + shaderManager->currentProgram()->setUniformValue("maskTexture", QT_MASK_TEXTURE_UNIT); - glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); + if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr) + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); + if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr) + glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); + + setBrush(&(q->state()->brush)); //### } bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) @@ -993,15 +954,30 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) Q_D(QGL2PaintEngineEx); // qDebug("QGL2PaintEngineEx::begin()"); + d->drawable.setDevice(pdev); + d->ctx = d->drawable.context(); + + if (d->ctx->d_ptr->active_engine) { + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(d->ctx->d_ptr->active_engine); + QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr); + p->transferMode(BrushDrawingMode); + p->drawable.doneCurrent(); + } + + d->ctx->d_ptr->active_engine = this; + + d->drawable.makeCurrent(); + QSize sz = d->drawable.size(); + d->width = sz.width(); + d->height = sz.height(); + d->mode = BrushDrawingMode; - QGLWidget* widget = static_cast<QGLWidget*>(pdev); - d->ctx = const_cast<QGLContext*>(widget->context()); - d->ctx->makeCurrent(); - d->width = widget->width(); - d->height = widget->height(); +#if !defined(QT_OPENGL_ES_2) + qt_resolve_version_2_0_functions(d->ctx); +#endif if (!d->shaderManager) - d->shaderManager = new QGLPEXShaderManager(d->ctx); + d->shaderManager = new QGLEngineShaderManager(d->ctx); glViewport(0, 0, d->width, d->height); @@ -1020,17 +996,82 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->use_system_clip = !systemClip().isEmpty(); glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + + QGLPixmapData *source = d->drawable.copyOnBegin(); + if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) { + if (d->drawable.hasTransparentBackground()) + glClearColor(0.0, 0.0, 0.0, 0.0); + else { + const QColor &c = d->drawable.backgroundColor(); + float alpha = c.alphaF(); + glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); + } + glClear(GL_COLOR_BUFFER_BIT); + } else if (source) { + QGLContext *ctx = d->ctx; + + d->transferMode(ImageDrawingMode); + + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + source->bind(false); + + QRect rect(0, 0, source->width(), source->height()); + d->drawTexture(QRectF(rect), QRectF(rect), rect.size(), true); + } + updateClipRegion(QRegion(), Qt::NoClip); return true; } bool QGL2PaintEngineEx::end() { Q_D(QGL2PaintEngineEx); - d->ctx->swapBuffers(); + QGLContext *ctx = d->ctx; + if (ctx->d_ptr->active_engine != this) { + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine); + if (engine && engine->isActive()) { + QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr); + p->transferMode(BrushDrawingMode); + p->drawable.doneCurrent(); + } + d->drawable.makeCurrent(); + } + + glUseProgram(0); + d->transferMode(BrushDrawingMode); + d->drawable.swapBuffers(); + d->drawable.doneCurrent(); + d->ctx->d_ptr->active_engine = 0; + return false; } +void QGL2PaintEngineEx::ensureActive() +{ + Q_D(QGL2PaintEngineEx); + QGLContext *ctx = d->ctx; + + if (isActive() && ctx->d_ptr->active_engine != this) { + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine); + if (engine && engine->isActive()) { + QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr); + p->transferMode(BrushDrawingMode); + p->drawable.doneCurrent(); + } + d->drawable.makeCurrent(); + + ctx->d_ptr->active_engine = this; + + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + + glViewport(0, 0, d->width, d->height); + setState(state()); + d->updateDepthClip(); + } +} + /////////////////////////////////// State/Clipping stolen from QOpenGLPaintEngine ////////////////////////////////////////// @@ -1161,14 +1202,19 @@ void QGL2PaintEngineEx::updateClipRegion(const QRegion &clipRegion, Qt::ClipOper state()->hasClipping = op != Qt::NoClip || d->use_system_clip; } - if (state()->hasClipping && state()->clipRegion.rects().size() == 1) - state()->fastClip = state()->clipRegion.rects().at(0); - else - state()->fastClip = QRect(); - d->updateDepthClip(); } +void QGL2PaintEngineExPrivate::systemStateChanged() +{ + Q_Q(QGL2PaintEngineEx); + use_system_clip = !systemClip.isEmpty(); + + if (q->painter()->hasClipping()) + q->updateClipRegion(q->painter()->clipRegion(), Qt::ReplaceClip); + else + q->updateClipRegion(QRegion(), Qt::NoClip); +} void QGL2PaintEngineExPrivate::updateDepthClip() { @@ -1176,20 +1222,17 @@ void QGL2PaintEngineExPrivate::updateDepthClip() Q_Q(QGL2PaintEngineEx); + q->ensureActive(); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); if (!q->state()->hasClipping) return; - QRect fastClip; - if (q->state()->clipEnabled) { - fastClip = q->state()->fastClip; - } else if (use_system_clip && q->systemClip().rects().count() == 1) { - fastClip = q->systemClip().rects().at(0); - } + const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects(); + if (rects.size() == 1) { + QRect fastClip = rects.at(0); - if (!fastClip.isEmpty()) { glEnable(GL_SCISSOR_TEST); const int left = fastClip.left(); @@ -1201,12 +1244,11 @@ void QGL2PaintEngineExPrivate::updateDepthClip() return; } - glClearDepthf(0x0); + glClearDepth(0x0); glDepthMask(true); glClear(GL_DEPTH_BUFFER_BIT); - glClearDepthf(0x1); + glClearDepth(0x1); - const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects(); glEnable(GL_SCISSOR_TEST); for (int i = 0; i < rects.size(); ++i) { QRect rect = rects.at(i); @@ -1229,50 +1271,57 @@ void QGL2PaintEngineExPrivate::updateDepthClip() -void QGL2PaintEngineEx::setState(QPainterState *s) +void QGL2PaintEngineEx::setState(QPainterState *new_state) { // qDebug("QGL2PaintEngineEx::setState()"); Q_D(QGL2PaintEngineEx); + + QOpenGL2PaintEngineState *s = static_cast<QOpenGL2PaintEngineState *>(new_state); + + QOpenGL2PaintEngineState *old_state = state(); + const bool needsDepthClipUpdate = !old_state + || s->clipEnabled != old_state->clipEnabled + || (s->clipEnabled && s->clipRegion != old_state->clipRegion); + QPaintEngineEx::setState(s); - d->updateDepthClip(); + if (needsDepthClipUpdate) + d->updateDepthClip(); d->matrixDirty = true; d->compositionModeDirty = true; d->brushTextureDirty = true; d->brushUniformsDirty = true; d->simpleShaderMatrixUniformDirty = true; - d->brushShaderMatrixUniformDirty = true; - d->imageShaderMatrixUniformDirty = true; - d->textShaderMatrixUniformDirty = true; + d->shaderMatrixUniformDirty = true; } QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const { - QOpenGLPaintEngineState *s; + QOpenGL2PaintEngineState *s; if (!orig) - s = new QOpenGLPaintEngineState(); + s = new QOpenGL2PaintEngineState(); else - s = new QOpenGLPaintEngineState(*static_cast<QOpenGLPaintEngineState *>(orig)); + s = new QOpenGL2PaintEngineState(*static_cast<QOpenGL2PaintEngineState *>(orig)); return s; } -QOpenGLPaintEngineState::QOpenGLPaintEngineState(QOpenGLPaintEngineState &other) +QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other) : QPainterState(other) { clipRegion = other.clipRegion; hasClipping = other.hasClipping; - fastClip = other.fastClip; } -QOpenGLPaintEngineState::QOpenGLPaintEngineState() +QOpenGL2PaintEngineState::QOpenGL2PaintEngineState() { hasClipping = false; } -QOpenGLPaintEngineState::~QOpenGLPaintEngineState() +QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() { } +QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index ce66e4b..dececa3 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -53,21 +53,32 @@ // We mean it. // +#include <QDebug> + #include <private/qpaintengineex_p.h> +#include <private/qglengineshadermanager_p.h> +#include <private/qgl2pexvertexarray_p.h> + +enum EngineMode { + ImageDrawingMode, + TextDrawingMode, + BrushDrawingMode +}; + +QT_BEGIN_NAMESPACE class QGL2PaintEngineExPrivate; -class QOpenGLPaintEngineState : public QPainterState +class QOpenGL2PaintEngineState : public QPainterState { public: - QOpenGLPaintEngineState(QOpenGLPaintEngineState &other); - QOpenGLPaintEngineState(); - ~QOpenGLPaintEngineState(); + QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other); + QOpenGL2PaintEngineState(); + ~QOpenGL2PaintEngineState(); QRegion clipRegion; bool hasClipping; - QRect fastClip; }; @@ -81,6 +92,8 @@ public: bool begin(QPaintDevice *device); bool end(); + void ensureActive(); + virtual void fill(const QVectorPath &path, const QBrush &brush); virtual void stroke(const QVectorPath &path, const QPen &pen); virtual void clip(const QVectorPath &path, Qt::ClipOperation op); @@ -100,19 +113,17 @@ public: virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags = Qt::AutoColor); virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); - void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti); Type type() const { return OpenGL; } - // State stuff is just for clipping and ripped off from QGLPaintEngine void setState(QPainterState *s); QPainterState *createState(QPainterState *orig) const; - inline QOpenGLPaintEngineState *state() { - return static_cast<QOpenGLPaintEngineState *>(QPaintEngineEx::state()); + inline QOpenGL2PaintEngineState *state() { + return static_cast<QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); } - inline const QOpenGLPaintEngineState *state() const { - return static_cast<const QOpenGLPaintEngineState *>(QPaintEngineEx::state()); + inline const QOpenGL2PaintEngineState *state() const { + return static_cast<const QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); } void updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op); @@ -120,6 +131,86 @@ private: Q_DISABLE_COPY(QGL2PaintEngineEx) }; +class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate +{ + Q_DECLARE_PUBLIC(QGL2PaintEngineEx) +public: + QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) : + q(q_ptr), + width(0), height(0), + ctx(0), + currentBrush( &(q->state()->brush) ), + inverseScale(1), + shaderManager(0) + { } + + ~QGL2PaintEngineExPrivate(); + + void updateBrushTexture(); + void updateBrushUniforms(); + void updateMatrix(); + void updateCompositionMode(); + void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform); + + void setBrush(const QBrush* brush); + + void transferMode(EngineMode newMode); + + // fill, drawOutline, drawTexture & drawCachedGlyphs are the rendering entry points: + void fill(const QVectorPath &path); + void drawOutline(const QVectorPath& path); + void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque); + void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti); + + void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive); + // ^ draws whatever is in the vertex array + void composite(const QGLRect& boundingRect); + // ^ Composites the bounding rect onto dest buffer + void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill); + // ^ Calls drawVertexArrays to render into stencil buffer + void cleanStencilBuffer(const QGLRect& area); + + void prepareForDraw(bool srcPixelsAreOpaque); + + inline void useSimpleShader(); + inline QColor premultiplyColor(QColor c, GLfloat opacity); + + QGL2PaintEngineEx* q; + QGLDrawable drawable; + int width, height; + QGLContext *ctx; + + EngineMode mode; + + // Dirty flags + bool matrixDirty; // Implies matrix uniforms are also dirty + bool compositionModeDirty; + bool brushTextureDirty; + bool brushUniformsDirty; + bool simpleShaderMatrixUniformDirty; + bool shaderMatrixUniformDirty; + bool stencilBuferDirty; + + const QBrush* currentBrush; // May not be the state's brush! + + GLfloat inverseScale; + + QGL2PEXVertexArray vertexCoordinateArray; + QGL2PEXVertexArray textureCoordinateArray; + + GLfloat staticVertexCoordinateArray[8]; + GLfloat staticTextureCoordinateArray[8]; + + GLfloat pmvMatrix[4][4]; + + QGLEngineShaderManager* shaderManager; + + // Clipping & state stuff stolen from QOpenGLPaintEngine: + void updateDepthClip(); + void systemStateChanged(); + uint use_system_clip : 1; +}; +QT_END_NAMESPACE #endif diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 78aaddb..73af174 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -13,18 +13,15 @@ include(../qbase.pri) !win32:!embedded:!mac:CONFIG += x11 contains(QT_CONFIG, opengl):CONFIG += opengl contains(QT_CONFIG, opengles1):CONFIG += opengles1 +contains(QT_CONFIG, opengles1):CONFIG += opengles1cl contains(QT_CONFIG, opengles2):CONFIG += opengles2 -!contains(QT_CONFIG, opengles2) { - HEADERS += qgraphicssystem_gl_p.h qwindowsurface_gl_p.h qpixmapdata_gl_p.h - SOURCES += qgraphicssystem_gl.cpp qwindowsurface_gl.cpp qpixmapdata_gl.cpp -} - HEADERS += qgl.h \ qgl_p.h \ qglcolormap.h \ qglpixelbuffer.h \ qglframebufferobject.h \ + qglextensions_p.h SOURCES += qgl.cpp \ qglcolormap.cpp \ @@ -33,25 +30,34 @@ SOURCES += qgl.cpp \ qglextensions.cpp \ !contains(QT_CONFIG, opengles2) { - HEADERS += qpaintengine_opengl_p.h qglpixmapfilter_p.h - SOURCES += qpaintengine_opengl.cpp qglpixmapfilter.cpp + HEADERS += qpaintengine_opengl_p.h + SOURCES += qpaintengine_opengl.cpp } -contains(QT_CONFIG, opengles2) { - SOURCES += gl2paintengineex/qglgradientcache.cpp \ - gl2paintengineex/qglpexshadermanager.cpp \ - gl2paintengineex/qglshader.cpp \ +!contains(QT_CONFIG, opengles1):!contains(QT_CONFIG, opengles1cl) { + HEADERS += qglshaderprogram.h \ + qglpixmapfilter_p.h \ + qgraphicssystem_gl_p.h \ + qwindowsurface_gl_p.h \ + qpixmapdata_gl_p.h \ + gl2paintengineex/qglgradientcache_p.h \ + gl2paintengineex/qglengineshadermanager_p.h \ + gl2paintengineex/qgl2pexvertexarray_p.h \ + gl2paintengineex/qpaintengineex_opengl2_p.h \ + gl2paintengineex/qglengineshadersource_p.h + + SOURCES += qglshaderprogram.cpp \ + qglpixmapfilter.cpp \ + qgraphicssystem_gl.cpp \ + qwindowsurface_gl.cpp \ + qpixmapdata_gl.cpp \ + gl2paintengineex/qglgradientcache.cpp \ + gl2paintengineex/qglengineshadermanager.cpp \ gl2paintengineex/qgl2pexvertexarray.cpp \ gl2paintengineex/qpaintengineex_opengl2.cpp - HEADERS += gl2paintengineex/qglgradientcache_p.h \ - gl2paintengineex/qglpexshadermanager_p.h \ - gl2paintengineex/qglshader_p.h \ - gl2paintengineex/qgl2pexvertexarray_p.h \ - gl2paintengineex/qpaintengineex_opengl2_p.h } - x11 { contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles1cl)|contains(QT_CONFIG, opengles2) { SOURCES += qgl_x11egl.cpp \ diff --git a/src/opengl/qegl.cpp b/src/opengl/qegl.cpp index 165a0f3..f1ae4ed 100644 --- a/src/opengl/qegl.cpp +++ b/src/opengl/qegl.cpp @@ -119,7 +119,7 @@ bool QEglContext::chooseConfig if (red == props.value(EGL_RED_SIZE) && green == props.value(EGL_GREEN_SIZE) && blue == props.value(EGL_BLUE_SIZE) && - (props.value(EGL_ALPHA_SIZE) == EGL_DONT_CARE || + (props.value(EGL_ALPHA_SIZE) == 0 || alpha == props.value(EGL_ALPHA_SIZE))) { cfg = configs[index]; delete [] configs; @@ -405,7 +405,54 @@ int QEglProperties::value(int name) const if (props[index] == name) return props[index + 1]; } - return EGL_DONT_CARE; + + // If the attribute has not been explicitly set, return the EGL default + // The following defaults were taken from the EGL 1.4 spec: + switch(name) { + case EGL_BUFFER_SIZE: return 0; + case EGL_RED_SIZE: return 0; + case EGL_GREEN_SIZE: return 0; + case EGL_BLUE_SIZE: return 0; + case EGL_LUMINANCE_SIZE: return 0; + case EGL_ALPHA_SIZE: return 0; + case EGL_ALPHA_MASK_SIZE: return 0; + case EGL_BIND_TO_TEXTURE_RGB: return EGL_DONT_CARE; + case EGL_BIND_TO_TEXTURE_RGBA: return EGL_DONT_CARE; + case EGL_COLOR_BUFFER_TYPE: return EGL_RGB_BUFFER; + case EGL_CONFIG_CAVEAT: return EGL_DONT_CARE; + case EGL_CONFIG_ID: return EGL_DONT_CARE; + case EGL_DEPTH_SIZE: return 0; + case EGL_LEVEL: return 0; + case EGL_NATIVE_RENDERABLE: return EGL_DONT_CARE; + case EGL_NATIVE_VISUAL_TYPE: return EGL_DONT_CARE; + case EGL_MAX_SWAP_INTERVAL: return EGL_DONT_CARE; + case EGL_MIN_SWAP_INTERVAL: return EGL_DONT_CARE; + case EGL_RENDERABLE_TYPE: return EGL_OPENGL_ES_BIT; + case EGL_SAMPLE_BUFFERS: return 0; + case EGL_SAMPLES: return 0; + case EGL_STENCIL_SIZE: return 0; + case EGL_SURFACE_TYPE: return EGL_WINDOW_BIT; + case EGL_TRANSPARENT_TYPE: return EGL_NONE; + case EGL_TRANSPARENT_RED_VALUE: return EGL_DONT_CARE; + case EGL_TRANSPARENT_GREEN_VALUE: return EGL_DONT_CARE; + case EGL_TRANSPARENT_BLUE_VALUE: return EGL_DONT_CARE; + +#if defined(EGL_VERSION_1_3) + case EGL_CONFORMANT: return 0; + case EGL_MATCH_NATIVE_PIXMAP: return EGL_NONE; +#endif + + case EGL_MAX_PBUFFER_HEIGHT: + case EGL_MAX_PBUFFER_WIDTH: + case EGL_MAX_PBUFFER_PIXELS: + case EGL_NATIVE_VISUAL_ID: + case EGL_NONE: + qWarning("QEglProperties::value() - Attibute %d does not affect config selection", name); + return EGL_DONT_CARE; + default: + qWarning("QEglProperties::value() - Attibute %d is unknown in EGL <=1.4", name); + return EGL_DONT_CARE; + } } // Set the value associated with a property, replacing an existing @@ -535,7 +582,7 @@ QString QEglProperties::toString() const if (val != EGL_DONT_CARE) { str += QLatin1String("id="); str += QString::number(val); - str += QLatin1String(" "); + str += QLatin1Char(' '); } #ifdef EGL_RENDERABLE_TYPE @@ -570,11 +617,11 @@ QString QEglProperties::toString() const bufferSize = EGL_DONT_CARE; str += QLatin1String(" rgba="); str += QString::number(red); - str += QLatin1String(","); + str += QLatin1Char(','); str += QString::number(green); - str += QLatin1String(","); + str += QLatin1Char(','); str += QString::number(blue); - str += QLatin1String(","); + str += QLatin1Char(','); str += QString::number(alpha); if (bufferSize != EGL_DONT_CARE) { // Only report buffer size if different than r+g+b+a. @@ -593,13 +640,13 @@ QString QEglProperties::toString() const #endif val = value(EGL_DEPTH_SIZE); - if (val != EGL_DONT_CARE) { + if (val != 0) { addTag(str, QLatin1String(" depth=")); str += QString::number(val); } val = value(EGL_STENCIL_SIZE); - if (val != EGL_DONT_CARE) { + if (val != 0) { addTag(str, QLatin1String(" stencil=")); str += QString::number(val); } @@ -649,7 +696,7 @@ QString QEglProperties::toString() const } val = value(EGL_LEVEL); - if (val != EGL_DONT_CARE) { + if (val != 0) { addTag(str, QLatin1String(" level=")); str += QString::number(val); } @@ -661,7 +708,7 @@ QString QEglProperties::toString() const if (height != EGL_DONT_CARE || width != EGL_DONT_CARE) { addTag(str, QLatin1String(" max-pbuffer-size=")); str += QString::number(width); - str += QLatin1String("x"); + str += QLatin1Char('x'); str += QString::number(height); if (pixels != (width * height)) { addTag(str, QLatin1String(" max-pbuffer-pixels=")); @@ -700,13 +747,13 @@ QString QEglProperties::toString() const #endif val = value(EGL_SAMPLES); - if (val != EGL_DONT_CARE) { + if (val != 0) { addTag(str, QLatin1String(" samples=")); str += QString::number(val); } val = value(EGL_SAMPLE_BUFFERS); - if (val != EGL_DONT_CARE) { + if (val != 0) { addTag(str, QLatin1String(" sample-buffers=")); str += QString::number(val); } @@ -715,9 +762,9 @@ QString QEglProperties::toString() const if (val == EGL_TRANSPARENT_RGB) { addTag(str, QLatin1String(" transparent-rgb=")); str += QString::number(value(EGL_TRANSPARENT_RED_VALUE)); - str += QLatin1String(","); + str += QLatin1Char(','); str += QString::number(value(EGL_TRANSPARENT_GREEN_VALUE)); - str += QLatin1String(","); + str += QLatin1Char(','); str += QString::number(value(EGL_TRANSPARENT_BLUE_VALUE)); } @@ -755,7 +802,7 @@ QString QEglProperties::toString() const #ifdef EGL_LUMINANCE_SIZE val = value(EGL_LUMINANCE_SIZE); - if (val != EGL_DONT_CARE) { + if (val != 0) { addTag(str, QLatin1String(" luminance=")); str += QString::number(val); } @@ -763,7 +810,7 @@ QString QEglProperties::toString() const #ifdef EGL_ALPHA_MASK_SIZE val = value(EGL_ALPHA_MASK_SIZE); - if (val != EGL_DONT_CARE) { + if (val != 0) { addTag(str, QLatin1String(" alpha-mask=")); str += QString::number(val); } @@ -771,7 +818,7 @@ QString QEglProperties::toString() const #ifdef EGL_CONFORMANT val = value(EGL_CONFORMANT); - if (val != EGL_DONT_CARE) { + if (val != 0) { if (val) addTag(str, QLatin1String(" conformant=true")); else diff --git a/src/opengl/qegl_x11egl.cpp b/src/opengl/qegl_x11egl.cpp index 8efe7e7..c703900 100644 --- a/src/opengl/qegl_x11egl.cpp +++ b/src/opengl/qegl_x11egl.cpp @@ -42,6 +42,7 @@ #include <QtGui/qpaintdevice.h> #include <QtGui/qpixmap.h> #include <QtGui/qwidget.h> +#include <QtCore/qdebug.h> #include "qegl_p.h" #if defined(QT_OPENGL_ES) || defined(QT_OPENVG) @@ -80,8 +81,10 @@ bool QEglContext::createSurface(QPaintDevice *device) surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); else surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); + if (surf == EGL_NO_SURFACE) { - qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); + qWarning() << "QEglContext::createSurface(): Unable to create EGL surface:" + << errorString(eglGetError()); return false; } return true; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 2d58084..60039eb 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -65,15 +65,20 @@ #include "qimage.h" #include "qgl_p.h" -#if defined(QT_OPENGL_ES_2) #include "gl2paintengineex/qpaintengineex_opengl2_p.h" -#else + +#ifndef QT_OPENGL_ES_2 #include <private/qpaintengine_opengl_p.h> #endif +#include <qglpixelbuffer.h> +#include <qglframebufferobject.h> + #include <private/qimage_p.h> #include <private/qpixmapdata_p.h> #include <private/qpixmapdata_gl_p.h> +#include <private/qglpixelbuffer_p.h> +#include <private/qwindowsurface_gl_p.h> #include "qcolormap.h" #include "qcache.h" #include "qfile.h" @@ -1290,6 +1295,7 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format) eglContext = 0; #endif pbo = 0; + fbo = 0; crWin = false; initDone = false; sharing = false; @@ -1298,6 +1304,7 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format) version_flags_cached = false; version_flags = QGLFormat::OpenGL_Version_None; current_fbo = 0; + active_engine = 0; } QGLContext* QGLContext::currentCtx = 0; @@ -1308,12 +1315,8 @@ QGLContext* QGLContext::currentCtx = 0; QGLFramebufferObject::toImage() */ -QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) +static void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, bool include_alpha) { - QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32); - int w = size.width(); - int h = size.height(); - glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { // OpenGL gives RGBA; Qt wants ARGB uint *p = (uint*)img.bits(); @@ -1344,7 +1347,30 @@ QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include } } - return img.mirrored(); + img = img.mirrored(); +} + +QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) +{ + QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32); + int w = size.width(); + int h = size.height(); + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); + convertFromGLImage(img, w, h, alpha_format, include_alpha); + return img; +} + +QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha) +{ + QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32); + int w = size.width(); + int h = size.height(); +#if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + //### glGetTexImage not in GL ES 2.0, need to do something else here! + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); +#endif + convertFromGLImage(img, w, h, alpha_format, include_alpha); + return img; } // returns the highest number closest to v, which is a power of 2 @@ -1548,7 +1574,7 @@ void QGLContextPrivate::cleanup() Q_Q(QGLContext); if (pbo) { QGLContext *ctx = q; - glDeleteBuffersARB(1, &pbo); + glDeleteBuffers(1, &pbo); pbo = 0; } } @@ -1813,7 +1839,7 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint use_pbo = qt_resolve_buffer_extensions(ctx); if (use_pbo && pbo == 0) - glGenBuffersARB(1, &pbo); + glGenBuffers(1, &pbo); } // the GL_BGRA format is only present in GL version >= 1.2 @@ -1864,8 +1890,8 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint uchar *ptr = 0; if (use_pbo) { - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo); - glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, img.width() * img.height() * 4, 0, GL_STREAM_DRAW_ARB); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo); + glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, img.width() * img.height() * 4, 0, GL_STREAM_DRAW_ARB); ptr = reinterpret_cast<uchar *>(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB)); } @@ -1892,7 +1918,7 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint } if (use_pbo) - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); // this assumes the size of a texture is always smaller than the max cache size int cost = img.width()*img.height()*4/1024; @@ -1944,11 +1970,13 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint /*! \internal */ GLuint QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean) { -#if !defined(QT_OPENGL_ES_2) - if (target == qt_gl_preferredTextureTarget() && pixmap.pixmapData()->classId() == QPixmapData::OpenGLClass) { - const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pixmap.pixmapData()); + Q_Q(QGLContext); + QPixmapData *pd = pixmap.pixmapData(); +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + if (target == GL_TEXTURE_2D && pd->classId() == QPixmapData::OpenGLClass) { + const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pd); - if (data->isValidContext(QGLContext::currentContext())) + if (data->isValidContext(q)) return data->bind(); } #endif @@ -2100,12 +2128,34 @@ void QGLContext::deleteTexture(QMacCompatGLuint id) } #endif -// qpaintengine_opengl.cpp -#if !defined(QT_OPENGL_ES_2) -extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array); -#else -void qt_add_rect_to_array(const QRectF &r, q_vertexType *array) {}; -#endif +void qt_add_rect_to_array(const QRectF &r, q_vertexType *array) +{ + qreal left = r.left(); + qreal right = r.right(); + qreal top = r.top(); + qreal bottom = r.bottom(); + + array[0] = f2vt(left); + array[1] = f2vt(top); + array[2] = f2vt(right); + array[3] = f2vt(top); + array[4] = f2vt(right); + array[5] = f2vt(bottom); + array[6] = f2vt(left); + array[7] = f2vt(bottom); +} + +void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array) +{ + array[0] = f2vt(x1); + array[1] = f2vt(y1); + array[2] = f2vt(x2); + array[3] = f2vt(y1); + array[4] = f2vt(x2); + array[5] = f2vt(y2); + array[6] = f2vt(x1); + array[7] = f2vt(y2); +} static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint textureHeight, GLenum textureTarget) { @@ -2558,6 +2608,42 @@ const QGLContext* QGLContext::currentContext() visual. On other platforms it may work differently. */ +/*! \fn int QGLContext::choosePixelFormat(void* dummyPfd, HDC pdc) + + \bold{Win32 only:} This virtual function chooses a pixel format + that matches the OpenGL \link setFormat() format\endlink. + Reimplement this function in a subclass if you need a custom + context. + + \warning The \a dummyPfd pointer and \a pdc are used as a \c + PIXELFORMATDESCRIPTOR*. We use \c void to avoid using + Windows-specific types in our header files. + + \sa chooseContext() +*/ + +/*! \fn void *QGLContext::chooseVisual() + + \bold{X11 only:} This virtual function tries to find a visual that + matches the format, reducing the demands if the original request + cannot be met. + + The algorithm for reducing the demands of the format is quite + simple-minded, so override this method in your subclass if your + application has spcific requirements on visual selection. + + \sa chooseContext() +*/ + +/*! \fn void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth) + \internal + + \bold{X11 only:} This virtual function chooses a visual that matches + the OpenGL \link format() format\endlink. Reimplement this function + in a subclass if you need a custom visual. + + \sa chooseContext() +*/ /*! \fn void QGLContext::reset() @@ -2642,7 +2728,7 @@ const QGLContext* QGLContext::currentContext() \i paintGL() - Renders the OpenGL scene. Gets called whenever the widget needs to be updated. \i resizeGL() - Sets up the OpenGL viewport, projection, etc. Gets - called whenever the the widget has been resized (and also when it + called whenever the widget has been resized (and also when it is shown for the first time because all newly created widgets get a resize event automatically). \i initializeGL() - Sets up the OpenGL rendering context, defines display @@ -3074,11 +3160,10 @@ void QGLWidget::setFormat(const QGLFormat &format) */ /* - \obsolete - \fn void QGLWidget::setContext(QGLContext *context, - const QGLContext* shareContext, - bool deleteOldContext) + const QGLContext* shareContext, + bool deleteOldContext) + \obsolete Sets a new context for this widget. The QGLContext \a context must be created using \e new. QGLWidget will delete \a context when @@ -3228,9 +3313,10 @@ void QGLWidget::resizeOverlayGL(int, int) { } - +/*! \fn bool QGLWidget::event(QEvent *e) + \reimp +*/ #if !defined(Q_OS_WINCE) && !defined(Q_WS_QWS) -/*! \reimp */ bool QGLWidget::event(QEvent *e) { Q_D(QGLWidget); @@ -3256,7 +3342,7 @@ bool QGLWidget::event(QEvent *e) glFinish(); doneCurrent(); } else if (e->type() == QEvent::ParentChange) { - if (d->glcx->d_func()->screen != d->xinfo.screen()) { + if (d->glcx->d_func()->screen != d->xinfo.screen() || testAttribute(Qt::WA_TranslucentBackground)) { setContext(new QGLContext(d->glcx->requestedFormat(), this)); // ### recreating the overlay isn't supported atm } @@ -4112,14 +4198,16 @@ void QGLWidget::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QM } #endif -#if defined(QT_OPENGL_ES_2) -Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_engine) -#else +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_2_engine) +#endif + +#ifndef QT_OPENGL_ES_2 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_engine) #endif #ifdef Q_WS_QWS -Q_OPENGL_EXPORT QOpenGLPaintEngine* qt_qgl_paint_engine() +Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine() { #if !defined(QT_OPENGL_ES_2) return qt_gl_engine(); @@ -4137,7 +4225,16 @@ Q_OPENGL_EXPORT QOpenGLPaintEngine* qt_qgl_paint_engine() */ QPaintEngine *QGLWidget::paintEngine() const { +#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) return qt_gl_engine(); +#elif defined(QT_OPENGL_ES_2) + return qt_gl_2_engine(); +#else + if (!qt_gl_preferGL2Engine()) + return qt_gl_engine(); + else + return qt_gl_2_engine(); +#endif } #ifdef QT3_SUPPORT @@ -4226,6 +4323,8 @@ void QGLExtensions::init_extensions() glExtensions |= FramebufferObject; glExtensions |= GenerateMipmap; #endif + if (extensions.contains(QLatin1String("EXT_framebuffer_blit"))) + glExtensions |= FramebufferBlit; QGLContext cx(QGLFormat::defaultFormat()); if (glExtensions & TextureCompression) { @@ -4266,7 +4365,7 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name() { if (qt_gl_lib_name()->isNull()) { #if defined(Q_WS_X11) || defined(Q_WS_QWS) - return QString(QLatin1String("GL")); + return QLatin1String("GL"); #else // Q_WS_MAC return QLatin1String("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib"); #endif @@ -4275,4 +4374,226 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name() } #endif +void QGLDrawable::setDevice(QPaintDevice *pdev) +{ + wasBound = false; + widget = 0; + buffer = 0; + fbo = 0; +#ifdef Q_WS_QWS + wsurf = 0; +#endif + +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + if (pdev->devType() == QInternal::Pixmap) { + QPixmapData *data = static_cast<QPixmap *>(pdev)->pixmapData(); + Q_ASSERT(data->classId() == QPixmapData::OpenGLClass); + pixmapData = static_cast<QGLPixmapData *>(data); + + fbo = pixmapData->fbo(); + } +#else + Q_ASSERT(pdev->devType() != QInternal::Pixmap); +#endif + + if (pdev->devType() == QInternal::Widget) + widget = static_cast<QGLWidget *>(pdev); + else if (pdev->devType() == QInternal::Pbuffer) + buffer = static_cast<QGLPixelBuffer *>(pdev); + else if (pdev->devType() == QInternal::FramebufferObject) + fbo = static_cast<QGLFramebufferObject *>(pdev); +#ifdef Q_WS_QWS + else if (pdev->devType() == QInternal::UnknownDevice) + wsurf = static_cast<QWSGLPaintDevice*>(pdev)->windowSurface(); +#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + else if (pdev->devType() == QInternal::UnknownDevice) + wsurf = static_cast<QGLWindowSurface *>(pdev); +#endif +} + +void QGLDrawable::swapBuffers() +{ + if (widget) { + if (widget->autoBufferSwap()) + widget->swapBuffers(); +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + } else if (pixmapData) { + pixmapData->swapBuffers(); +#endif + } else { + glFlush(); + } +} + +void QGLDrawable::makeCurrent() +{ + previous_fbo = 0; + if (!pixmapData && !fbo) { + QGLContext *ctx = context(); + previous_fbo = ctx->d_ptr->current_fbo; + ctx->d_ptr->current_fbo = 0; + if (previous_fbo) + glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); + } + + if (widget) + widget->makeCurrent(); +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + else if (pixmapData) + pixmapData->makeCurrent(); +#endif + else if (buffer) + buffer->makeCurrent(); +#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) + else if (wsurf) + wsurf->context()->makeCurrent(); +#endif + else if (fbo) { + wasBound = fbo->isBound(); + if (!wasBound) + fbo->bind(); + } +} + +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +QGLPixmapData *QGLDrawable::copyOnBegin() const +{ + if (!pixmapData || pixmapData->isUninitialized()) + return 0; + return pixmapData; +} +#endif + +void QGLDrawable::doneCurrent() +{ +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + if (pixmapData) { + pixmapData->doneCurrent(); + return; + } +#endif + + if (previous_fbo) { + QGLContext *ctx = context(); + ctx->d_ptr->current_fbo = previous_fbo; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, previous_fbo); + } + + if (fbo && !wasBound) + fbo->release(); +} + +QSize QGLDrawable::size() const +{ + if (widget) { + return QSize(widget->d_func()->glcx->device()->width(), + widget->d_func()->glcx->device()->height()); +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + } else if (pixmapData) { + return pixmapData->size(); +#endif + } else if (buffer) { + return buffer->size(); + } else if (fbo) { + return fbo->size(); + } +#ifdef Q_WS_QWS + else if (wsurf) + return wsurf->window()->frameSize(); +#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + else if (wsurf) + return QSize(wsurf->width(), wsurf->height()); +#endif + return QSize(); +} + +QGLFormat QGLDrawable::format() const +{ + if (widget) + return widget->format(); + else if (buffer) + return buffer->format(); +#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) + else if (wsurf) + return wsurf->context()->format(); +#endif + else if (fbo && QGLContext::currentContext()) { + QGLFormat fmt = QGLContext::currentContext()->format(); + fmt.setStencil(fbo->attachment() == QGLFramebufferObject::CombinedDepthStencil); + fmt.setDepth(fbo->attachment() != QGLFramebufferObject::NoAttachment); + return fmt; + } + + return QGLFormat(); +} + +GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format) +{ + if (widget) + return widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true); + else if (buffer) + return buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true); + else if (fbo && QGLContext::currentContext()) + return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true); +#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) + else if (wsurf) + return wsurf->context()->d_func()->bindTexture(image, target, format, true); +#endif + return 0; +} + +GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) +{ + if (widget) + return widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true); + else if (buffer) + return buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true); + else if (fbo && QGLContext::currentContext()) + return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true); +#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) + else if (wsurf) + return wsurf->context()->d_func()->bindTexture(pixmap, target, format, true); +#endif + return 0; +} + +QColor QGLDrawable::backgroundColor() const +{ + if (widget) + return widget->palette().brush(widget->backgroundRole()).color(); + else if (pixmapData) + return pixmapData->fillColor(); + return QApplication::palette().brush(QPalette::Background).color(); +} + +bool QGLDrawable::hasTransparentBackground() const +{ + return widget && widget->testAttribute(Qt::WA_TranslucentBackground); +} + +QGLContext *QGLDrawable::context() const +{ + if (widget) + return widget->d_func()->glcx; + else if (buffer) + return buffer->d_func()->qctx; + else if (fbo) + return const_cast<QGLContext *>(QGLContext::currentContext()); +#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) + else if (wsurf) + return wsurf->context(); +#endif + return 0; +} + +bool QGLDrawable::autoFillBackground() const +{ + if (widget) + return widget->autoFillBackground(); + else if (pixmapData) + return pixmapData->needsFill(); + else + return false; +} + QT_END_NAMESPACE diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 32fbce2..19d779a 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -372,8 +372,8 @@ private: friend QGLContextPrivate *qt_phonon_get_dptr(const QGLContext *); #endif friend class QGLFramebufferObject; -#ifdef Q_WS_WIN friend class QGLFramebufferObjectPrivate; +#ifdef Q_WS_WIN friend bool qt_resolve_GLSL_functions(QGLContext *ctx); friend bool qt_createGLSLProgram(QGLContext *ctx, GLuint &program, const char *shader_src, GLuint &shader); #endif diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp index 98c5710..287c537 100644 --- a/src/opengl/qgl_egl.cpp +++ b/src/opengl/qgl_egl.cpp @@ -57,14 +57,14 @@ void qt_egl_set_format(QEglProperties& props, int deviceType, const QGLFormat& f // Set the pixel format to that contained in the QGLFormat // if the system hasn't already chosen a fixed format to // match the pixmap, widget, etc. - if (props.value(EGL_RED_SIZE) == EGL_DONT_CARE || f.redBufferSize() != -1) + if (props.value(EGL_RED_SIZE) == 0 || f.redBufferSize() != -1) props.setValue(EGL_RED_SIZE, f.redBufferSize() == -1 ? 1 : f.redBufferSize()); - if (props.value(EGL_GREEN_SIZE) == EGL_DONT_CARE || f.greenBufferSize() != -1) + if (props.value(EGL_GREEN_SIZE) == 0 || f.greenBufferSize() != -1) props.setValue(EGL_GREEN_SIZE, f.greenBufferSize() == -1 ? 1 : f.greenBufferSize()); - if (props.value(EGL_BLUE_SIZE) == EGL_DONT_CARE || f.blueBufferSize() != -1) + if (props.value(EGL_BLUE_SIZE) == 0 || f.blueBufferSize() != -1) props.setValue(EGL_BLUE_SIZE, f.blueBufferSize() == -1 ? 1 : f.blueBufferSize()); if (f.alpha()) { - if (props.value(EGL_ALPHA_SIZE) == EGL_DONT_CARE || f.alphaBufferSize() != -1) + if (props.value(EGL_ALPHA_SIZE) == 0 || f.alphaBufferSize() != -1) props.setValue(EGL_ALPHA_SIZE, f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize()); } diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 1214f20..b1a63b5 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -61,6 +61,10 @@ #include "QtCore/qhash.h" #include "private/qwidget_p.h" +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +#include "private/qpixmapdata_gl_p.h" +#endif + #ifndef QT_OPENGL_ES_1_CL #define q_vertexType float #define q_vertexTypeEnum GL_FLOAT @@ -239,6 +243,7 @@ public: QGLFormat glFormat; QGLFormat reqFormat; GLuint pbo; + GLuint fbo; uint valid : 1; uint sharing : 1; @@ -256,6 +261,7 @@ public: GLint max_texture_size; GLuint current_fbo; + QPaintEngine *active_engine; #ifdef Q_WS_WIN static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->extensionFuncs; } @@ -283,6 +289,54 @@ Q_SIGNALS: void aboutToDestroyContext(const QGLContext *context); }; +class QGLPixelBuffer; +class QGLFramebufferObject; +class QWSGLWindowSurface; +class QGLWindowSurface; +class QGLDrawable { +public: + QGLDrawable() : widget(0), buffer(0), fbo(0) +#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) + , wsurf(0) +#endif +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + , pixmapData(0) +#endif + {} + void setDevice(QPaintDevice *pdev); + void swapBuffers(); + void makeCurrent(); + void doneCurrent(); + QSize size() const; + QGLFormat format() const; + GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA); + GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA); + QColor backgroundColor() const; + QGLContext *context() const; + bool autoFillBackground() const; + bool hasTransparentBackground() const; + +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + QGLPixmapData *copyOnBegin() const; +#endif + +private: + bool wasBound; + QGLWidget *widget; + QGLPixelBuffer *buffer; + QGLFramebufferObject *fbo; +#ifdef Q_WS_QWS + QWSGLWindowSurface *wsurf; +#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + QGLWindowSurface *wsurf; +#endif + +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) + QGLPixmapData *pixmapData; +#endif + int previous_fbo; +}; + // GL extension definitions class QGLExtensions { public: @@ -298,7 +352,8 @@ public: StencilWrap = 0x00000100, PackedDepthStencil = 0x00000200, NVFloatBuffer = 0x00000400, - PixelBufferObject = 0x00000800 + PixelBufferObject = 0x00000800, + FramebufferBlit = 0x00001000 }; Q_DECLARE_FLAGS(Extensions, Extension) @@ -379,6 +434,16 @@ extern QOpenGLPaintEngine* qt_qgl_paint_engine(); extern EGLDisplay qt_qgl_egl_display(); #endif +inline bool qt_gl_preferGL2Engine() +{ +#if defined(QT_OPENGL_ES_2) + return true; +#else + return (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) + && !qgetenv("QT_GL_USE_OPENGL2ENGINE").isEmpty(); +#endif +} + inline GLenum qt_gl_preferredTextureFormat() { return QSysInfo::ByteOrder == QSysInfo::BigEndian ? GL_RGBA : GL_BGRA; @@ -386,12 +451,16 @@ inline GLenum qt_gl_preferredTextureFormat() inline GLenum qt_gl_preferredTextureTarget() { +#if defined(QT_OPENGL_ES_2) + return GL_TEXTURE_2D; +#else return (QGLExtensions::glExtensions & QGLExtensions::TextureRectangle) + && !qt_gl_preferGL2Engine() ? GL_TEXTURE_RECTANGLE_NV : GL_TEXTURE_2D; +#endif } - QT_END_NAMESPACE #endif // QGL_P_H diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp index bd8569a..217b0fc 100644 --- a/src/opengl/qgl_win.cpp +++ b/src/opengl/qgl_win.cpp @@ -884,19 +884,9 @@ static bool qLogEq(bool a, bool b) return (((!a) && (!b)) || (a && b)); } -/*! - \bold{Win32 only:} This virtual function chooses a pixel - format that matches the OpenGL \link setFormat() format\endlink. - Reimplement this function in a subclass if you need a custom - context. - - \warning The \a dummyPfd pointer and \a pdc are used as a \c - PIXELFORMATDESCRIPTOR*. We use \c void to avoid using - Windows-specific types in our header files. - - \sa chooseContext() -*/ - +/* + See qgl.cpp for qdoc comment. + */ int QGLContext::choosePixelFormat(void* dummyPfd, HDC pdc) { Q_D(QGLContext); diff --git a/src/opengl/qgl_wince.cpp b/src/opengl/qgl_wince.cpp index cb51598..7429071 100644 --- a/src/opengl/qgl_wince.cpp +++ b/src/opengl/qgl_wince.cpp @@ -552,9 +552,6 @@ void QGLWidgetPrivate::updateColormap() ReleaseDC(q->winId(), hdc); } -/*! - \reimp -\*/ bool QGLWidget::event(QEvent *e) { Q_D(QGLWidget); diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index 28c34de..28a50bd 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -433,7 +433,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) if (!d->gpm) return false; } - QString glxExt = QString(QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS))); + QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); if (glxExt.contains(QLatin1String("GLX_SGI_video_sync"))) { if (d->glFormat.swapInterval() == -1) d->glFormat.setSwapInterval(0); @@ -443,19 +443,9 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) return true; } - -/*! - \bold{X11 only:} This virtual function tries to find a - visual that matches the format, reducing the demands if the original - request cannot be met. - - The algorithm for reducing the demands of the format is quite - simple-minded, so override this method in your subclass if your - application has spcific requirements on visual selection. - - \sa chooseContext() -*/ - +/* + See qgl.cpp for qdoc comment. + */ void *QGLContext::chooseVisual() { Q_D(QGLContext); @@ -519,25 +509,28 @@ void *QGLContext::chooseVisual() return vis; } - -/*! - \internal - - \bold{X11 only:} This virtual function chooses a visual - that matches the OpenGL \link format() format\endlink. Reimplement this - function in a subclass if you need a custom visual. - - \sa chooseContext() -*/ - +/* + See qgl.cpp for qdoc comment. + */ void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth) { Q_D(QGLContext); - int spec[40]; + int spec[45]; int i = 0; spec[i++] = GLX_LEVEL; spec[i++] = f.plane(); const QX11Info *xinfo = qt_x11Info(d->paintDevice); + bool useFBConfig = false; + +#if defined(GLX_VERSION_1_3) && !defined(QT_NO_XRENDER) + QWidget* widget = 0; + if (d->paintDevice->devType() == QInternal::Widget) + widget = static_cast<QWidget*>(d->paintDevice); + + // Only use glXChooseFBConfig for widgets if we're trying to get an ARGB visual + if (widget && widget->testAttribute(Qt::WA_TranslucentBackground) && X11->use_xrender) + useFBConfig = true; +#endif #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info) static bool useTranspExt = false; @@ -565,28 +558,41 @@ void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth) useTranspExtChecked = true; } - if (f.plane() && useTranspExt) { + if (f.plane() && useTranspExt && !useFBConfig) { // Required to avoid non-transparent overlay visual(!) on some systems spec[i++] = GLX_TRANSPARENT_TYPE_EXT; spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT; } #endif +#if defined(GLX_VERSION_1_3) + // GLX_RENDER_TYPE is only in glx >=1.3 + if (useFBConfig) { + spec[i++] = GLX_RENDER_TYPE; + spec[i++] = f.rgba() ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; + } +#endif + if (f.doubleBuffer()) spec[i++] = GLX_DOUBLEBUFFER; + if (useFBConfig) + spec[i++] = True; if (f.depth()) { spec[i++] = GLX_DEPTH_SIZE; spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize(); } if (f.stereo()) { spec[i++] = GLX_STEREO; + if (useFBConfig) + spec[i++] = True; } if (f.stencil()) { spec[i++] = GLX_STENCIL_SIZE; spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize(); } if (f.rgba()) { - spec[i++] = GLX_RGBA; + if (!useFBConfig) + spec[i++] = GLX_RGBA; spec[i++] = GLX_RED_SIZE; spec[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize(); spec[i++] = GLX_GREEN_SIZE; @@ -621,8 +627,86 @@ void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth) spec[i++] = f.samples() == -1 ? 4 : f.samples(); } +#if defined(GLX_VERSION_1_3) + if (useFBConfig) { + spec[i++] = GLX_DRAWABLE_TYPE; + switch(d->paintDevice->devType()) { + case QInternal::Pixmap: + spec[i++] = GLX_PIXMAP_BIT; + break; + case QInternal::Pbuffer: + spec[i++] = GLX_PBUFFER_BIT; + break; + default: + qWarning("QGLContext: Unknown paint device type %d", d->paintDevice->devType()); + // Fall-through & assume it's a window + case QInternal::Widget: + spec[i++] = GLX_WINDOW_BIT; + break; + }; + } +#endif + spec[i] = XNone; - return glXChooseVisual(xinfo->display(), xinfo->screen(), spec); + + + XVisualInfo* chosenVisualInfo = 0; + +#if defined(GLX_VERSION_1_3) + while (useFBConfig) { + GLXFBConfig *configs; + int configCount = 0; + configs = glXChooseFBConfig(xinfo->display(), xinfo->screen(), spec, &configCount); + + if (!configs) + break; // fallback to trying glXChooseVisual + + for (i = 0; i < configCount; ++i) { + XVisualInfo* vi; + vi = glXGetVisualFromFBConfig(xinfo->display(), configs[i]); + if (!vi) + continue; + +#if !defined(QT_NO_XRENDER) + QWidget* w = 0; + if (d->paintDevice->devType() == QInternal::Widget) + w = static_cast<QWidget*>(d->paintDevice); + + if (w && w->testAttribute(Qt::WA_TranslucentBackground) && f.alpha()) { + // Attempt to find a config who's visual has a proper alpha channel + XRenderPictFormat *pictFormat; + pictFormat = XRenderFindVisualFormat(xinfo->display(), vi->visual); + + if (pictFormat && (pictFormat->type == PictTypeDirect) && pictFormat->direct.alphaMask) { + // The pict format for the visual matching the FBConfig indicates ARGB + if (chosenVisualInfo) + XFree(chosenVisualInfo); + chosenVisualInfo = vi; + break; + } + } else +#endif //QT_NO_XRENDER + if (chosenVisualInfo) { + // If we've got a visual we can use and we're not trying to find one with a + // real alpha channel, we might as well just use the one we've got + break; + } + + if (!chosenVisualInfo) + chosenVisualInfo = vi; // Have something to fall back to + else + XFree(vi); + } + + XFree(configs); + break; + } +#endif // defined(GLX_VERSION_1_3) + + if (!chosenVisualInfo) + chosenVisualInfo = glXChooseVisual(xinfo->display(), xinfo->screen(), spec); + + return chosenVisualInfo; } @@ -703,7 +787,7 @@ void QGLContext::swapBuffers() const static qt_glXWaitVideoSyncSGI glXWaitVideoSyncSGI = 0; static bool resolved = false; if (!resolved) { - QString glxExt = QString(QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS))); + QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); if (glxExt.contains(QLatin1String("GLX_SGI_video_sync"))) { #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) void *handle = dlopen(NULL, RTLD_LAZY); @@ -948,7 +1032,7 @@ void *QGLContext::getProcAddress(const QString &proc) const if (resolved && !glXGetProcAddressARB) return 0; if (!glXGetProcAddressARB) { - QString glxExt = QString(QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS))); + QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); if (glxExt.contains(QLatin1String("GLX_ARB_get_proc_address"))) { #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) void *handle = dlopen(NULL, RTLD_LAZY); @@ -1191,6 +1275,12 @@ void QGLWidget::setContext(QGLContext *context, d_func()->xinfo = parentWidget()->d_func()->xinfo; } + // If the application has set WA_TranslucentBackground and not explicitly set + // the alpha buffer size to zero, modify the format so it have an alpha channel + QGLFormat& fmt = d->glcx->d_func()->glFormat; + if (testAttribute(Qt::WA_TranslucentBackground) && fmt.alphaBufferSize() == -1) + fmt.setAlphaBufferSize(1); + bool createFailed = false; if (!d->glcx->isValid()) { if (!d->glcx->create(shareContext ? shareContext : oldcx)) diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index 480a2dc..3c745b8 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -114,13 +114,6 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval()); #endif - // Create the EGL surface to draw into. - if (!d->eglContext->createSurface(device())) { - delete d->eglContext; - d->eglContext = 0; - return false; - } - return true; } @@ -262,21 +255,125 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, d_func()->xinfo = parentWidget()->d_func()->xinfo; } + // If the application has set WA_TranslucentBackground and not explicitly set + // the alpha buffer size to zero, modify the format so it have an alpha channel + QGLFormat& fmt = d->glcx->d_func()->glFormat; + if (testAttribute(Qt::WA_TranslucentBackground) && fmt.alphaBufferSize() == -1) + fmt.setAlphaBufferSize(1); + + bool createFailed = false; + if (!d->glcx->isValid()) { + if (!d->glcx->create(shareContext ? shareContext : oldcx)) + createFailed = true; + } + if (createFailed) { + if (deleteOldContext) + delete oldcx; + return; + } + + if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) { + if (deleteOldContext) + delete oldcx; + return; + } + bool visible = isVisible(); if (visible) hide(); XVisualInfo vi; + memset(&vi, 0, sizeof(XVisualInfo)); + + // Check to see if EGL is suggesting an appropriate visual id: + EGLint nativeVisualId; + QEglContext* qeglCtx = d->glcx->d_func()->eglContext; + qeglCtx->configAttrib(EGL_NATIVE_VISUAL_ID, &nativeVisualId); + vi.visualid = nativeVisualId; + + if (vi.visualid) { + // EGL has suggested a visual id, so get the rest of the visual info for that id: + XVisualInfo *chosenVisualInfo; + int matchingCount = 0; + chosenVisualInfo = XGetVisualInfo(x11Info().display(), VisualIDMask, &vi, &matchingCount); + if (chosenVisualInfo) { + qDebug("Using X Visual ID (%d) provided by EGL", (int)vi.visualid); + vi = *chosenVisualInfo; + XFree(chosenVisualInfo); + } + else { + qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!", + nativeVisualId, (int)qeglCtx->config()); + vi.visualid = 0; + } + } - int err = XMatchVisualInfo(x11Info().display(), x11Info().screen(), x11Info().depth(), TrueColor, &vi); - if (err == 0) { - qWarning("Error: Couldn't get a matching X visual for format"); - return; + // If EGL does not know the visual ID, so try to select an appropriate one ourselves, first + // using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo + + bool useArgb = context->format().alpha() && !context->deviceIsPixmap(); +#if !defined(QT_NO_XRENDER) + if (vi.visualid == 0 && useArgb) { + // Try to use XRender to find an ARGB visual we can use + vi.screen = x11Info().screen(); + vi.depth = 32; + vi.c_class = TrueColor; + XVisualInfo *matchingVisuals; + int matchingCount = 0; + matchingVisuals = XGetVisualInfo(x11Info().display(), + VisualScreenMask|VisualDepthMask|VisualClassMask, + &vi, &matchingCount); + + for (int i = 0; i < matchingCount; ++i) { + XRenderPictFormat *format; + format = XRenderFindVisualFormat(x11Info().display(), matchingVisuals[i].visual); + if (format->type == PictTypeDirect && format->direct.alphaMask) { + vi = matchingVisuals[i]; + qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid); + break; + } + } + XFree(matchingVisuals); + } +#endif + + if (vi.visualid == 0) { + EGLint depth; + qeglCtx->configAttrib(EGL_BUFFER_SIZE, &depth); + int err; + err = XMatchVisualInfo(x11Info().display(), x11Info().screen(), depth, TrueColor, &vi); + if (err == 0) { + qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!", + (int)qeglCtx->config(), depth); + depth = x11Info().depth(); + err = XMatchVisualInfo(x11Info().display(), x11Info().screen(), depth, TrueColor, &vi); + if (err == 0) { + qWarning("Error: Couldn't get any matching X visual!"); + return; + } else + qWarning(" - Falling back to X11 suggested depth (%d)", depth); + } else + qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth); + + // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-( + if (useArgb) + useArgb = vi.depth == 32; } +// qDebug("Visual Info:"); +// qDebug(" bits_per_rgb=%d", vi.bits_per_rgb); +// qDebug(" red_mask=0x%x", vi.red_mask); +// qDebug(" green_mask=0x%x", vi.green_mask); +// qDebug(" blue_mask=0x%x", vi.blue_mask); +// qDebug(" colormap_size=%d", vi.colormap_size); +// qDebug(" c_class=%d", vi.c_class); +// qDebug(" depth=%d", vi.depth); +// qDebug(" screen=%d", vi.screen); +// qDebug(" visualid=%d", vi.visualid); + XSetWindowAttributes a; - Window p = RootWindow(X11->display, vi.screen); + Window p = RootWindow(x11Info().display(), x11Info().screen()); if (parentWidget()) p = parentWidget()->winId(); @@ -284,9 +381,14 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, a.background_pixel = colmap.pixel(palette().color(backgroundRole())); a.border_pixel = colmap.pixel(Qt::black); - Window w = XCreateWindow(X11->display, p, x(), y(), width(), height(), - 0, vi.depth, InputOutput, vi.visual, - CWBackPixel|CWBorderPixel, &a); + unsigned int valueMask = CWBackPixel|CWBorderPixel; + if(useArgb) { + a.colormap = XCreateColormap(x11Info().display(), p, vi.visual, AllocNone); + valueMask |= CWColormap; + } + + Window w = XCreateWindow(x11Info().display(), p, x(), y(), width(), height(), + 0, vi.depth, InputOutput, vi.visual, valueMask, &a); if (deleteOldContext) delete oldcx; @@ -294,28 +396,20 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, create(w); // Create with the ID of the window we've just created - d->eglSurfaceWindowId = w; // Remember the window id we created the surface for - - if (visible) - show(); - bool createFailed = false; - if (!d->glcx->isValid()) { - if (!d->glcx->create(shareContext ? shareContext : oldcx)) - createFailed = true; - } - if (createFailed) { - if (deleteOldContext) - delete oldcx; + // Create the EGL surface to draw into. + if (!d->glcx->d_func()->eglContext->createSurface(this)) { + delete d->glcx->d_func()->eglContext; + d->glcx->d_func()->eglContext = 0; return; } - if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) { - if (deleteOldContext) - delete oldcx; - return; - } + d->eglSurfaceWindowId = w; // Remember the window id we created the surface for + + if (visible) + show(); + XFlush(X11->display); d->glcx->setWindowCreated(true); } diff --git a/src/opengl/qglextensions.cpp b/src/opengl/qglextensions.cpp index 8357cf9..3c198fb 100644 --- a/src/opengl/qglextensions.cpp +++ b/src/opengl/qglextensions.cpp @@ -45,9 +45,15 @@ QT_BEGIN_NAMESPACE bool qt_resolve_framebufferobject_extensions(QGLContext *ctx) { -#if !defined(QT_OPENGL_ES_2) - if (glIsRenderbufferEXT != 0) +#if defined(QT_OPENGL_ES_2) + static bool have_resolved = false; + if (have_resolved) + return true; + have_resolved = true; +#else + if (glIsRenderbuffer != 0) return true; +#endif if (ctx == 0) { qWarning("QGLFramebufferObject: Unable to resolve framebuffer object extensions -" @@ -55,32 +61,37 @@ bool qt_resolve_framebufferobject_extensions(QGLContext *ctx) return false; } - glIsRenderbufferEXT = (_glIsRenderbufferEXT) ctx->getProcAddress(QLatin1String("glIsRenderbufferEXT")); - glBindRenderbufferEXT = (_glBindRenderbufferEXT) ctx->getProcAddress(QLatin1String("glBindRenderbufferEXT")); - glDeleteRenderbuffersEXT = (_glDeleteRenderbuffersEXT) ctx->getProcAddress(QLatin1String("glDeleteRenderbuffersEXT")); - glGenRenderbuffersEXT = (_glGenRenderbuffersEXT) ctx->getProcAddress(QLatin1String("glGenRenderbuffersEXT")); - glRenderbufferStorageEXT = (_glRenderbufferStorageEXT) ctx->getProcAddress(QLatin1String("glRenderbufferStorageEXT")); - glGetRenderbufferParameterivEXT = - (_glGetRenderbufferParameterivEXT) ctx->getProcAddress(QLatin1String("glGetRenderbufferParameterivEXT")); - glIsFramebufferEXT = (_glIsFramebufferEXT) ctx->getProcAddress(QLatin1String("glIsFramebufferEXT")); - glBindFramebufferEXT = (_glBindFramebufferEXT) ctx->getProcAddress(QLatin1String("glBindFramebufferEXT")); - glDeleteFramebuffersEXT = (_glDeleteFramebuffersEXT) ctx->getProcAddress(QLatin1String("glDeleteFramebuffersEXT")); - glGenFramebuffersEXT = (_glGenFramebuffersEXT) ctx->getProcAddress(QLatin1String("glGenFramebuffersEXT")); - glCheckFramebufferStatusEXT = (_glCheckFramebufferStatusEXT) ctx->getProcAddress(QLatin1String("glCheckFramebufferStatusEXT")); - glFramebufferTexture1DEXT = (_glFramebufferTexture1DEXT) ctx->getProcAddress(QLatin1String("glFramebufferTexture1DEXT")); - glFramebufferTexture2DEXT = (_glFramebufferTexture2DEXT) ctx->getProcAddress(QLatin1String("glFramebufferTexture2DEXT")); - glFramebufferTexture3DEXT = (_glFramebufferTexture3DEXT) ctx->getProcAddress(QLatin1String("glFramebufferTexture3DEXT")); - glFramebufferRenderbufferEXT = (_glFramebufferRenderbufferEXT) ctx->getProcAddress(QLatin1String("glFramebufferRenderbufferEXT")); - glGetFramebufferAttachmentParameterivEXT = - (_glGetFramebufferAttachmentParameterivEXT) ctx->getProcAddress(QLatin1String("glGetFramebufferAttachmentParameterivEXT")); - glGenerateMipmapEXT = (_glGenerateMipmapEXT) ctx->getProcAddress(QLatin1String("glGenerateMipmapEXT")); - return glIsRenderbufferEXT; + + glBlitFramebufferEXT = (_glBlitFramebufferEXT) ctx->getProcAddress(QLatin1String("glBlitFramebufferEXT")); + glRenderbufferStorageMultisampleEXT = + (_glRenderbufferStorageMultisampleEXT) ctx->getProcAddress(QLatin1String("glRenderbufferStorageMultisampleEXT")); + +#if !defined(QT_OPENGL_ES_2) + glIsRenderbuffer = (_glIsRenderbuffer) ctx->getProcAddress(QLatin1String("glIsRenderbufferEXT")); + glBindRenderbuffer = (_glBindRenderbuffer) ctx->getProcAddress(QLatin1String("glBindRenderbufferEXT")); + glDeleteRenderbuffers = (_glDeleteRenderbuffers) ctx->getProcAddress(QLatin1String("glDeleteRenderbuffersEXT")); + glGenRenderbuffers = (_glGenRenderbuffers) ctx->getProcAddress(QLatin1String("glGenRenderbuffersEXT")); + glRenderbufferStorage = (_glRenderbufferStorage) ctx->getProcAddress(QLatin1String("glRenderbufferStorageEXT")); + glGetRenderbufferParameteriv = + (_glGetRenderbufferParameteriv) ctx->getProcAddress(QLatin1String("glGetRenderbufferParameterivEXT")); + glIsFramebuffer = (_glIsFramebuffer) ctx->getProcAddress(QLatin1String("glIsFramebufferEXT")); + glBindFramebuffer = (_glBindFramebuffer) ctx->getProcAddress(QLatin1String("glBindFramebufferEXT")); + glDeleteFramebuffers = (_glDeleteFramebuffers) ctx->getProcAddress(QLatin1String("glDeleteFramebuffersEXT")); + glGenFramebuffers = (_glGenFramebuffers) ctx->getProcAddress(QLatin1String("glGenFramebuffersEXT")); + glCheckFramebufferStatus = (_glCheckFramebufferStatus) ctx->getProcAddress(QLatin1String("glCheckFramebufferStatusEXT")); + glFramebufferTexture2D = (_glFramebufferTexture2D) ctx->getProcAddress(QLatin1String("glFramebufferTexture2DEXT")); + glFramebufferRenderbuffer = (_glFramebufferRenderbuffer) ctx->getProcAddress(QLatin1String("glFramebufferRenderbufferEXT")); + glGetFramebufferAttachmentParameteriv = + (_glGetFramebufferAttachmentParameteriv) ctx->getProcAddress(QLatin1String("glGetFramebufferAttachmentParameterivEXT")); + glGenerateMipmap = (_glGenerateMipmap) ctx->getProcAddress(QLatin1String("glGenerateMipmapEXT")); + + return glIsRenderbuffer; #else - Q_UNUSED(ctx); return true; #endif } +#if !defined(QT_OPENGL_ES_2) bool qt_resolve_version_1_3_functions(QGLContext *ctx) { if (glMultiTexCoord4f != 0) @@ -89,14 +100,12 @@ bool qt_resolve_version_1_3_functions(QGLContext *ctx) QGLContext cx(QGLFormat::defaultFormat()); glMultiTexCoord4f = (_glMultiTexCoord4f) ctx->getProcAddress(QLatin1String("glMultiTexCoord4f")); -#if defined(QT_OPENGL_ES_2) - return glMultiTexCoord4f; -#else glActiveTexture = (_glActiveTexture) ctx->getProcAddress(QLatin1String("glActiveTexture")); return glMultiTexCoord4f && glActiveTexture; -#endif } +#endif +#if !defined(QT_OPENGL_ES_2) bool qt_resolve_stencil_face_extension(QGLContext *ctx) { if (glActiveStencilFaceEXT != 0) @@ -107,7 +116,10 @@ bool qt_resolve_stencil_face_extension(QGLContext *ctx) return glActiveStencilFaceEXT; } +#endif + +#if !defined(QT_OPENGL_ES_2) bool qt_resolve_frag_program_extensions(QGLContext *ctx) { if (glProgramStringARB != 0) @@ -126,60 +138,215 @@ bool qt_resolve_frag_program_extensions(QGLContext *ctx) && glGenProgramsARB && glProgramLocalParameter4fvARB; } +#endif + bool qt_resolve_buffer_extensions(QGLContext *ctx) { - if (glBindBufferARB && glDeleteBuffersARB && glGenBuffersARB && glBufferDataARB - && glMapBufferARB && glUnmapBufferARB) + if (glMapBufferARB && glUnmapBufferARB +#if !defined(QT_OPENGL_ES_2) + && glBindBuffer && glDeleteBuffers && glGenBuffers && glBufferData +#endif + ) return true; - glBindBufferARB = (_glBindBufferARB) ctx->getProcAddress(QLatin1String("glBindBufferARB")); - glDeleteBuffersARB = (_glDeleteBuffersARB) ctx->getProcAddress(QLatin1String("glDeleteBuffersARB")); - glGenBuffersARB = (_glGenBuffersARB) ctx->getProcAddress(QLatin1String("glGenBuffersARB")); - glBufferDataARB = (_glBufferDataARB) ctx->getProcAddress(QLatin1String("glBufferDataARB")); +#if !defined(QT_OPENGL_ES_2) + glBindBuffer = (_glBindBuffer) ctx->getProcAddress(QLatin1String("glBindBufferARB")); + glDeleteBuffers = (_glDeleteBuffers) ctx->getProcAddress(QLatin1String("glDeleteBuffersARB")); + glGenBuffers = (_glGenBuffers) ctx->getProcAddress(QLatin1String("glGenBuffersARB")); + glBufferData = (_glBufferData) ctx->getProcAddress(QLatin1String("glBufferDataARB")); +#endif glMapBufferARB = (_glMapBufferARB) ctx->getProcAddress(QLatin1String("glMapBufferARB")); glUnmapBufferARB = (_glUnmapBufferARB) ctx->getProcAddress(QLatin1String("glUnmapBufferARB")); - return glBindBufferARB - && glDeleteBuffersARB - && glGenBuffersARB - && glBufferDataARB - && glMapBufferARB - && glUnmapBufferARB; + return glMapBufferARB + && glUnmapBufferARB +#if !defined(QT_OPENGL_ES_2) + && glBindBuffer + && glDeleteBuffers + && glGenBuffers + && glBufferData +#endif + ; } bool qt_resolve_glsl_extensions(QGLContext *ctx) { +#if defined(QT_OPENGL_ES_2) + // The GLSL shader functions are always present in OpenGL/ES 2.0. + // The only exceptions are glGetProgramBinaryOES and glProgramBinaryOES. + if (!QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glslResolved) { + glGetProgramBinaryOES = (_glGetProgramBinaryOES) ctx->getProcAddress(QLatin1String("glGetProgramBinaryOES")); + glProgramBinaryOES = (_glProgramBinaryOES) ctx->getProcAddress(QLatin1String("glProgramBinaryOES")); + QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glslResolved = true; + } + return true; +#else if (glCreateShader) return true; glCreateShader = (_glCreateShader) ctx->getProcAddress(QLatin1String("glCreateShader")); - glShaderSource = (_glShaderSource) ctx->getProcAddress(QLatin1String("glShaderSource")); - glCompileShader = (_glCompileShader) ctx->getProcAddress(QLatin1String("glCompileShader")); - glDeleteShader = (_glDeleteShader) ctx->getProcAddress(QLatin1String("glDeleteShader")); - - glCreateProgram = (_glCreateProgram) ctx->getProcAddress(QLatin1String("glCreateProgram")); - glAttachShader = (_glAttachShader) ctx->getProcAddress(QLatin1String("glAttachShader")); - glDetachShader = (_glDetachShader) ctx->getProcAddress(QLatin1String("glDetachShader")); - glLinkProgram = (_glLinkProgram) ctx->getProcAddress(QLatin1String("glLinkProgram")); - glUseProgram = (_glUseProgram) ctx->getProcAddress(QLatin1String("glUseProgram")); - glDeleteProgram = (_glDeleteProgram) ctx->getProcAddress(QLatin1String("glDeleteProgram")); - - glGetShaderInfoLog = (_glGetShaderInfoLog) ctx->getProcAddress(QLatin1String("glGetShaderInfoLog")); - glGetShaderiv = (_glGetShaderiv) ctx->getProcAddress(QLatin1String("glGetShaderiv")); - glGetProgramiv = (_glGetProgramiv) ctx->getProcAddress(QLatin1String("glGetProgramiv")); - - glGetUniformLocation = (_glGetUniformLocation) ctx->getProcAddress(QLatin1String("glGetUniformLocation")); - glUniform4fv = (_glUniform4fv) ctx->getProcAddress(QLatin1String("glUniform4fv")); - glUniform3fv = (_glUniform3fv) ctx->getProcAddress(QLatin1String("glUniform3fv")); - glUniform2fv = (_glUniform2fv) ctx->getProcAddress(QLatin1String("glUniform2fv")); - glUniform1fv = (_glUniform1fv) ctx->getProcAddress(QLatin1String("glUniform1fv")); - glUniform1i = (_glUniform1i) ctx->getProcAddress(QLatin1String("glUniform1i")); - - return glCreateShader && glShaderSource && glCompileShader && glDeleteProgram && - glCreateProgram && glAttachShader && glDetachShader && glLinkProgram && glUseProgram && - glDeleteProgram && glGetShaderInfoLog && glGetShaderiv && glGetProgramiv && glGetUniformLocation && - glUniform1i && glUniform1fv && glUniform2fv && glUniform3fv && glUniform4fv; + if (glCreateShader) { + glShaderSource = (_glShaderSource) ctx->getProcAddress(QLatin1String("glShaderSource")); + glShaderBinary = (_glShaderBinary) ctx->getProcAddress(QLatin1String("glShaderBinary")); + glCompileShader = (_glCompileShader) ctx->getProcAddress(QLatin1String("glCompileShader")); + glDeleteShader = (_glDeleteShader) ctx->getProcAddress(QLatin1String("glDeleteShader")); + glIsShader = (_glIsShader) ctx->getProcAddress(QLatin1String("glIsShader")); + + glCreateProgram = (_glCreateProgram) ctx->getProcAddress(QLatin1String("glCreateProgram")); + glAttachShader = (_glAttachShader) ctx->getProcAddress(QLatin1String("glAttachShader")); + glDetachShader = (_glDetachShader) ctx->getProcAddress(QLatin1String("glDetachShader")); + glLinkProgram = (_glLinkProgram) ctx->getProcAddress(QLatin1String("glLinkProgram")); + glUseProgram = (_glUseProgram) ctx->getProcAddress(QLatin1String("glUseProgram")); + glDeleteProgram = (_glDeleteProgram) ctx->getProcAddress(QLatin1String("glDeleteProgram")); + glIsProgram = (_glIsProgram) ctx->getProcAddress(QLatin1String("glIsProgram")); + + glGetShaderInfoLog = (_glGetShaderInfoLog) ctx->getProcAddress(QLatin1String("glGetShaderInfoLog")); + glGetShaderiv = (_glGetShaderiv) ctx->getProcAddress(QLatin1String("glGetShaderiv")); + glGetShaderSource = (_glGetShaderSource) ctx->getProcAddress(QLatin1String("glGetShaderSource")); + glGetProgramiv = (_glGetProgramiv) ctx->getProcAddress(QLatin1String("glGetProgramiv")); + glGetProgramInfoLog = (_glGetProgramInfoLog) ctx->getProcAddress(QLatin1String("glGetProgramInfoLog")); + + glGetUniformLocation = (_glGetUniformLocation) ctx->getProcAddress(QLatin1String("glGetUniformLocation")); + glUniform4fv = (_glUniform4fv) ctx->getProcAddress(QLatin1String("glUniform4fv")); + glUniform3fv = (_glUniform3fv) ctx->getProcAddress(QLatin1String("glUniform3fv")); + glUniform2fv = (_glUniform2fv) ctx->getProcAddress(QLatin1String("glUniform2fv")); + glUniform1fv = (_glUniform1fv) ctx->getProcAddress(QLatin1String("glUniform1fv")); + glUniform1i = (_glUniform1i) ctx->getProcAddress(QLatin1String("glUniform1i")); + glUniform1iv = (_glUniform1iv) ctx->getProcAddress(QLatin1String("glUniform1iv")); + glUniformMatrix2fv = (_glUniformMatrix2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2fv")); + glUniformMatrix3fv = (_glUniformMatrix3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3fv")); + glUniformMatrix4fv = (_glUniformMatrix4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4fv")); + glUniformMatrix2x3fv = (_glUniformMatrix2x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x3fv")); + glUniformMatrix2x4fv = (_glUniformMatrix2x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x4fv")); + glUniformMatrix3x2fv = (_glUniformMatrix3x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x2fv")); + glUniformMatrix3x4fv = (_glUniformMatrix3x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x4fv")); + glUniformMatrix4x2fv = (_glUniformMatrix4x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x2fv")); + glUniformMatrix4x3fv = (_glUniformMatrix4x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x3fv")); + + glBindAttribLocation = (_glBindAttribLocation) ctx->getProcAddress(QLatin1String("glBindAttribLocation")); + glGetAttribLocation = (_glGetAttribLocation) ctx->getProcAddress(QLatin1String("glGetAttribLocation")); + glVertexAttrib1fv = (_glVertexAttrib1fv) ctx->getProcAddress(QLatin1String("glVertexAttrib1fv")); + glVertexAttrib2fv = (_glVertexAttrib2fv) ctx->getProcAddress(QLatin1String("glVertexAttrib2fv")); + glVertexAttrib3fv = (_glVertexAttrib3fv) ctx->getProcAddress(QLatin1String("glVertexAttrib3fv")); + glVertexAttrib4fv = (_glVertexAttrib4fv) ctx->getProcAddress(QLatin1String("glVertexAttrib4fv")); + glVertexAttribPointer = (_glVertexAttribPointer) ctx->getProcAddress(QLatin1String("glVertexAttribPointer")); + glDisableVertexAttribArray = (_glDisableVertexAttribArray) ctx->getProcAddress(QLatin1String("glDisableVertexAttribArray")); + glEnableVertexAttribArray = (_glEnableVertexAttribArray) ctx->getProcAddress(QLatin1String("glEnableVertexAttribArray")); + + } else { + // We may not have the standard shader functions, but we might + // have the older ARB functions instead. + glCreateShader = (_glCreateShader) ctx->getProcAddress(QLatin1String("glCreateShaderObjectARB")); + glShaderSource = (_glShaderSource) ctx->getProcAddress(QLatin1String("glShaderSourceARB")); + glShaderBinary = (_glShaderBinary) ctx->getProcAddress(QLatin1String("glShaderBinaryARB")); + glCompileShader = (_glCompileShader) ctx->getProcAddress(QLatin1String("glCompileShaderARB")); + glDeleteShader = (_glDeleteShader) ctx->getProcAddress(QLatin1String("glDeleteObjectARB")); + glIsShader = 0; + + glCreateProgram = (_glCreateProgram) ctx->getProcAddress(QLatin1String("glCreateProgramObjectARB")); + glAttachShader = (_glAttachShader) ctx->getProcAddress(QLatin1String("glAttachObjectARB")); + glDetachShader = (_glDetachShader) ctx->getProcAddress(QLatin1String("glDetachObjectARB")); + glLinkProgram = (_glLinkProgram) ctx->getProcAddress(QLatin1String("glLinkProgramARB")); + glUseProgram = (_glUseProgram) ctx->getProcAddress(QLatin1String("glUseProgramObjectARB")); + glDeleteProgram = (_glDeleteProgram) ctx->getProcAddress(QLatin1String("glDeleteObjectARB")); + glIsProgram = 0; + + glGetShaderInfoLog = (_glGetShaderInfoLog) ctx->getProcAddress(QLatin1String("glGetInfoLogARB")); + glGetShaderiv = (_glGetShaderiv) ctx->getProcAddress(QLatin1String("glGetObjectParameterivARB")); + glGetShaderSource = (_glGetShaderSource) ctx->getProcAddress(QLatin1String("glGetShaderSourceARB")); + glGetProgramiv = (_glGetProgramiv) ctx->getProcAddress(QLatin1String("glGetObjectParameterivARB")); + glGetProgramInfoLog = (_glGetProgramInfoLog) ctx->getProcAddress(QLatin1String("glGetInfoLogARB")); + + glGetUniformLocation = (_glGetUniformLocation) ctx->getProcAddress(QLatin1String("glGetUniformLocationARB")); + glUniform4fv = (_glUniform4fv) ctx->getProcAddress(QLatin1String("glUniform4fvARB")); + glUniform3fv = (_glUniform3fv) ctx->getProcAddress(QLatin1String("glUniform3fvARB")); + glUniform2fv = (_glUniform2fv) ctx->getProcAddress(QLatin1String("glUniform2fvARB")); + glUniform1fv = (_glUniform1fv) ctx->getProcAddress(QLatin1String("glUniform1fvARB")); + glUniform1i = (_glUniform1i) ctx->getProcAddress(QLatin1String("glUniform1iARB")); + glUniform1iv = (_glUniform1iv) ctx->getProcAddress(QLatin1String("glUniform1ivARB")); + glUniformMatrix2fv = (_glUniformMatrix2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2fvARB")); + glUniformMatrix3fv = (_glUniformMatrix3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3fvARB")); + glUniformMatrix4fv = (_glUniformMatrix4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4fvARB")); + glUniformMatrix2x3fv = (_glUniformMatrix2x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x3fvARB")); + glUniformMatrix2x4fv = (_glUniformMatrix2x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x4fvARB")); + glUniformMatrix3x2fv = (_glUniformMatrix3x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x2fvARB")); + glUniformMatrix3x4fv = (_glUniformMatrix3x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x4fvARB")); + glUniformMatrix4x2fv = (_glUniformMatrix4x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x2fvARB")); + glUniformMatrix4x3fv = (_glUniformMatrix4x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x3fvARB")); + + glBindAttribLocation = (_glBindAttribLocation) ctx->getProcAddress(QLatin1String("glBindAttribLocationARB")); + glGetAttribLocation = (_glGetAttribLocation) ctx->getProcAddress(QLatin1String("glGetAttribLocationARB")); + glVertexAttrib1fv = (_glVertexAttrib1fv) ctx->getProcAddress(QLatin1String("glVertexAttrib1fvARB")); + glVertexAttrib2fv = (_glVertexAttrib2fv) ctx->getProcAddress(QLatin1String("glVertexAttrib2fvARB")); + glVertexAttrib3fv = (_glVertexAttrib3fv) ctx->getProcAddress(QLatin1String("glVertexAttrib3fvARB")); + glVertexAttrib4fv = (_glVertexAttrib4fv) ctx->getProcAddress(QLatin1String("glVertexAttrib4fvARB")); + glVertexAttribPointer = (_glVertexAttribPointer) ctx->getProcAddress(QLatin1String("glVertexAttribPointerARB")); + glDisableVertexAttribArray = (_glDisableVertexAttribArray) ctx->getProcAddress(QLatin1String("glDisableVertexAttribArrayARB")); + glEnableVertexAttribArray = (_glEnableVertexAttribArray) ctx->getProcAddress(QLatin1String("glEnableVertexAttribArrayARB")); + } + + // Note: glShaderBinary(), glIsShader(), glIsProgram(), and + // glUniformMatrixNxMfv() are optional, but all other functions + // are required. + + return glCreateShader && + glShaderSource && + glCompileShader && + glDeleteProgram && + glCreateProgram && + glAttachShader && + glDetachShader && + glLinkProgram && + glUseProgram && + glDeleteProgram && + glGetShaderInfoLog && + glGetShaderiv && + glGetShaderSource && + glGetProgramiv && + glGetProgramInfoLog && + glGetUniformLocation && + glUniform1fv && + glUniform2fv && + glUniform3fv && + glUniform4fv && + glUniform1i && + glUniform1iv && + glUniformMatrix2fv && + glUniformMatrix3fv && + glUniformMatrix4fv && + glBindAttribLocation && + glGetAttribLocation && + glVertexAttrib1fv && + glVertexAttrib2fv && + glVertexAttrib3fv && + glVertexAttrib4fv && + glVertexAttribPointer && + glDisableVertexAttribArray && + glEnableVertexAttribArray; +#endif } +#if !defined(QT_OPENGL_ES_2) +bool qt_resolve_version_2_0_functions(QGLContext *ctx) +{ + bool gl2supported = true; + if (!qt_resolve_glsl_extensions(ctx)) + gl2supported = false; + + if (!qt_resolve_version_1_3_functions(ctx)) + gl2supported = false; + + if (glStencilOpSeparate) + return gl2supported; + + glStencilOpSeparate = (_glStencilOpSeparate) ctx->getProcAddress(QLatin1String("glStencilOpSeparate")); + if (!glStencilOpSeparate) + gl2supported = false; + + return gl2supported; +} +#endif + + QT_END_NAMESPACE diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h index a0517f5..d6edfb6 100644 --- a/src/opengl/qglextensions_p.h +++ b/src/opengl/qglextensions_p.h @@ -74,11 +74,15 @@ typedef ptrdiff_t GLsizeiptrARB; #endif +#ifndef GL_VERSION_2_0 +typedef char GLchar; +#endif + // ARB_pixel_buffer_object -typedef void (APIENTRY *_glBindBufferARB) (GLenum, GLuint); -typedef void (APIENTRY *_glDeleteBuffersARB) (GLsizei, const GLuint *); -typedef void (APIENTRY *_glGenBuffersARB) (GLsizei, GLuint *); -typedef void (APIENTRY *_glBufferDataARB) (GLenum, GLsizeiptrARB, const GLvoid *, GLenum); +typedef void (APIENTRY *_glBindBuffer) (GLenum, GLuint); +typedef void (APIENTRY *_glDeleteBuffers) (GLsizei, const GLuint *); +typedef void (APIENTRY *_glGenBuffers) (GLsizei, GLuint *); +typedef void (APIENTRY *_glBufferData) (GLenum, GLsizeiptrARB, const GLvoid *, GLenum); typedef GLvoid* (APIENTRY *_glMapBufferARB) (GLenum, GLenum); typedef GLboolean (APIENTRY *_glUnmapBufferARB) (GLenum); @@ -92,8 +96,10 @@ typedef void (APIENTRY *_glProgramLocalParameter4fvARB) (GLenum, GLuint, const G // GLSL typedef GLuint (APIENTRY *_glCreateShader) (GLenum); typedef void (APIENTRY *_glShaderSource) (GLuint, GLsizei, const char **, const GLint *); +typedef void (APIENTRY *_glShaderBinary) (GLint, const GLuint*, GLenum, const void*, GLint); typedef void (APIENTRY *_glCompileShader) (GLuint); typedef void (APIENTRY *_glDeleteShader) (GLuint); +typedef GLboolean (APIENTRY *_glIsShader) (GLuint); typedef GLuint (APIENTRY *_glCreateProgram) (); typedef void (APIENTRY *_glAttachShader) (GLuint, GLuint); @@ -101,62 +107,101 @@ typedef void (APIENTRY *_glDetachShader) (GLuint, GLuint); typedef void (APIENTRY *_glLinkProgram) (GLuint); typedef void (APIENTRY *_glUseProgram) (GLuint); typedef void (APIENTRY *_glDeleteProgram) (GLuint); +typedef GLboolean (APIENTRY *_glIsProgram) (GLuint); typedef void (APIENTRY *_glGetShaderInfoLog) (GLuint, GLsizei, GLsizei *, char *); typedef void (APIENTRY *_glGetShaderiv) (GLuint, GLenum, GLint *); +typedef void (APIENTRY *_glGetShaderSource) (GLuint, GLsizei, GLsizei *, char *); typedef void (APIENTRY *_glGetProgramiv) (GLuint, GLenum, GLint *); +typedef void (APIENTRY *_glGetProgramInfoLog) (GLuint, GLsizei, GLsizei *, char *); typedef GLuint (APIENTRY *_glGetUniformLocation) (GLuint, const char*); -typedef void (APIENTRY *_glUniform4fv) (GLint, GLsizei, GLfloat *); -typedef void (APIENTRY *_glUniform3fv) (GLint, GLsizei, GLfloat *); -typedef void (APIENTRY *_glUniform2fv) (GLint, GLsizei, GLfloat *); -typedef void (APIENTRY *_glUniform1fv) (GLint, GLsizei, GLfloat *); +typedef void (APIENTRY *_glUniform4fv) (GLint, GLsizei, const GLfloat *); +typedef void (APIENTRY *_glUniform3fv) (GLint, GLsizei, const GLfloat *); +typedef void (APIENTRY *_glUniform2fv) (GLint, GLsizei, const GLfloat *); +typedef void (APIENTRY *_glUniform1fv) (GLint, GLsizei, const GLfloat *); typedef void (APIENTRY *_glUniform1i) (GLint, GLint); +typedef void (APIENTRY *_glUniform1iv) (GLint, GLsizei, const GLint *); +typedef void (APIENTRY *_glUniformMatrix2fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix3fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix4fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix2x3fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix2x4fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix3x2fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix3x4fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix4x2fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix4x3fv) (GLint, GLsizei, GLboolean, const GLfloat *); + +typedef void (APIENTRY *_glBindAttribLocation) (GLuint, GLuint, const char *); +typedef GLint (APIENTRY *_glGetAttribLocation) (GLuint, const char *); +typedef void (APIENTRY *_glVertexAttrib1fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttrib2fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttrib3fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttrib4fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttribPointer) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *); +typedef void (APIENTRY *_glDisableVertexAttribArray) (GLuint); +typedef void (APIENTRY *_glEnableVertexAttribArray) (GLuint); + +typedef void (APIENTRY *_glGetProgramBinaryOES) (GLuint, GLsizei, GLsizei *, GLenum *, void *); +typedef void (APIENTRY *_glProgramBinaryOES) (GLuint, GLenum, const void *, GLint); -typedef void (APIENTRY *_glActiveStencilFaceEXT) (GLenum ); typedef void (APIENTRY *_glMultiTexCoord4f) (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); +typedef void (APIENTRY *_glActiveStencilFaceEXT) (GLenum ); + +// Needed for GL2 engine: +typedef void (APIENTRY *_glStencilOpSeparate) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (APIENTRY *_glActiveTexture) (GLenum); + // EXT_GL_framebuffer_object -typedef GLboolean (APIENTRY *_glIsRenderbufferEXT) (GLuint renderbuffer); -typedef void (APIENTRY *_glBindRenderbufferEXT) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRY *_glDeleteRenderbuffersEXT) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRY *_glGenRenderbuffersEXT) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRY *_glRenderbufferStorageEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRY *_glGetRenderbufferParameterivEXT) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRY *_glIsFramebufferEXT) (GLuint framebuffer); -typedef void (APIENTRY *_glBindFramebufferEXT) (GLenum target, GLuint framebuffer); -typedef void (APIENTRY *_glDeleteFramebuffersEXT) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRY *_glGenFramebuffersEXT) (GLsizei n, GLuint *framebuffers); -typedef GLenum (APIENTRY *_glCheckFramebufferStatusEXT) (GLenum target); -typedef void (APIENTRY *_glFramebufferTexture1DEXT) (GLenum target, GLenum attachment, GLenum textarget, - GLuint texture, GLint level); -typedef void (APIENTRY *_glFramebufferTexture2DEXT) (GLenum target, GLenum attachment, GLenum textarget, +typedef GLboolean (APIENTRY *_glIsRenderbuffer) (GLuint renderbuffer); +typedef void (APIENTRY *_glBindRenderbuffer) (GLenum target, GLuint renderbuffer); +typedef void (APIENTRY *_glDeleteRenderbuffers) (GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRY *_glGenRenderbuffers) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRY *_glRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRY *_glGetRenderbufferParameteriv) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (APIENTRY *_glIsFramebuffer) (GLuint framebuffer); +typedef void (APIENTRY *_glBindFramebuffer) (GLenum target, GLuint framebuffer); +typedef void (APIENTRY *_glDeleteFramebuffers) (GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRY *_glGenFramebuffers) (GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRY *_glCheckFramebufferStatus) (GLenum target); +typedef void (APIENTRY *_glFramebufferTexture2D) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRY *_glFramebufferTexture3DEXT) (GLenum target, GLenum attachment, GLenum textarget, - GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRY *_glFramebufferRenderbufferEXT) (GLenum target, GLenum attachment, GLenum renderbuffertarget, +typedef void (APIENTRY *_glFramebufferRenderbuffer) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRY *_glGetFramebufferAttachmentParameterivEXT) (GLenum target, GLenum attachment, GLenum pname, +typedef void (APIENTRY *_glGetFramebufferAttachmentParameteriv) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRY *_glGenerateMipmapEXT) (GLenum target); +typedef void (APIENTRY *_glGenerateMipmap) (GLenum target); + +// EXT_GL_framebuffer_blit +typedef void (APIENTRY *_glBlitFramebufferEXT) (int srcX0, int srcY0, int srcX1, int srcY1, + int dstX0, int dstY0, int dstX1, int dstY1, + GLbitfield mask, GLenum filter); + +// EXT_GL_framebuffer_multisample +typedef void (APIENTRY *_glRenderbufferStorageMultisampleEXT) (GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height); QT_BEGIN_NAMESPACE struct QGLExtensionFuncs { QGLExtensionFuncs() { +#if !defined(QT_OPENGL_ES_2) qt_glProgramStringARB = 0; qt_glBindProgramARB = 0; qt_glDeleteProgramsARB = 0; qt_glGenProgramsARB = 0; qt_glProgramLocalParameter4fvARB = 0; + // GLSL qt_glCreateShader = 0; qt_glShaderSource = 0; + qt_glShaderBinary = 0; qt_glCompileShader = 0; qt_glDeleteShader = 0; + qt_glIsShader = 0; qt_glCreateProgram = 0; qt_glAttachShader = 0; @@ -164,10 +209,13 @@ struct QGLExtensionFuncs qt_glLinkProgram = 0; qt_glUseProgram = 0; qt_glDeleteProgram = 0; + qt_glIsProgram = 0; qt_glGetShaderInfoLog = 0; qt_glGetShaderiv = 0; + qt_glGetShaderSource = 0; qt_glGetProgramiv = 0; + qt_glGetProgramInfoLog = 0; qt_glGetUniformLocation = 0; qt_glUniform4fv = 0; @@ -175,40 +223,74 @@ struct QGLExtensionFuncs qt_glUniform2fv = 0; qt_glUniform1fv = 0; qt_glUniform1i = 0; + qt_glUniform1iv = 0; + qt_glUniformMatrix2fv = 0; + qt_glUniformMatrix3fv = 0; + qt_glUniformMatrix4fv = 0; + qt_glUniformMatrix2x3fv = 0; + qt_glUniformMatrix2x4fv = 0; + qt_glUniformMatrix3x2fv = 0; + qt_glUniformMatrix3x4fv = 0; + qt_glUniformMatrix4x2fv = 0; + qt_glUniformMatrix4x3fv = 0; + + qt_glBindAttribLocation = 0; + qt_glGetAttribLocation = 0; + qt_glVertexAttrib1fv = 0; + qt_glVertexAttrib2fv = 0; + qt_glVertexAttrib3fv = 0; + qt_glVertexAttrib4fv = 0; + qt_glVertexAttribPointer = 0; + qt_glDisableVertexAttribArray = 0; + qt_glEnableVertexAttribArray = 0; + + // Extras for GL2 engine: + qt_glActiveTexture = 0; + qt_glStencilOpSeparate = 0; qt_glActiveStencilFaceEXT = 0; - qt_glMultiTexCoord4f = 0; - qt_glActiveTexture = 0; +#else + qt_glslResolved = false; + + qt_glGetProgramBinaryOES = 0; + qt_glProgramBinaryOES = 0; +#endif + // FBOs #if !defined(QT_OPENGL_ES_2) - qt_glIsRenderbufferEXT = 0; - qt_glBindRenderbufferEXT = 0; - qt_glDeleteRenderbuffersEXT = 0; - qt_glGenRenderbuffersEXT = 0; - qt_glRenderbufferStorageEXT = 0; - qt_glGetRenderbufferParameterivEXT = 0; - qt_glIsFramebufferEXT = 0; - qt_glBindFramebufferEXT = 0; - qt_glDeleteFramebuffersEXT = 0; - qt_glGenFramebuffersEXT = 0; - qt_glCheckFramebufferStatusEXT = 0; - qt_glFramebufferTexture1DEXT = 0; - qt_glFramebufferTexture2DEXT = 0; - qt_glFramebufferTexture3DEXT = 0; - qt_glFramebufferRenderbufferEXT = 0; - qt_glGetFramebufferAttachmentParameterivEXT = 0; - qt_glGenerateMipmapEXT = 0; -#endif - - qt_glBindBufferARB = 0; - qt_glDeleteBuffersARB = 0; - qt_glGenBuffersARB = 0; - qt_glBufferDataARB = 0; + qt_glIsRenderbuffer = 0; + qt_glBindRenderbuffer = 0; + qt_glDeleteRenderbuffers = 0; + qt_glGenRenderbuffers = 0; + qt_glRenderbufferStorage = 0; + qt_glGetRenderbufferParameteriv = 0; + qt_glIsFramebuffer = 0; + qt_glBindFramebuffer = 0; + qt_glDeleteFramebuffers = 0; + qt_glGenFramebuffers = 0; + qt_glCheckFramebufferStatus = 0; + qt_glFramebufferTexture2D = 0; + qt_glFramebufferRenderbuffer = 0; + qt_glGetFramebufferAttachmentParameteriv = 0; + qt_glGenerateMipmap = 0; +#endif + qt_glBlitFramebufferEXT = 0; + qt_glRenderbufferStorageMultisampleEXT = 0; + + // Buffer objects: +#if !defined(QT_OPENGL_ES_2) + qt_glBindBuffer = 0; + qt_glDeleteBuffers = 0; + qt_glGenBuffers = 0; + qt_glBufferData = 0; +#endif qt_glMapBufferARB = 0; qt_glUnmapBufferARB = 0; } + +#if !defined(QT_OPENGL_ES_2) _glProgramStringARB qt_glProgramStringARB; _glBindProgramARB qt_glBindProgramARB; _glDeleteProgramsARB qt_glDeleteProgramsARB; @@ -218,8 +300,10 @@ struct QGLExtensionFuncs // GLSL definitions _glCreateShader qt_glCreateShader; _glShaderSource qt_glShaderSource; + _glShaderBinary qt_glShaderBinary; _glCompileShader qt_glCompileShader; _glDeleteShader qt_glDeleteShader; + _glIsShader qt_glIsShader; _glCreateProgram qt_glCreateProgram; _glAttachShader qt_glAttachShader; @@ -227,10 +311,13 @@ struct QGLExtensionFuncs _glLinkProgram qt_glLinkProgram; _glUseProgram qt_glUseProgram; _glDeleteProgram qt_glDeleteProgram; + _glIsProgram qt_glIsProgram; _glGetShaderInfoLog qt_glGetShaderInfoLog; _glGetShaderiv qt_glGetShaderiv; + _glGetShaderSource qt_glGetShaderSource; _glGetProgramiv qt_glGetProgramiv; + _glGetProgramInfoLog qt_glGetProgramInfoLog; _glGetUniformLocation qt_glGetUniformLocation; _glUniform4fv qt_glUniform4fv; @@ -238,38 +325,74 @@ struct QGLExtensionFuncs _glUniform2fv qt_glUniform2fv; _glUniform1fv qt_glUniform1fv; _glUniform1i qt_glUniform1i; + _glUniform1iv qt_glUniform1iv; + _glUniformMatrix2fv qt_glUniformMatrix2fv; + _glUniformMatrix3fv qt_glUniformMatrix3fv; + _glUniformMatrix4fv qt_glUniformMatrix4fv; + _glUniformMatrix2x3fv qt_glUniformMatrix2x3fv; + _glUniformMatrix2x4fv qt_glUniformMatrix2x4fv; + _glUniformMatrix3x2fv qt_glUniformMatrix3x2fv; + _glUniformMatrix3x4fv qt_glUniformMatrix3x4fv; + _glUniformMatrix4x2fv qt_glUniformMatrix4x2fv; + _glUniformMatrix4x3fv qt_glUniformMatrix4x3fv; + + _glBindAttribLocation qt_glBindAttribLocation; + _glGetAttribLocation qt_glGetAttribLocation; + _glVertexAttrib1fv qt_glVertexAttrib1fv; + _glVertexAttrib2fv qt_glVertexAttrib2fv; + _glVertexAttrib3fv qt_glVertexAttrib3fv; + _glVertexAttrib4fv qt_glVertexAttrib4fv; + _glVertexAttribPointer qt_glVertexAttribPointer; + _glDisableVertexAttribArray qt_glDisableVertexAttribArray; + _glEnableVertexAttribArray qt_glEnableVertexAttribArray; - _glActiveStencilFaceEXT qt_glActiveStencilFaceEXT; +#else + bool qt_glslResolved; + + _glGetProgramBinaryOES qt_glGetProgramBinaryOES; + _glProgramBinaryOES qt_glProgramBinaryOES; +#endif + _glActiveStencilFaceEXT qt_glActiveStencilFaceEXT; _glMultiTexCoord4f qt_glMultiTexCoord4f; + +#if !defined(QT_OPENGL_ES_2) + // Extras needed for GL2 engine: _glActiveTexture qt_glActiveTexture; + _glStencilOpSeparate qt_glStencilOpSeparate; +#endif + // FBOs #if !defined(QT_OPENGL_ES_2) - _glIsRenderbufferEXT qt_glIsRenderbufferEXT; - _glBindRenderbufferEXT qt_glBindRenderbufferEXT; - _glDeleteRenderbuffersEXT qt_glDeleteRenderbuffersEXT; - _glGenRenderbuffersEXT qt_glGenRenderbuffersEXT; - _glRenderbufferStorageEXT qt_glRenderbufferStorageEXT; - _glGetRenderbufferParameterivEXT qt_glGetRenderbufferParameterivEXT; - _glIsFramebufferEXT qt_glIsFramebufferEXT; - _glBindFramebufferEXT qt_glBindFramebufferEXT; - _glDeleteFramebuffersEXT qt_glDeleteFramebuffersEXT; - _glGenFramebuffersEXT qt_glGenFramebuffersEXT; - _glCheckFramebufferStatusEXT qt_glCheckFramebufferStatusEXT; - _glFramebufferTexture1DEXT qt_glFramebufferTexture1DEXT; - _glFramebufferTexture2DEXT qt_glFramebufferTexture2DEXT; - _glFramebufferTexture3DEXT qt_glFramebufferTexture3DEXT; - _glFramebufferRenderbufferEXT qt_glFramebufferRenderbufferEXT; - _glGetFramebufferAttachmentParameterivEXT qt_glGetFramebufferAttachmentParameterivEXT; - _glGenerateMipmapEXT qt_glGenerateMipmapEXT; -#endif - - _glBindBufferARB qt_glBindBufferARB; - _glDeleteBuffersARB qt_glDeleteBuffersARB; - _glGenBuffersARB qt_glGenBuffersARB; - _glBufferDataARB qt_glBufferDataARB; + _glIsRenderbuffer qt_glIsRenderbuffer; + _glBindRenderbuffer qt_glBindRenderbuffer; + _glDeleteRenderbuffers qt_glDeleteRenderbuffers; + _glGenRenderbuffers qt_glGenRenderbuffers; + _glRenderbufferStorage qt_glRenderbufferStorage; + _glGetRenderbufferParameteriv qt_glGetRenderbufferParameteriv; + _glIsFramebuffer qt_glIsFramebuffer; + _glBindFramebuffer qt_glBindFramebuffer; + _glDeleteFramebuffers qt_glDeleteFramebuffers; + _glGenFramebuffers qt_glGenFramebuffers; + _glCheckFramebufferStatus qt_glCheckFramebufferStatus; + _glFramebufferTexture2D qt_glFramebufferTexture2D; + _glFramebufferRenderbuffer qt_glFramebufferRenderbuffer; + _glGetFramebufferAttachmentParameteriv qt_glGetFramebufferAttachmentParameteriv; + _glGenerateMipmap qt_glGenerateMipmap; +#endif + _glBlitFramebufferEXT qt_glBlitFramebufferEXT; + _glRenderbufferStorageMultisampleEXT qt_glRenderbufferStorageMultisampleEXT; + + // Buffer objects +#if !defined(QT_OPENGL_ES_2) + _glBindBuffer qt_glBindBuffer; + _glDeleteBuffers qt_glDeleteBuffers; + _glGenBuffers qt_glGenBuffers; + _glBufferData qt_glBufferData; +#endif _glMapBufferARB qt_glMapBufferARB; _glUnmapBufferARB qt_glUnmapBufferARB; + }; @@ -397,6 +520,28 @@ struct QGLExtensionFuncs #define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 #endif +// GL_EXT_framebuffer_blit +#ifndef GL_READ_FRAMEBUFFER_EXT +#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 +#endif + +// GL_EXT_framebuffer_multisample +#ifndef GL_RENDERBUFFER_SAMPLES_EXT +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#endif + +#ifndef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#endif + +#ifndef GL_MAX_SAMPLES_EXT +#define GL_MAX_SAMPLES_EXT 0x8D5 +#endif + +#ifndef GL_DRAW_FRAMEBUFFER_EXT +#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 +#endif + #ifndef GL_EXT_packed_depth_stencil #define GL_DEPTH_STENCIL_EXT 0x84F9 #define GL_UNSIGNED_INT_24_8_EXT 0x84FA @@ -416,6 +561,42 @@ struct QGLExtensionFuncs #define GL_UNPACK_IMAGE_HEIGHT 0x806E #endif +#ifndef GL_VERSION_1_4 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#endif + +#ifndef GL_VERSION_2_0 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#endif + + +#if !defined(QT_OPENGL_ES_2) #define glProgramStringARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glProgramStringARB #define glBindProgramARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindProgramARB #define glDeleteProgramsARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteProgramsARB @@ -426,63 +607,52 @@ struct QGLExtensionFuncs #define glMultiTexCoord4f QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glMultiTexCoord4f -#if !defined(QT_OPENGL_ES_2) #define glActiveTexture QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glActiveTexture -#endif - -#if !defined(QT_OPENGL_ES_2) - -#define glIsRenderbufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsRenderbufferEXT -#define glBindRenderbufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindRenderbufferEXT -#define glDeleteRenderbuffersEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteRenderbuffersEXT -#define glGenRenderbuffersEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenRenderbuffersEXT -#define glRenderbufferStorageEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glRenderbufferStorageEXT -#define glGetRenderbufferParameterivEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetRenderbufferParameterivEXT -#define glIsFramebufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsFramebufferEXT -#define glBindFramebufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindFramebufferEXT -#define glDeleteFramebuffersEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteFramebuffersEXT -#define glGenFramebuffersEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenFramebuffersEXT -#define glCheckFramebufferStatusEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCheckFramebufferStatusEXT -#define glFramebufferTexture1DEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferTexture1DEXT -#define glFramebufferTexture2DEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferTexture2DEXT -#define glFramebufferTexture3DEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferTexture3DEXT -#define glFramebufferRenderbufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferRenderbufferEXT -#define glGetFramebufferAttachmentParameterivEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetFramebufferAttachmentParameterivEXT -#define glGenerateMipmapEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenerateMipmapEXT - -#else // QT_OPENGL_ES_2 +#endif // !defined(QT_OPENGL_ES_2) -#define glIsRenderbufferEXT glIsRenderbuffer -#define glBindRenderbufferEXT glBindRenderbuffer -#define glDeleteRenderbuffersEXT glDeleteRenderbuffers -#define glGenRenderbuffersEXT glGenRenderbuffers -#define glRenderbufferStorageEXT glRenderbufferStorage -#define glGetRenderbufferParameterivEXT glGetRenderbufferParameteriv -#define glIsFramebufferEXT glIsFramebuffer -#define glBindFramebufferEXT glBindFramebuffer -#define glDeleteFramebuffersEXT glDeleteFramebuffers -#define glGenFramebuffersEXT glGenFramebuffers -#define glCheckFramebufferStatusEXT glCheckFramebufferStatus -#define glFramebufferTexture1DEXT glFramebufferTexture1D -#define glFramebufferTexture2DEXT glFramebufferTexture2D -#define glFramebufferTexture3DEXT glFramebufferTexture3D -#define glFramebufferRenderbufferEXT glFramebufferRenderbuffer -#define glGetFramebufferAttachmentParameterivEXT glGetFramebufferAttachmentParameteriv -#define glGenerateMipmapEXT glGenerateMipmap +// FBOs +#if !defined(QT_OPENGL_ES_2) +#define glIsRenderbuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsRenderbuffer +#define glBindRenderbuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindRenderbuffer +#define glDeleteRenderbuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteRenderbuffers +#define glGenRenderbuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenRenderbuffers +#define glRenderbufferStorage QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glRenderbufferStorage +#define glGetRenderbufferParameteriv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetRenderbufferParameteriv +#define glIsFramebuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsFramebuffer +#define glBindFramebuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindFramebuffer +#define glDeleteFramebuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteFramebuffers +#define glGenFramebuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenFramebuffers +#define glCheckFramebufferStatus QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCheckFramebufferStatus +#define glFramebufferTexture2D QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferTexture2D +#define glFramebufferRenderbuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferRenderbuffer +#define glGetFramebufferAttachmentParameteriv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetFramebufferAttachmentParameteriv +#define glGenerateMipmap QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenerateMipmap #endif // QT_OPENGL_ES_2 +#define glBlitFramebufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBlitFramebufferEXT +#define glRenderbufferStorageMultisampleEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glRenderbufferStorageMultisampleEXT + -#define glBindBufferARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindBufferARB -#define glDeleteBuffersARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteBuffersARB -#define glGenBuffersARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenBuffersARB -#define glBufferDataARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBufferDataARB +// Buffer objects +#if !defined(QT_OPENGL_ES_2) +#define glBindBuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindBuffer +#define glDeleteBuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteBuffers +#define glGenBuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenBuffers +#define glBufferData QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBufferData +#endif #define glMapBufferARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glMapBufferARB #define glUnmapBufferARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUnmapBufferARB + +// GLSL +#if !defined(QT_OPENGL_ES_2) + #define glCreateShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCreateShader #define glShaderSource QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glShaderSource +#define glShaderBinary QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glShaderBinary #define glCompileShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCompileShader #define glDeleteShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteShader +#define glIsShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsShader #define glCreateProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCreateProgram #define glAttachShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glAttachShader @@ -490,10 +660,13 @@ struct QGLExtensionFuncs #define glLinkProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glLinkProgram #define glUseProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUseProgram #define glDeleteProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteProgram +#define glIsProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsProgram #define glGetShaderInfoLog QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderInfoLog #define glGetShaderiv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderiv +#define glGetShaderSource QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderSource #define glGetProgramiv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetProgramiv +#define glGetProgramInfoLog QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetProgramInfoLog #define glGetUniformLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetUniformLocation #define glUniform4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform4fv @@ -501,11 +674,48 @@ struct QGLExtensionFuncs #define glUniform2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform2fv #define glUniform1fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1fv #define glUniform1i QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1i +#define glUniform1iv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1iv +#define glUniformMatrix2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix2fv +#define glUniformMatrix3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix3fv +#define glUniformMatrix4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix4fv +#define glUniformMatrix2x3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix2x3fv +#define glUniformMatrix2x4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix2x4fv +#define glUniformMatrix3x2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix3x2fv +#define glUniformMatrix3x4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix3x4fv +#define glUniformMatrix4x2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix4x2fv +#define glUniformMatrix4x3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix4x3fv + +#define glBindAttribLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindAttribLocation +#define glGetAttribLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetAttribLocation +#define glVertexAttrib1fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib1fv +#define glVertexAttrib2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib2fv +#define glVertexAttrib3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib3fv +#define glVertexAttrib4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib4fv +#define glVertexAttribPointer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttribPointer +#define glDisableVertexAttribArray QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDisableVertexAttribArray +#define glEnableVertexAttribArray QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glEnableVertexAttribArray + +#else // QT_OPENGL_ES_2 + +#define glGetProgramBinaryOES QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetProgramBinaryOES +#define glProgramBinaryOES QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glProgramBinaryOES + +#endif // QT_OPENGL_ES_2 + + +#if !defined(QT_OPENGL_ES_2) +#define glStencilOpSeparate QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glStencilOpSeparate +#endif + +#if defined(QT_OPENGL_ES_2) +#define glClearDepth glClearDepthf +#endif extern bool qt_resolve_framebufferobject_extensions(QGLContext *ctx); bool qt_resolve_buffer_extensions(QGLContext *ctx); bool qt_resolve_version_1_3_functions(QGLContext *ctx); +bool qt_resolve_version_2_0_functions(QGLContext *ctx); bool qt_resolve_stencil_face_extension(QGLContext *ctx); bool qt_resolve_frag_program_extensions(QGLContext *ctx); diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 4ba9213..3e7ca0a 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -43,7 +43,12 @@ #include <qdebug.h> #include <private/qgl_p.h> +#include <private/qpaintengineex_opengl2_p.h> + +#ifndef QT_OPENGL_ES_2 #include <private/qpaintengine_opengl_p.h> +#endif + #include <qglframebufferobject.h> #include <qlibrary.h> #include <qimage.h> @@ -67,6 +72,215 @@ extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool); } \ } +class QGLFramebufferObjectFormatPrivate +{ +public: + int samples; + QGLFramebufferObject::Attachment attachment; + GLenum target; + GLenum internal_format; +}; + +/*! + \class QGLFramebufferObjectFormat + \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL + framebuffer object. + + \since 4.6 + + \ingroup multimedia + + A framebuffer object has several characteristics: + \list + \i \link setSamples() Number of samples per pixels.\endlink + \i \link setAttachment() Depth and/or stencil attachments.\endlink + \i \link setTextureTarget() Texture target.\endlink + \i \link setInternalFormat() Internal format.\endlink + \endlist + + Note that the desired attachments or number of samples per pixels might not + be supported by the hardware driver. Call QGLFramebufferObject::format() + after creating a QGLFramebufferObject to find the exact format that was + used to create the frame buffer object. + + \sa QGLFramebufferObject +*/ + +/*! + \since 4.6 + + Creates a QGLFramebufferObjectFormat object with properties specifying + the format of an OpenGL framebuffer object. + + A multisample framebuffer object is specified by setting \a samples + to a value different from zero. If the desired amount of samples per pixel is + not supported by the hardware then the maximum number of samples per pixel + will be used. Note that multisample framebuffer objects can not be bound as + textures. Also, the \c{GL_EXT_framebuffer_multisample} extension is required + to create a framebuffer with more than one sample per pixel. + + For multisample framebuffer objects a color render buffer is created, + otherwise a texture with the texture target \a target is created. + The color render buffer or texture will have the internal format + \a internalFormat, and will be bound to the \c GL_COLOR_ATTACHMENT0 + attachment in the framebuffer object. + + The \a attachment parameter describes the depth/stencil buffer + configuration. + + \sa samples(), attachment(), target(), internalFormat() +*/ + +QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(int samples, + QGLFramebufferObject::Attachment attachment, + GLenum target, + GLenum internalFormat) +{ + d = new QGLFramebufferObjectFormatPrivate; + d->samples = samples; + d->attachment = attachment; + d->target = target; + d->internal_format = internalFormat; +} + +/*! + \since 4.6 + + Constructs a copy of \a other. +*/ + +QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other) +{ + d = new QGLFramebufferObjectFormatPrivate; + *d = *other.d; +} + +/*! + \since 4.6 + + Assigns \a other to this object. +*/ + +QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other) +{ + *d = *other.d; + return *this; +} + +/*! + \since 4.6 + + Destroys the QGLFramebufferObjectFormat. +*/ +QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat() +{ + delete d; +} + +/*! + \since 4.6 + + Sets the number of samples per pixel for a multisample framebuffer object + to \a samples. + A sample count of 0 represents a regular non-multisample framebuffer object. + + \sa samples() +*/ +void QGLFramebufferObjectFormat::setSamples(int samples) +{ + d->samples = samples; +} + +/*! + \since 4.6 + + Returns the number of samples per pixel if a framebuffer object + is a multisample framebuffer object. Otherwise, returns 0. + + \sa setSamples() +*/ +int QGLFramebufferObjectFormat::samples() const +{ + return d->samples; +} + +/*! + \since 4.6 + + Sets the attachments a framebuffer object should have to \a attachment. + + \sa attachment() +*/ +void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment) +{ + d->attachment = attachment; +} + +/*! + \since 4.6 + + Returns the status of the depth and stencil buffers attached to + a framebuffer object. + + \sa setAttachment() +*/ +QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const +{ + return d->attachment; +} + +/*! + \since 4.6 + + Sets the texture target of the texture attached to a framebuffer object to + \a target. Ignored for multisample framebuffer objects. + + \sa textureTarget(), samples() +*/ +void QGLFramebufferObjectFormat::setTextureTarget(GLenum target) +{ + d->target = target; +} + +/*! + \since 4.6 + + Returns the texture target of the texture attached to a framebuffer object. + Ignored for multisample framebuffer objects. + + \sa setTextureTarget(), samples() +*/ +GLenum QGLFramebufferObjectFormat::textureTarget() const +{ + return d->target; +} + +/*! + \since 4.6 + + Sets the internal format of a framebuffer object's texture or multisample + framebuffer object's color buffer to \a internalFormat. + + \sa internalFormat() +*/ +void QGLFramebufferObjectFormat::setInternalFormat(GLenum internalFormat) +{ + d->internal_format = internalFormat; +} + +/*! + \since 4.6 + + Returns the internal format of a framebuffer object's texture or + multisample framebuffer object's color buffer. + + \sa setInternalFormat() +*/ +GLenum QGLFramebufferObjectFormat::internalFormat() const +{ + return d->internal_format; +} + class QGLFramebufferObjectPrivate { public: @@ -74,13 +288,16 @@ public: ~QGLFramebufferObjectPrivate() {} void init(const QSize& sz, QGLFramebufferObject::Attachment attachment, - GLenum internal_format, GLenum texture_target); + GLenum internal_format, GLenum texture_target, GLint samples = 0); bool checkFramebufferStatus() const; GLuint texture; GLuint fbo; GLuint depth_stencil_buffer; + GLuint color_buffer; GLenum target; QSize size; + QGLFramebufferObjectFormat format; + int samples; uint valid : 1; uint bound : 1; QGLFramebufferObject::Attachment fbo_attachment; @@ -90,7 +307,7 @@ public: bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const { - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); switch(status) { case GL_NO_ERROR: case GL_FRAMEBUFFER_COMPLETE_EXT: @@ -122,6 +339,9 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer."); break; + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: + qDebug("QGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel."); + break; default: qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status; break; @@ -130,7 +350,7 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const } void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::Attachment attachment, - GLenum texture_target, GLenum internal_format) + GLenum texture_target, GLenum internal_format, GLint samples) { ctx = const_cast<QGLContext *>(QGLContext::currentContext()); bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject); @@ -142,81 +362,137 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At // texture dimensions while (glGetError() != GL_NO_ERROR) {} // reset error state - glGenFramebuffersEXT(1, &fbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo); QT_CHECK_GLERROR(); // init texture - glGenTextures(1, &texture); - glBindTexture(target, texture); - glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); + if (samples == 0) { + glGenTextures(1, &texture); + glBindTexture(target, texture); + glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); #ifndef QT_OPENGL_ES - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); #else - glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); #endif - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - target, texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + target, texture, 0); - QT_CHECK_GLERROR(); - valid = checkFramebufferStatus(); + QT_CHECK_GLERROR(); + valid = checkFramebufferStatus(); + + color_buffer = 0; + samples = 0; + } else { + GLint maxSamples; + glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples); + + samples = qBound(1, int(samples), int(maxSamples)); + + glGenRenderbuffers(1, &color_buffer); + glBindRenderbuffer(GL_RENDERBUFFER_EXT, color_buffer); + if (glRenderbufferStorageMultisampleEXT) { + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, + internal_format, size.width(), size.height()); + } else { + samples = 0; + glRenderbufferStorage(GL_RENDERBUFFER_EXT, internal_format, + size.width(), size.height()); + } + + glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, color_buffer); + + QT_CHECK_GLERROR(); + valid = checkFramebufferStatus(); + + if (valid) + glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples); + } if (attachment == QGLFramebufferObject::CombinedDepthStencil && (QGLExtensions::glExtensions & QGLExtensions::PackedDepthStencil)) { // depth and stencil buffer needs another extension - glGenRenderbuffersEXT(1, &depth_stencil_buffer); - Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer)); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer); - Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer)); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, size.width(), size.height()); + glGenRenderbuffers(1, &depth_stencil_buffer); + Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer)); + glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer); + Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer)); + if (samples != 0 && glRenderbufferStorageMultisampleEXT) + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, + GL_DEPTH24_STENCIL8_EXT, size.width(), size.height()); + else + glRenderbufferStorage(GL_RENDERBUFFER_EXT, + GL_DEPTH24_STENCIL8_EXT, size.width(), size.height()); + GLint i = 0; - glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i); + glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_buffer); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_buffer); fbo_attachment = QGLFramebufferObject::CombinedDepthStencil; + valid = checkFramebufferStatus(); if (!valid) - glDeleteRenderbuffersEXT(1, &depth_stencil_buffer); + glDeleteRenderbuffers(1, &depth_stencil_buffer); } else if (attachment == QGLFramebufferObject::Depth || attachment == QGLFramebufferObject::CombinedDepthStencil) { - glGenRenderbuffersEXT(1, &depth_stencil_buffer); - Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer)); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer); - Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer)); + glGenRenderbuffers(1, &depth_stencil_buffer); + Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer)); + glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer); + Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer)); + if (samples != 0 && glRenderbufferStorageMultisampleEXT) { #ifdef QT_OPENGL_ES #define GL_DEPTH_COMPONENT16 0x81A5 - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height()); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, + GL_DEPTH_COMPONENT16, size.width(), size.height()); #else - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height()); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, + GL_DEPTH_COMPONENT, size.width(), size.height()); #endif + } else { +#ifdef QT_OPENGL_ES +#define GL_DEPTH_COMPONENT16 0x81A5 + glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height()); +#else + glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height()); +#endif + } GLint i = 0; - glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i); + glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_buffer); fbo_attachment = QGLFramebufferObject::Depth; valid = checkFramebufferStatus(); if (!valid) - glDeleteRenderbuffersEXT(1, &depth_stencil_buffer); + glDeleteRenderbuffers(1, &depth_stencil_buffer); } else { fbo_attachment = QGLFramebufferObject::NoAttachment; } - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); if (!valid) { - glDeleteTextures(1, &texture); - glDeleteFramebuffersEXT(1, &fbo); + if (color_buffer) + glDeleteRenderbuffers(1, &color_buffer); + else + glDeleteTextures(1, &texture); + glDeleteFramebuffers(1, &fbo); } QT_CHECK_GLERROR(); + + format.setTextureTarget(target); + format.setSamples(int(samples)); + format.setAttachment(fbo_attachment); + format.setInternalFormat(internal_format); } /*! @@ -264,13 +540,18 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At framebuffer objects more portable. \endlist - Note that primitives drawn to a QGLFramebufferObject with QPainter - will only be antialiased if the QPainter::HighQualityAntialiasing - render hint is set. This is because there is currently no support - for the \c{GL_EXT_framebuffer_multisample} extension, which is - required to do multisample based antialiasing. Also note that the - QPainter::HighQualityAntialiasing render hint requires the - \c{GL_ARB_fragment_program} extension to work in OpenGL. + Note that you need to create a QGLFramebufferObject with more than one + sample per pixel for primitives to be antialiased when drawing using a + QPainter, unless if the QPainter::HighQualityAntialiasing render hint is + set. The QPainter::HighQualityAntialiasing render hint will enable + antialiasing as long as the \c{GL_ARB_fragment_program} extension is + present. To create a multisample framebuffer object you should use one of + the constructors that take a QGLFramebufferObject parameter, and set the + QGLFramebufferObject::samples() property to a non-zero value. + + If you want to use a framebuffer object with multisampling enabled + as a texture, you first need to copy from it to a regular framebuffer + object using QGLContext::blitFramebuffer(). \sa {Framebuffer Object Example} */ @@ -358,6 +639,32 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target) d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT); } +/*! \overload + + Constructs an OpenGL framebuffer object of the given \a size based on the + supplied \a format. +*/ + +QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format) + : d_ptr(new QGLFramebufferObjectPrivate) +{ + Q_D(QGLFramebufferObject); + d->init(size, format.attachment(), format.textureTarget(), format.internalFormat(), format.samples()); +} + +/*! \overload + + Constructs an OpenGL framebuffer object of the given \a width and \a height + based on the supplied \a format. +*/ + +QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format) + : d_ptr(new QGLFramebufferObjectPrivate) +{ + Q_D(QGLFramebufferObject); + d->init(QSize(width, height), format.attachment(), format.textureTarget(), format.internalFormat(), format.samples()); +} + #ifdef Q_MAC_COMPAT_GL_FUNCTIONS /*! \internal */ QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLenum target) @@ -445,9 +752,11 @@ QGLFramebufferObject::~QGLFramebufferObject() || qgl_share_reg()->checkSharing(d->ctx, QGLContext::currentContext()))) { glDeleteTextures(1, &d->texture); + if (d->color_buffer) + glDeleteRenderbuffers(1, &d->color_buffer); if (d->depth_stencil_buffer) - glDeleteRenderbuffersEXT(1, &d->depth_stencil_buffer); - glDeleteFramebuffersEXT(1, &d->fbo); + glDeleteRenderbuffers(1, &d->depth_stencil_buffer); + glDeleteFramebuffers(1, &d->fbo); } delete d_ptr; } @@ -490,13 +799,15 @@ bool QGLFramebufferObject::bind() return false; Q_D(QGLFramebufferObject); QGL_FUNC_CONTEXT; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->fbo); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo); d->bound = d->valid = d->checkFramebufferStatus(); const QGLContext *context = QGLContext::currentContext(); if (d->valid && context) { // Save the previous setting to automatically restore in release(). - d->previous_fbo = context->d_ptr->current_fbo; - context->d_ptr->current_fbo = d->fbo; + if (context->d_ptr->current_fbo != d->fbo) { + d->previous_fbo = context->d_ptr->current_fbo; + context->d_ptr->current_fbo = d->fbo; + } } return d->valid; } @@ -520,18 +831,19 @@ bool QGLFramebufferObject::release() return false; Q_D(QGLFramebufferObject); QGL_FUNC_CONTEXT; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - d->valid = d->checkFramebufferStatus(); d->bound = false; + const QGLContext *context = QGLContext::currentContext(); - if (d->valid && context) { + if (context) { // Restore the previous setting for stacked framebuffer objects. - context->d_ptr->current_fbo = d->previous_fbo; - if (d->previous_fbo) - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->previous_fbo); + if (d->previous_fbo != context->d_ptr->current_fbo) { + context->d_ptr->current_fbo = d->previous_fbo; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->previous_fbo); + } d->previous_fbo = 0; } - return d->valid; + + return true; } /*! @@ -540,6 +852,9 @@ bool QGLFramebufferObject::release() Returns the texture id for the texture attached as the default rendering target in this framebuffer object. This texture id can be bound as a normal texture in your own GL code. + + If a multisample framebuffer object is used then the value returned + from this function will be invalid. */ GLuint QGLFramebufferObject::texture() const { @@ -560,6 +875,15 @@ QSize QGLFramebufferObject::size() const } /*! + Returns the format of this framebuffer object. +*/ +const QGLFramebufferObjectFormat &QGLFramebufferObject::format() const +{ + Q_D(const QGLFramebufferObject); + return d->format; +} + +/*! \fn QImage QGLFramebufferObject::toImage() const Returns the contents of this framebuffer object as a QImage. @@ -577,17 +901,27 @@ QImage QGLFramebufferObject::toImage() const return image; } -#if !defined(QT_OPENGL_ES_2) -Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine) +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine) +#endif + +#ifndef QT_OPENGL_ES_2 +Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine) #endif /*! \reimp */ QPaintEngine *QGLFramebufferObject::paintEngine() const { -#if !defined(QT_OPENGL_ES_2) - return qt_buffer_paintengine(); +#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) + return qt_buffer_engine(); +#elif defined(QT_OPENGL_ES_2) + return qt_buffer_2_engine(); #else - return 0; + Q_D(const QGLFramebufferObject); + if (d->ctx->d_func()->internal_context || qt_gl_preferGL2Engine()) + return qt_buffer_2_engine(); + else + return qt_buffer_engine(); #endif } @@ -599,7 +933,8 @@ QPaintEngine *QGLFramebufferObject::paintEngine() const */ bool QGLFramebufferObject::hasOpenGLFramebufferObjects() { - QGLWidget dmy; // needed to detect and init the QGLExtensions object + if (!QGLContext::currentContext()) + QGLWidget dmy; // needed to detect and init the QGLExtensions object return (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject); } @@ -654,15 +989,16 @@ void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint te } #endif -extern int qt_defaultDpi(); +extern int qt_defaultDpiX(); +extern int qt_defaultDpiY(); /*! \reimp */ int QGLFramebufferObject::metric(PaintDeviceMetric metric) const { Q_D(const QGLFramebufferObject); - float dpmx = qt_defaultDpi()*100./2.54; - float dpmy = qt_defaultDpi()*100./2.54; + float dpmx = qt_defaultDpiX()*100./2.54; + float dpmy = qt_defaultDpiY()*100./2.54; int w = d->size.width(); int h = d->size.height(); switch (metric) { @@ -685,16 +1021,16 @@ int QGLFramebufferObject::metric(PaintDeviceMetric metric) const return 32;//d->depth; case PdmDpiX: - return (int)(dpmx * 0.0254); + return qRound(dpmx * 0.0254); case PdmDpiY: - return (int)(dpmy * 0.0254); + return qRound(dpmy * 0.0254); case PdmPhysicalDpiX: - return (int)(dpmx * 0.0254); + return qRound(dpmx * 0.0254); case PdmPhysicalDpiY: - return (int)(dpmy * 0.0254); + return qRound(dpmy * 0.0254); default: qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric); @@ -750,4 +1086,85 @@ bool QGLFramebufferObject::isBound() const return d->bound; } +/*! + \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit() + + \since 4.6 + + Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension + is present on this system; otherwise returns false. +*/ +bool QGLFramebufferObject::hasOpenGLFramebufferBlit() +{ + if (!QGLContext::currentContext()) + QGLWidget dmy; // needed to detect and init the QGLExtensions object + return (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit); +} + +/*! + \since 4.6 + + Blits from the \a sourceRect rectangle in the \a source framebuffer + object to the \a targetRect rectangle in the \a target framebuffer object. + + If \a source or \a target is 0, the default framebuffer will be used + instead of a framebuffer object as source or target respectively. + + The \a buffers parameter should be a mask consisting of any combination of + COLOR_BUFFER_BIT, DEPTH_BUFFER_BIT, and STENCIL_BUFFER_BIT. Any buffer type + that is not present both in the source and target buffers is ignored. + + The \a sourceRect and \a targetRect rectangles may have different sizes; + in this case \a buffers should not contain DEPTH_BUFFER_BIT or + STENCIL_BUFFER_BIT. The \a filter parameter should be set to GL_LINEAR or + GL_NEAREST, and specifies whether linear or nearest interpolation should + be used when scaling is performed. + + If \a source equals \a target a copy is performed within the same buffer. + Results are undefined if the source and target rectangles overlap and + have different sizes. The sizes must also be the same if any of the + framebuffer objects are multisample framebuffers. + + Note that the scissor test will restrict the blit area if enabled. + + This function will have no effect unless hasOpenGLFramebufferBlit() returns + true. +*/ +void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect, + QGLFramebufferObject *source, const QRect &sourceRect, + GLbitfield buffers, + GLenum filter) +{ + if (!(QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)) + return; + + const QGLContext *ctx = QGLContext::currentContext(); + if (!ctx) + return; + + const int height = ctx->device()->height(); + + const int sh = source ? source->height() : height; + const int th = target ? target->height() : height; + + const int sx0 = sourceRect.left(); + const int sx1 = sourceRect.left() + sourceRect.width(); + const int sy0 = sh - (sourceRect.top() + sourceRect.height()); + const int sy1 = sh - sourceRect.top(); + + const int tx0 = targetRect.left(); + const int tx1 = targetRect.left() + targetRect.width(); + const int ty0 = th - (targetRect.top() + targetRect.height()); + const int ty1 = th - targetRect.top(); + + glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0); + + glBlitFramebufferEXT(sx0, sy0, sx1, sy1, + tx0, ty0, tx1, ty1, + buffers, filter); + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); +} + QT_END_NAMESPACE diff --git a/src/opengl/qglframebufferobject.h b/src/opengl/qglframebufferobject.h index a9e1b2f..0a2a9d2 100644 --- a/src/opengl/qglframebufferobject.h +++ b/src/opengl/qglframebufferobject.h @@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(OpenGL) class QGLFramebufferObjectPrivate; +class QGLFramebufferObjectFormat; class Q_OPENGL_EXPORT QGLFramebufferObject : public QPaintDevice { @@ -77,6 +78,9 @@ public: GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA); #endif + QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format); + QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format); + #ifdef Q_MAC_COMPAT_GL_FUNCTIONS QGLFramebufferObject(const QSize &size, QMacCompatGLenum target = GL_TEXTURE_2D); QGLFramebufferObject(int width, int height, QMacCompatGLenum target = GL_TEXTURE_2D); @@ -89,10 +93,13 @@ public: virtual ~QGLFramebufferObject(); + const QGLFramebufferObjectFormat &format() const; + bool isValid() const; bool isBound() const; bool bind(); bool release(); + GLuint texture() const; QSize size() const; QImage toImage() const; @@ -110,6 +117,12 @@ public: void drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget = GL_TEXTURE_2D); #endif + static bool hasOpenGLFramebufferBlit(); + static void blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect, + QGLFramebufferObject *source, const QRect &sourceRect, + GLbitfield buffers = GL_COLOR_BUFFER_BIT, + GLenum filter = GL_NEAREST); + protected: int metric(PaintDeviceMetric metric) const; int devType() const { return QInternal::FramebufferObject; } @@ -120,6 +133,42 @@ private: friend class QGLDrawable; }; +class QGLFramebufferObjectFormatPrivate; +class Q_OPENGL_EXPORT QGLFramebufferObjectFormat +{ +public: +#if !defined(QT_OPENGL_ES) || defined(Q_QDOC) + QGLFramebufferObjectFormat(int samples = 0, + QGLFramebufferObject::Attachment attachment = QGLFramebufferObject::NoAttachment, + GLenum target = GL_TEXTURE_2D, + GLenum internalFormat = GL_RGBA8); +#else + QGLFramebufferObjectFormat(int samples = 0, + QGLFramebufferObject::Attachment attachment = QGLFramebufferObject::NoAttachment, + GLenum target = GL_TEXTURE_2D, + GLenum internalFormat = GL_RGBA); +#endif + + QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other); + QGLFramebufferObjectFormat &operator=(const QGLFramebufferObjectFormat &other); + ~QGLFramebufferObjectFormat(); + + void setSamples(int samples); + int samples() const; + + void setAttachment(QGLFramebufferObject::Attachment attachment); + QGLFramebufferObject::Attachment attachment() const; + + void setTextureTarget(GLenum target); + GLenum textureTarget() const; + + void setInternalFormat(GLenum internalFormat); + GLenum internalFormat() const; + +private: + QGLFramebufferObjectFormatPrivate *d; +}; + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 5f74f26..483856a 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -76,12 +76,13 @@ \sa {opengl/pbuffers}{Pbuffers Example} */ +#include <private/qpaintengineex_opengl2_p.h> #include <qglpixelbuffer.h> #include <private/qglpixelbuffer_p.h> #include <qimage.h> -#if !defined(QT_OPENGL_ES_2) +#ifndef QT_OPENGL_ES_2 #include <private/qpaintengine_opengl_p.h> #endif @@ -363,29 +364,39 @@ bool QGLPixelBuffer::isValid() const return !d->invalid; } -#if !defined(QT_OPENGL_ES_2) -Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine) +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine) +#endif + +#ifndef QT_OPENGL_ES_2 +Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine) #endif /*! \reimp */ QPaintEngine *QGLPixelBuffer::paintEngine() const { -#if !defined(QT_OPENGL_ES_2) - return qt_buffer_paintengine(); +#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) + return qt_buffer_engine(); +#elif defined(QT_OPENGL_ES_2) + return qt_buffer_2_engine(); #else - return 0; + if (d_ptr->qctx->d_func()->internal_context || qt_gl_preferGL2Engine()) + return qt_buffer_2_engine(); + else + return qt_buffer_engine(); #endif } -extern int qt_defaultDpi(); +extern int qt_defaultDpiX(); +extern int qt_defaultDpiY(); /*! \reimp */ int QGLPixelBuffer::metric(PaintDeviceMetric metric) const { Q_D(const QGLPixelBuffer); - float dpmx = qt_defaultDpi()*100./2.54; - float dpmy = qt_defaultDpi()*100./2.54; + float dpmx = qt_defaultDpiX()*100./2.54; + float dpmy = qt_defaultDpiY()*100./2.54; int w = d->req_size.width(); int h = d->req_size.height(); switch (metric) { @@ -408,16 +419,16 @@ int QGLPixelBuffer::metric(PaintDeviceMetric metric) const return 32;//d->depth; case PdmDpiX: - return (int)(dpmx * 0.0254); + return qRound(dpmx * 0.0254); case PdmDpiY: - return (int)(dpmy * 0.0254); + return qRound(dpmy * 0.0254); case PdmPhysicalDpiX: - return (int)(dpmx * 0.0254); + return qRound(dpmx * 0.0254); case PdmPhysicalDpiY: - return (int)(dpmy * 0.0254); + return qRound(dpmy * 0.0254); default: qWarning("QGLPixelBuffer::metric(), Unhandled metric type: %d\n", metric); diff --git a/src/opengl/qglpixelbuffer_mac.mm b/src/opengl/qglpixelbuffer_mac.mm index 9a679b1..e95e36b 100644 --- a/src/opengl/qglpixelbuffer_mac.mm +++ b/src/opengl/qglpixelbuffer_mac.mm @@ -299,9 +299,8 @@ void QGLPixelBuffer::releaseFromDynamicTexture() GLuint QGLPixelBuffer::generateDynamicTexture() const { - Q_D(const QGLPixelBuffer); - #ifdef QT_MAC_USE_COCOA + Q_D(const QGLPixelBuffer); NSOpenGLContext *oldContext = [NSOpenGLContext currentContext]; if (d->share_ctx != oldContext) [static_cast<NSOpenGLContext *>(d->share_ctx) makeCurrentContext]; diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index ff23948..275bbed 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -45,27 +45,12 @@ #include "qpaintengine_opengl_p.h" #include "qglpixelbuffer.h" -#include "qglextensions_p.h" +#include "qglshaderprogram.h" #include "qgl_p.h" #include "private/qapplication_p.h" -#ifndef GL_FRAGMENT_SHADER -#define GL_FRAGMENT_SHADER 0x8B30 -#endif - -#ifndef GL_COMPILE_STATUS -#define GL_COMPILE_STATUS 0x8B81 -#endif - -#ifndef GL_LINK_STATUS -#define GL_LINK_STATUS 0x8B82 -#endif - - - - QT_BEGIN_NAMESPACE @@ -79,117 +64,6 @@ void QGLPixmapFilterBase::drawImpl(QPainter *painter, const QPointF &pos, const processGL(painter, pos, src, source); } -QGLSLProgram::QGLSLProgram(const QString &src) - : ctx(QGLContext::currentContext()) -{ - if (!qt_resolve_glsl_extensions(const_cast<QGLContext *>(ctx))) { - qWarning("Failed to resolve GLSL functions"); - m_valid = false; - return; - } - - m_shader = glCreateShader(GL_FRAGMENT_SHADER); - - const QByteArray src_ba = src.toAscii(); - const char *src_cstr = src_ba.constData(); - - glShaderSource(m_shader, 1, &src_cstr, 0); - glCompileShader(m_shader); - glGetShaderiv(m_shader, GL_COMPILE_STATUS, &m_valid); - if (!m_valid) { - char data[4096]; - GLsizei len; - glGetShaderInfoLog(m_shader, 4096, &len, data); - qWarning("Failed to compile GLSL shader:\n%s\nCODE:\n%s\n", data, src_cstr); - return; - } - - m_program = glCreateProgram(); - glAttachShader(m_program, m_shader); - glLinkProgram(m_program); - glGetProgramiv(m_program, GL_LINK_STATUS, &m_valid); - if (!m_valid) { - char data[4096]; - GLsizei len; - glGetShaderInfoLog(m_shader, 4096, &len, data); - qWarning("Failed to link GLSL program:\n%s\nCODE:\n%s\n", data, src_cstr); - return; - } -} - -QGLSLProgram::~QGLSLProgram() -{ - glDeleteProgram(m_program); - glDeleteShader(m_shader); -} - -bool QGLSLProgram::success() const -{ - return m_valid; -} - -void QGLSLProgram::enable() -{ - glUseProgram(m_program); -} - -void QGLSLProgram::disable() -{ - glUseProgram(0); -} - -typedef GLuint (APIENTRY *_glGetUniformLocation) (GLuint, const char*); -typedef void (APIENTRY *_glUniform4fv) (GLint, GLsizei, GLfloat *); -typedef void (APIENTRY *_glUniform3fv) (GLint, GLsizei, GLfloat *); -typedef void (APIENTRY *_glUniform2fv) (GLint, GLsizei, GLfloat *); -typedef void (APIENTRY *_glUniform1fv) (GLint, GLsizei, GLfloat *); -typedef void (APIENTRY *_glUniform1i) (GLint, GLint); - -int QGLSLProgram::getUniformLocation(const QString &name) -{ - return glGetUniformLocation(m_program, name.toAscii().constData()); -} - -void QGLSLProgram::setUniform(int uniform, int value) -{ - enable(); - glUniform1i(uniform, value); -} - -void QGLSLProgram::setUniform(int uniform, qreal value) -{ - enable(); - GLfloat v[] = { value }; - glUniform1fv(uniform, 1, v); -} - -void QGLSLProgram::setUniform(int uniform, qreal v1, qreal v2) -{ - enable(); - GLfloat v[] = { v1, v2 }; - glUniform2fv(uniform, 1, v); -} - -void QGLSLProgram::setUniform(int uniform, qreal v1, qreal v2, qreal v3) -{ - enable(); - GLfloat v[] = { v1, v2, v3 }; - glUniform3fv(uniform, 1, v); -} - -void QGLSLProgram::setUniform(int uniform, qreal v1, qreal v2, qreal v3, qreal v4) -{ - enable(); - GLfloat v[] = { v1, v2, v3, v4 }; - glUniform4fv(uniform, 1, v); -} - -void QGLSLProgram::setUniform(int uniform, int count, float *v) -{ - enable(); - glUniform1fv(uniform, count, v); -} - class QGLPixmapColorizeFilter: public QGLPixmapFilter<QPixmapColorizeFilter> { public: @@ -199,8 +73,8 @@ protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &pixmap, const QRectF &srcRect) const; private: - mutable QGLSLProgram m_program; - uint m_colorUniform; + mutable QGLShaderProgram m_program; + int m_colorUniform; }; class QGLPixmapConvolutionFilter: public QGLPixmapFilter<QPixmapConvolutionFilter> @@ -213,11 +87,11 @@ protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const; private: - QString generateConvolutionShader() const; + QByteArray generateConvolutionShader() const; - mutable QGLSLProgram *m_program; - mutable uint m_scaleUniform; - mutable uint m_matrixUniform; + mutable QGLShaderProgram *m_program; + mutable int m_scaleUniform; + mutable int m_matrixUniform; mutable int m_kernelWidth; mutable int m_kernelHeight; @@ -242,10 +116,8 @@ QPixmapFilter *QGLContextPrivate::createPixmapFilter(int type) const return 0; } -#if !defined(QT_OPENGL_ES_2) extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array); extern void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array); -#endif static void qgl_drawTexture(const QRectF &rect, int tx_width, int tx_height, const QRectF & src) { @@ -294,10 +166,12 @@ static const char *qt_gl_colorize_filter = "}"; QGLPixmapColorizeFilter::QGLPixmapColorizeFilter() - : m_program(QLatin1String(qt_gl_colorize_filter)) { - m_program.setUniform(m_program.getUniformLocation(QLatin1String("texture")), 0); // GL_TEXTURE_0 - m_colorUniform = m_program.getUniformLocation(QLatin1String("color")); + m_program.addShader(QGLShader::FragmentShader, qt_gl_colorize_filter); + m_program.link(); + m_program.enable(); + m_program.setUniformValue(m_program.uniformLocation("texture"), GLint(0)); // GL_TEXTURE_0 + m_colorUniform = m_program.uniformLocation("color"); } bool QGLPixmapColorizeFilter::processGL(QPainter *, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const @@ -305,10 +179,10 @@ bool QGLPixmapColorizeFilter::processGL(QPainter *, const QPointF &pos, const QP bindTexture(src); QColor col = color(); - m_program.setUniform(m_colorUniform, col.redF(), col.greenF(), col.blueF()); + m_program.enable(); + m_program.setUniformValue(m_colorUniform, col.redF(), col.greenF(), col.blueF()); QRectF target = (srcRect.isNull() ? QRectF(src.rect()) : srcRect).translated(pos); - m_program.enable(); qgl_drawTexture(target, src.width(), src.height(), srcRect); m_program.disable(); @@ -316,17 +190,17 @@ bool QGLPixmapColorizeFilter::processGL(QPainter *, const QPointF &pos, const QP } // generates convolution filter code for arbitrary sized kernel -QString QGLPixmapConvolutionFilter::generateConvolutionShader() const { +QByteArray QGLPixmapConvolutionFilter::generateConvolutionShader() const { QByteArray code; - code.append("uniform sampler2D texture;\n"); - code.append("uniform vec2 inv_texture_size;\n"); - code.append("uniform float matrix["); + code.append("uniform sampler2D texture;\n" + "uniform vec2 inv_texture_size;\n" + "uniform float matrix["); code.append(QByteArray::number(m_kernelWidth * m_kernelHeight)); - code.append("];\n"); - code.append("vec2 offset["); + code.append("];\n" + "vec2 offset["); code.append(QByteArray::number(m_kernelWidth*m_kernelHeight)); - code.append("];\n"); - code.append("void main(void) {\n"); + code.append("];\n" + "void main(void) {\n"); for(int y = 0; y < m_kernelHeight; y++) { for(int x = 0; x < m_kernelWidth; x++) { @@ -336,23 +210,22 @@ QString QGLPixmapConvolutionFilter::generateConvolutionShader() const { code.append(QByteArray::number(x-(int)(m_kernelWidth/2))); code.append(".0, inv_texture_size.y * "); code.append(QByteArray::number((int)(m_kernelHeight/2)-y)); - code.append(".0)"); - code.append(";\n"); + code.append(".0);\n"); } } - code.append(" int i = 0;\n"); - code.append(" vec2 coords = gl_TexCoord[0].st;\n"); - code.append(" vec4 sum = vec4(0.0);\n"); - code.append(" for (i = 0; i < "); + code.append(" int i = 0;\n" + " vec2 coords = gl_TexCoord[0].st;\n" + " vec4 sum = vec4(0.0);\n" + " for (i = 0; i < "); code.append(QByteArray::number(m_kernelWidth * m_kernelHeight)); - code.append("; i++) {\n"); - code.append(" vec4 tmp = texture2D(texture,coords+offset[i]);\n"); - code.append(" sum += matrix[i] * tmp;\n"); - code.append(" }\n"); - code.append(" gl_FragColor = sum;\n"); - code.append("}"); - return QLatin1String(code); + code.append("; i++) {\n" + " vec4 tmp = texture2D(texture,coords+offset[i]);\n" + " sum += matrix[i] * tmp;\n" + " }\n" + " gl_FragColor = sum;\n" + "}"); + return code; } QGLPixmapConvolutionFilter::QGLPixmapConvolutionFilter() @@ -384,10 +257,12 @@ bool QGLPixmapConvolutionFilter::processGL(QPainter *, const QPointF &pos, const m_kernelWidth = columns(); m_kernelHeight = rows(); - QString code = generateConvolutionShader(); - m_program = new QGLSLProgram(code); - m_scaleUniform = m_program->getUniformLocation(QLatin1String("inv_texture_size")); - m_matrixUniform = m_program->getUniformLocation(QLatin1String("matrix")); + QByteArray code = generateConvolutionShader(); + m_program = new QGLShaderProgram(); + m_program->addShader(QGLShader::FragmentShader, code); + m_program->link(); + m_scaleUniform = m_program->uniformLocation("inv_texture_size"); + m_matrixUniform = m_program->uniformLocation("matrix"); } const qreal *kernel = convolutionKernel(); @@ -397,10 +272,10 @@ bool QGLPixmapConvolutionFilter::processGL(QPainter *, const QPointF &pos, const const qreal iw = 1.0 / src.width(); const qreal ih = 1.0 / src.height(); - m_program->setUniform(m_scaleUniform, iw, ih); - m_program->setUniform(m_matrixUniform, m_kernelWidth * m_kernelHeight, conv); - m_program->enable(); + m_program->setUniformValue(m_scaleUniform, iw, ih); + m_program->setUniformValueArray(m_matrixUniform, conv, m_kernelWidth * m_kernelHeight, 1); + qgl_drawTexture(target, src.width(), src.height(), boundingRectFor(srcRect)); m_program->disable(); return true; diff --git a/src/opengl/qglpixmapfilter_p.h b/src/opengl/qglpixmapfilter_p.h index dc2eea6..d6742fc 100644 --- a/src/opengl/qglpixmapfilter_p.h +++ b/src/opengl/qglpixmapfilter_p.h @@ -87,35 +87,6 @@ public: } }; -class Q_OPENGL_EXPORT QGLSLProgram -{ -public: - QGLSLProgram(const QString &src); - ~QGLSLProgram(); - - bool success() const; - - void enable(); - void disable(); - - int getUniformLocation(const QString &name); - - void setUniform(int uniform, int value); - void setUniform(int uniform, qreal value); - void setUniform(int uniform, qreal v1, qreal v2); - void setUniform(int uniform, qreal v1, qreal v2, qreal v3); - void setUniform(int uniform, qreal v1, qreal v2, qreal v3, qreal v4); - void setUniform(int uniform, int count, float *v); - -private: - GLuint m_shader; - GLuint m_program; - - GLint m_valid; - - const QGLContext *ctx; -}; - QT_END_NAMESPACE QT_END_HEADER diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp new file mode 100644 index 0000000..d74b930 --- /dev/null +++ b/src/opengl/qglshaderprogram.cpp @@ -0,0 +1,2992 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglshaderprogram.h" +#include "qglextensions_p.h" +#include "qgl_p.h" +#include <QtCore/qdebug.h> +#include <QtCore/qfile.h> +#include <QtCore/qvarlengtharray.h> +#include <QtCore/qvector.h> + +QT_BEGIN_NAMESPACE + +#if !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + +/*! + \class QGLShaderProgram + \brief The QGLShaderProgram class allows OpenGL shader programs to be linked and used. + \since 4.6 + + \section1 Introduction + + This class supports shader programs written in the OpenGL Shading + Language (GLSL) and in the OpenGL/ES Shading Language (GLSL/ES). + + QGLShader and QGLShaderProgram shelter the programmer from the details of + compiling and linking vertex and fragment shaders. + + The following example creates a vertex shader program using the + supplied source \c{code}. Once compiled and linked, the shader + program is activated in the current QGLContext by calling + QGLShaderProgram::enable(): + + \code + QGLShader shader(QGLShader::VertexShader); + shader.setSourceCode(code); + + QGLShaderProgram program(context); + program.addShader(shader); + program.link(); + + program.enable(); + \endcode + + \section1 Writing portable shaders + + Shader programs can be difficult to reuse across OpenGL implementations + because of varying levels of support for standard vertex attributes and + uniform variables. In particular, GLSL/ES lacks all of the + standard variables that are present on desktop OpenGL systems: + \c{gl_Vertex}, \c{gl_Normal}, \c{gl_Color}, and so on. Desktop OpenGL + lacks the variable qualifiers \c{highp}, \c{mediump}, and \c{lowp}. + + The QGLShaderProgram class makes the process of writing portable shaders + easier by prefixing all shader programs with the following lines on + desktop OpenGL: + + \code + #define highp + #define mediump + #define lowp + \endcode + + This makes it possible to run most GLSL/ES shader programs + on desktop systems. The programmer should restrict themselves + to just features that are present in GLSL/ES, and avoid + standard variable names that only work on the desktop. + + \section1 Simple shader example + + \code + program.addShader(QGLShader::VertexShader, + "attribute highp vec4 vertex;\n" + "attribute mediump mat4 matrix;\n" + "void main(void)\n" + "{\n" + " gl_Position = matrix * vertex;\n" + "}"); + program.addShader(QGLShader::FragmentShader, + "uniform mediump vec4 color;\n" + "void main(void)\n" + "{\n" + " gl_FragColor = color;\n" + "}"); + program.link(); + program.enable(); + + int vertexLocation = program.attributeLocation("vertex"); + int matrixLocation = program.attributeLocation("matrix"); + int colorLocation = program.uniformLocation("color"); + \endcode + + With the above shader program active, we can draw a green triangle + as follows: + + \code + static GLfloat const triangleVertices[] = { + 60.0f, 10.0f, 0.0f, + 110.0f, 110.0f, 0.0f, + 10.0f, 110.0f, 0.0f + }; + + QColor color(0, 255, 0, 255); + + QMatrix4x4 pmvMatrix; + pmvMatrix.ortho(rect()); + + program.setAttributeArray(vertexLocation, triangleVertices, 3); + program.setUniformValue(matrixLocation, pmvMatrix); + program.setUniformValue(colorLocation, color); + + glDrawArrays(GL_TRIANGLES, 0, 3); + \endcode + + \section1 Partial shaders + + Desktop GLSL can attach an arbitrary number of vertex and fragment + shaders to a shader program. Embedded GLSL/ES on the other hand + supports only a single shader of each type on a shader program. + + Multiple shaders of the same type can be useful when large libraries + of shaders are needed. Common functions can be factored out into + library shaders that can be reused in multiple shader programs. + + To support this use of shaders, the application programmer can + create shaders with the QGLShader::PartialVertexShader and + QGLShader::PartialFragmentShader types. These types direct + QGLShader and QGLShaderProgram to delay shader compilation until + link time. + + When link() is called, the sources for the partial shaders are + concatenated, and a single vertex or fragment shader is compiled + and linked into the shader program. + + It is more efficient to use the QGLShader::VertexShader and + QGLShader::FragmentShader when there is only one shader of that + type in the program. + + \sa QGLShader +*/ + +/*! + \class QGLShader + \brief The QGLShader class allows OpenGL shaders to be compiled. + \since 4.6 + + This class supports shaders written in the OpenGL Shading Language (GLSL) + and in the OpenGL/ES Shading Language (GLSL/ES). + + QGLShader and QGLShaderProgram shelter the programmer from the details of + compiling and linking vertex and fragment shaders. + + \sa QGLShaderProgram +*/ + +/*! + \enum QGLShader::ShaderType + This enum specifies the type of QGLShader that is being created. + + \value VertexShader Vertex shader written in the OpenGL Shading Language (GLSL). + \value FragmentShader Fragment shader written in the OpenGL Shading Language (GLSL). + \value PartialVertexShader Partial vertex shader that will be concatenated with all other partial vertex shaders at link time. + \value PartialFragmentShader Partial fragment shader that will be concatenated with all other partial fragment shaders at link time. +*/ + +#ifndef GL_FRAGMENT_SHADER +#define GL_FRAGMENT_SHADER 0x8B30 +#endif +#ifndef GL_VERTEX_SHADER +#define GL_VERTEX_SHADER 0x8B31 +#endif +#ifndef GL_COMPILE_STATUS +#define GL_COMPILE_STATUS 0x8B81 +#endif +#ifndef GL_LINK_STATUS +#define GL_LINK_STATUS 0x8B82 +#endif +#ifndef GL_INFO_LOG_LENGTH +#define GL_INFO_LOG_LENGTH 0x8B84 +#endif +#ifndef GL_ACTIVE_UNIFORMS +#define GL_ACTIVE_UNIFORMS 0x8B86 +#endif +#ifndef GL_ACTIVE_UNIFORM_MAX_LENGTH +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#endif +#ifndef GL_ACTIVE_ATTRIBUTES +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#endif +#ifndef GL_ACTIVE_ATTRIBUTE_MAX_LENGTH +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#endif +#ifndef GL_CURRENT_VERTEX_ATTRIB +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#endif +#ifndef GL_SHADER_SOURCE_LENGTH +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#endif +#ifndef GL_SHADER_BINARY_FORMATS +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#endif +#ifndef GL_NUM_SHADER_BINARY_FORMATS +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#endif + +class QGLShaderPrivate +{ +public: + QGLShaderPrivate(QGLShader::ShaderType type, const QGLContext *ctx) + { + context = ctx; + shader = 0; + shaderType = type; + compiled = false; + isPartial = (type == QGLShader::PartialVertexShader || + type == QGLShader::PartialFragmentShader); + hasPartialSource = false; + } + + const QGLContext *context; + GLuint shader; + QGLShader::ShaderType shaderType; + bool compiled; + bool isPartial; + bool hasPartialSource; + QString log; + QByteArray partialSource; + + bool create(); + bool compile(); +}; + +#define ctx context + +bool QGLShaderPrivate::create() +{ + if (isPartial) + return true; + if (!context) + context = QGLContext::currentContext(); + if (!context) + return false; + if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) { + if (shaderType == QGLShader::VertexShader) + shader = glCreateShader(GL_VERTEX_SHADER); + else + shader = glCreateShader(GL_FRAGMENT_SHADER); + if (!shader) { + qWarning() << "QGLShader: could not create shader"; + return false; + } + return true; + } else { + return false; + } +} + +bool QGLShaderPrivate::compile() +{ + // Partial shaders are compiled during QGLShaderProgram::link(). + if (isPartial && hasPartialSource) { + compiled = true; + return true; + } + if (!shader) + return false; + glCompileShader(shader); + GLint value = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &value); + compiled = (value != 0); + value = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &value); + if (!compiled && value > 1) { + char *logbuf = new char [value]; + GLint len; + glGetShaderInfoLog(shader, value, &len, logbuf); + log = QString::fromLatin1(logbuf); + qWarning() << "QGLShader::compile:" << log; + delete [] logbuf; + } + return compiled; +} + +#undef ctx +#define ctx d->context + +/*! + Constructs a new QGLShader object of the specified \a type + and attaches it to \a parent. If shader programs are not supported, + then isValid() will return false. + + This constructor is normally followed by a call to setSourceCode() + or setSourceCodeFile(). + + The shader will be associated with the current QGLContext. + + \sa setSourceCode(), setSourceCodeFile(), isValid() +*/ +QGLShader::QGLShader(QGLShader::ShaderType type, QObject *parent) + : QObject(parent) +{ + d = new QGLShaderPrivate(type, QGLContext::currentContext()); + d->create(); +} + +/*! + Constructs a new QGLShader object from the source code in \a fileName + and attaches it to \a parent. If the filename ends in \c{.fsh}, + it is assumed to be a fragment shader, otherwise it is assumed to + be a vertex shader (normally the extension is \c{.vsh} for vertex shaders). + If the shader could not be loaded, then isValid() will return false. + + The shader will be associated with the current QGLContext. + + \sa isValid() +*/ +QGLShader::QGLShader(const QString& fileName, QObject *parent) + : QObject(parent) +{ + if (fileName.endsWith(QLatin1String(".fsh"), Qt::CaseInsensitive)) + d = new QGLShaderPrivate(QGLShader::FragmentShader, QGLContext::currentContext()); + else + d = new QGLShaderPrivate(QGLShader::VertexShader, QGLContext::currentContext()); + if (d->create() && !setSourceCodeFile(fileName)) { + if (d->shader) + glDeleteShader(d->shader); + d->shader = 0; + } +} + +/*! + Constructs a new QGLShader object of the specified \a type from the + source code in \a fileName and attaches it to \a parent. + If the shader could not be loaded, then isValid() will return false. + + The shader will be associated with the current QGLContext. + + \sa isValid() +*/ +QGLShader::QGLShader + (const QString& fileName, QGLShader::ShaderType type, QObject *parent) + : QObject(parent) +{ + d = new QGLShaderPrivate(type, QGLContext::currentContext()); + if (d->create() && !setSourceCodeFile(fileName)) { + if (d->shader) + glDeleteShader(d->shader); + d->shader = 0; + } +} + +/*! + Constructs a new QGLShader object of the specified \a type + and attaches it to \a parent. If shader programs are not supported, + then isValid() will return false. + + This constructor is normally followed by a call to setSourceCode() + or setSourceCodeFile(). + + The shader will be associated with \a context. + + \sa setSourceCode(), setSourceCodeFile(), isValid() +*/ +QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent) + : QObject(parent) +{ + d = new QGLShaderPrivate(type, context); + d->create(); +} + +/*! + Constructs a new QGLShader object from the source code in \a fileName + and attaches it to \a parent. If the filename ends in \c{.fsh}, + it is assumed to be a fragment shader, otherwise it is assumed to + be a vertex shader (normally the extension is \c{.vsh} for vertex shaders). + If the shader could not be loaded, then isValid() will return false. + + The shader will be associated with \a context. + + \sa isValid() +*/ +QGLShader::QGLShader(const QString& fileName, const QGLContext *context, QObject *parent) + : QObject(parent) +{ + if (fileName.endsWith(QLatin1String(".fsh"), Qt::CaseInsensitive)) + d = new QGLShaderPrivate(QGLShader::FragmentShader, context); + else + d = new QGLShaderPrivate(QGLShader::VertexShader, context); + if (d->create() && !setSourceCodeFile(fileName)) { + if (d->shader) + glDeleteShader(d->shader); + d->shader = 0; + } +} + +/*! + Constructs a new QGLShader object of the specified \a type from the + source code in \a fileName and attaches it to \a parent. + If the shader could not be loaded, then isValid() will return false. + + The shader will be associated with \a context. + + \sa isValid() +*/ +QGLShader::QGLShader + (const QString& fileName, QGLShader::ShaderType type, const QGLContext *context, QObject *parent) + : QObject(parent) +{ + d = new QGLShaderPrivate(type, context); + if (d->create() && !setSourceCodeFile(fileName)) { + if (d->shader) + glDeleteShader(d->shader); + d->shader = 0; + } +} + +/*! + Deletes this shader. If the shader has been attached to a + QGLShaderProgram object, then the actual shader will stay around + until the QGLShaderProgram is destroyed. +*/ +QGLShader::~QGLShader() +{ + if (d->shader) + glDeleteShader(d->shader); + delete d; +} + +/*! + Returns true if this shader is valid. Shaders become invalid + when they are destroyed and no longer attached to a QGLShaderProgram. +*/ +bool QGLShader::isValid() const +{ + if (d->isPartial && d->hasPartialSource) + return true; + if (!d->shader) + return false; +#if defined(QT_OPENGL_ES_2) + return glIsShader(d->shader); +#else + // glIsShader() may not exist on some systems. + return (!glIsShader || glIsShader(d->shader)); +#endif +} + +/*! + Returns the type of this shader. +*/ +QGLShader::ShaderType QGLShader::shaderType() const +{ + return d->shaderType; +} + +// The precision qualifiers are useful on OpenGL/ES systems, +// but usually not present on desktop systems. Define the +// keywords to empty strings on desktop systems. +#ifndef QT_OPENGL_ES +#define QGL_DEFINE_QUALIFIERS 1 +static const char qualifierDefines[] = + "#define lowp\n" + "#define mediump\n" + "#define highp\n"; +#endif + +/*! + Sets the \a source code for this shader and compiles it. + Returns true if the source was successfully compiled, false otherwise. + + If shaderType() is PartialVertexShader or PartialFragmentShader, + then this function will always return true, even if the source code + is invalid. Partial shaders are compiled when QGLShaderProgram::link() + is called. +*/ +bool QGLShader::setSourceCode(const char *source) +{ + if (d->isPartial) { + d->partialSource = QByteArray(source); + d->hasPartialSource = true; + return d->compile(); + } else if (d->shader) { + QVarLengthArray<const char *> src; +#ifdef QGL_DEFINE_QUALIFIERS + src.append(qualifierDefines); +#endif + src.append(source); + glShaderSource(d->shader, src.size(), src.data(), 0); + return d->compile(); + } else { + return false; + } +} + +/*! + \overload + + Sets the \a source code for this shader and compiles it. + Returns true if the source was successfully compiled, false otherwise. + + If shaderType() is PartialVertexShader or PartialFragmentShader, + then this function will always return true, even if the source code + is invalid. Partial shaders are compiled when QGLShaderProgram::link() + is called. +*/ +bool QGLShader::setSourceCode(const QByteArray& source) +{ + return setSourceCode(source.constData()); +} + +/*! + \overload + + Sets the \a source code for this shader and compiles it. + Returns true if the source was successfully compiled, false otherwise. + + If shaderType() is PartialVertexShader or PartialFragmentShader, + then this function will always return true, even if the source code + is invalid. Partial shaders are compiled when QGLShaderProgram::link() + is called. +*/ +bool QGLShader::setSourceCode(const QString& source) +{ + return setSourceCode(source.toLatin1().constData()); +} + +/*! + Sets the source code for this shader to the contents of \a fileName + and compiles it. Returns true if the file could be opened and the + source compiled, false otherwise. + + If shaderType() is PartialVertexShader or PartialFragmentShader, + then this function will always return true, even if the source code + is invalid. Partial shaders are compiled when QGLShaderProgram::link() + is called. +*/ +bool QGLShader::setSourceCodeFile(const QString& fileName) +{ + QFile file(fileName); + if (!file.open(QFile::ReadOnly)) { + qWarning() << "QGLShader: Unable to open file" << fileName; + return false; + } + + QByteArray contents = file.readAll(); + return setSourceCode(contents.constData()); +} + +/*! + Sets the binary code for this shader to the \a length bytes from + the array \a binary. The \a format specifies how the binary data + should be interpreted by the OpenGL engine. Returns true if the + binary was set on the shader; false otherwise. + + This function cannot be used with PartialVertexShader or + PartialFragmentShader. + + \sa shaderBinaryFormats() +*/ +bool QGLShader::setBinaryCode(GLenum format, const void *binary, int length) +{ +#if !defined(QT_OPENGL_ES_2) + if (!glShaderBinary) + return false; +#endif + if (d->isPartial || !d->shader) + return false; + glGetError(); // Clear error state. + glShaderBinary(1, &(d->shader), format, binary, length); + return (glGetError() == GL_NO_ERROR); +} + +/*! + Sets the binary code for this shader to the \a length bytes from + the array \a binary. The \a format specifies how the binary data + should be interpreted by the OpenGL engine. Returns true if the + binary was set on the shader; false otherwise. + + The \a otherShader will also have binary code set on it. This is + for the case where \a binary contains both vertex and fragment + shader code. + + This function cannot be used with PartialVertexShader or + PartialFragmentShader. + + \sa shaderBinaryFormats() +*/ +bool QGLShader::setBinaryCode + (QGLShader& otherShader, GLenum format, const void *binary, int length) +{ +#if !defined(QT_OPENGL_ES_2) + if (!glShaderBinary) + return false; +#endif + if (d->isPartial || !d->shader) + return false; + if (otherShader.d->isPartial || !otherShader.d->shader) + return false; + glGetError(); // Clear error state. + GLuint shaders[2]; + shaders[0] = d->shader; + shaders[1] = otherShader.d->shader; + glShaderBinary(2, shaders, format, binary, length); + return (glGetError() == GL_NO_ERROR); +} + +/*! + Returns a list of all binary formats that are supported by + setBinaryCode() on this system. + + \sa setBinaryCode() +*/ +QList<GLenum> QGLShader::shaderBinaryFormats() +{ + GLint num; + QList<GLenum> list; + glGetError(); // Clear error state. + glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &num); + if (glGetError() != GL_NO_ERROR || num <= 0) + return list; + QVarLengthArray<GLint> formats(num); + glGetIntegerv(GL_SHADER_BINARY_FORMATS, formats.data()); + for (GLint i = 0; i < num; ++i) + list += (GLenum)(formats[i]); + return list; +} + +/*! + Returns the source code for this shader. + + \sa setSourceCode() +*/ +QByteArray QGLShader::sourceCode() const +{ + if (d->isPartial) + return d->partialSource; + if (!d->shader) + return QByteArray(); + GLint size = 0; + glGetShaderiv(d->shader, GL_SHADER_SOURCE_LENGTH, &size); + if (size <= 0) + return QByteArray(); + GLint len = 0; + char *source = new char [size]; + glGetShaderSource(d->shader, size, &len, source); + QByteArray src(source); + delete [] source; + return src; +} + +/*! + Returns true if this shader has been compiled; false otherwise. + + \sa setSourceCode() +*/ +bool QGLShader::isCompiled() const +{ + return d->compiled; +} + +/*! + Returns the errors and warnings that occurred during the last compile. + + \sa setSourceCode() +*/ +QString QGLShader::log() const +{ + return d->log; +} + +/*! + Returns the OpenGL identifier associated with this shader. + + If shaderType() is PartialVertexShader or PartialFragmentShader, + this function will always return zero. Partial shaders are + created and compiled when QGLShaderProgram::link() is called. + + \sa QGLShaderProgram::programId() +*/ +GLuint QGLShader::shaderId() const +{ + return d->shader; +} + +#undef ctx +#define ctx context + +class QGLShaderProgramPrivate +{ +public: + QGLShaderProgramPrivate(const QGLContext *ctx) + { + context = ctx; + program = 0; + linked = false; + inited = false; + hasPartialShaders = false; + vertexShader = 0; + fragmentShader = 0; + } + ~QGLShaderProgramPrivate() + { + if (program) + glDeleteProgram(program); + } + + const QGLContext *context; + GLuint program; + bool linked; + bool inited; + bool hasPartialShaders; + QString log; + QList<QGLShader *> shaders; + QList<QGLShader *> anonShaders; + QGLShader *vertexShader; + QGLShader *fragmentShader; +}; + +#undef ctx +#define ctx d->context + +/*! + Constructs a new shader program and attaches it to \a parent. + The program will be invalid until addShader() is called. + + The shader program will be associated with the current QGLContext. + + \sa isValid(), addShader() +*/ +QGLShaderProgram::QGLShaderProgram(QObject *parent) + : QObject(parent) +{ + d = new QGLShaderProgramPrivate(QGLContext::currentContext()); +} + +/*! + Constructs a new shader program and attaches it to \a parent. + The program will be invalid until addShader() is called. + + The shader program will be associated with \a context. + + \sa isValid(), addShader() +*/ +QGLShaderProgram::QGLShaderProgram(const QGLContext *context, QObject *parent) + : QObject(parent) +{ + d = new QGLShaderProgramPrivate(context); +} + +/*! + Deletes this shader program. +*/ +QGLShaderProgram::~QGLShaderProgram() +{ + delete d; +} + +bool QGLShaderProgram::init() +{ + if (d->program || d->inited) + return true; + d->inited = true; + if (!d->context) + d->context = QGLContext::currentContext(); + if (!d->context) + return false; + if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(d->context))) { + d->program = glCreateProgram(); + if (!(d->program)) { + qWarning() << "QGLShaderProgram: could not create shader program"; + return false; + } + return true; + } else { + qWarning() << "QGLShaderProgram: shader programs are not supported"; + return false; + } +} + +/*! + Returns true if this shader program object is valid, false otherwise. +*/ +bool QGLShaderProgram::isValid() const +{ + if (!d->program) + return false; +#if defined(QT_OPENGL_ES_2) + return glIsProgram(d->program); +#else + // glIsProgram() may not exist on some systems. + return (!glIsProgram || glIsProgram(d->program)); +#endif +} + +/*! + Adds a compiled \a shader to this shader program. Returns true + if the shader could be added, or false otherwise. + + Ownership of the \a shader object remains with the caller. + It will not be deleted when this QGLShaderProgram instance + is deleted. This allows the caller to add the same shader + to multiple shader programs. + + \sa removeShader(), link(), removeAllShaders() +*/ +bool QGLShaderProgram::addShader(QGLShader *shader) +{ + if (!init()) + return false; + if (d->shaders.contains(shader)) + return true; // Already added to this shader program. + if (d->program && shader) { + if (!shader->d->compiled) + return false; + if (!shader->d->isPartial) { + if (!shader->d->shader) + return false; + glAttachShader(d->program, shader->d->shader); + } else { + d->hasPartialShaders = true; + } + d->linked = false; // Program needs to be relinked. + d->shaders.append(shader); + return true; + } else { + return false; + } +} + +/*! + Compiles \a source as a shader of the specified \a type and + adds it to this shader program. Returns true if compilation + was successful, false otherwise. The compilation errors + and warnings will be made available via log(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QGLShader first. + + \sa removeShader(), link(), log(), removeAllShaders() +*/ +bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const char *source) +{ + if (!init()) + return false; + QGLShader *shader = new QGLShader(type, this); + if (!shader->setSourceCode(source)) { + d->log = shader->log(); + delete shader; + return false; + } + d->anonShaders.append(shader); + return addShader(shader); +} + +/*! + \overload + + Compiles \a source as a shader of the specified \a type and + adds it to this shader program. Returns true if compilation + was successful, false otherwise. The compilation errors + and warnings will be made available via log(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QGLShader first. + + \sa removeShader(), link(), log(), removeAllShaders() +*/ +bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QByteArray& source) +{ + return addShader(type, source.constData()); +} + +/*! + \overload + + Compiles \a source as a shader of the specified \a type and + adds it to this shader program. Returns true if compilation + was successful, false otherwise. The compilation errors + and warnings will be made available via log(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QGLShader first. + + \sa removeShader(), link(), log(), removeAllShaders() +*/ +bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QString& source) +{ + return addShader(type, source.toLatin1().constData()); +} + +/*! + Removes \a shader from this shader program. The object is not deleted. + + \sa addShader(), link(), removeAllShaders() +*/ +void QGLShaderProgram::removeShader(QGLShader *shader) +{ + if (d->program && shader && shader->d->shader) { + glDetachShader(d->program, shader->d->shader); + d->linked = false; // Program needs to be relinked. + } + d->shaders.removeAll(shader); + d->anonShaders.removeAll(shader); +} + +/*! + Returns a list of all shaders that have been added to this shader + program using addShader(). + + \sa addShader(), removeShader() +*/ +QList<QGLShader *> QGLShaderProgram::shaders() const +{ + return d->shaders; +} + +/*! + Removes all of the shaders that were added to this program previously. + The QGLShader objects for the shaders will not be deleted if they + were constructed externally. QGLShader objects that are constructed + internally by QGLShaderProgram will be deleted. + + \sa addShader(), removeShader() +*/ +void QGLShaderProgram::removeAllShaders() +{ + foreach (QGLShader *shader, d->shaders) { + if (d->program && shader && shader->d->shader) + glDetachShader(d->program, shader->d->shader); + } + foreach (QGLShader *shader, d->anonShaders) { + // Delete shader objects that were created anonymously. + delete shader; + } + d->shaders.clear(); + d->anonShaders.clear(); + d->linked = false; // Program needs to be relinked. +} + +#if defined(QT_OPENGL_ES_2) + +#ifndef GL_PROGRAM_BINARY_LENGTH_OES +#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 +#endif +#ifndef GL_NUM_PROGRAM_BINARY_FORMATS_OES +#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE +#endif +#ifndef GL_PROGRAM_BINARY_FORMATS_OES +#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF +#endif + +#endif + +/*! + Returns the program binary associated with this shader program. + The numeric identifier of the program binary format is returned + in \a format. The \c OES_get_program_binary extension will need + to be supported by the system for binary retrieval to succeed. + + Returns an empty QByteArray if the program binary cannot be + retrieved on this system, or the shader program has not yet + been linked. + + The returned binary can be supplied to setProgramBinary() on the + same machine at some future point to reload the program. It contains + the compiled code of all of the shaders that were attached to the + program at the time programBinary() is called. + + \sa setProgramBinary(), programBinaryFormats() +*/ +QByteArray QGLShaderProgram::programBinary(int *format) const +{ +#if defined(QT_OPENGL_ES_2) + if (!isLinked()) + return QByteArray(); + + // Get the length of the binary data, bailing out if there is none. + GLint length = 0; + glGetProgramiv(d->program, GL_PROGRAM_BINARY_LENGTH_OES, &length); + if (length <= 0) + return QByteArray(); + + // Retrieve the binary data. + QByteArray binary(length, 0); + GLenum binaryFormat; + glGetProgramBinaryOES(d->program, length, 0, &binaryFormat, binary.data()); + if (format) + *format = (int)binaryFormat; + return binary; +#else + Q_UNUSED(format); + return QByteArray(); +#endif +} + +/*! + Sets the \a binary for this shader program according to \a format. + Returns true if the binary was set, or false if the binary format + is not supported or this system does not support program binaries. + The program will be linked if the load succeeds. + + \sa programBinary(), programBinaryFormats(), isLinked() +*/ +bool QGLShaderProgram::setProgramBinary(int format, const QByteArray& binary) +{ +#if defined(QT_OPENGL_ES_2) + // Load the binary and check that it was linked correctly. + glProgramBinaryOES(d->program, (GLenum)format, + binary.constData(), binary.size()); + GLint value = 0; + glGetProgramiv(d->program, GL_LINK_STATUS, &value); + d->linked = (value != 0); + value = 0; + glGetProgramiv(d->program, GL_INFO_LOG_LENGTH, &value); + d->log = QString(); + if (value > 1) { + char *logbuf = new char [value]; + GLint len; + glGetProgramInfoLog(d->program, value, &len, logbuf); + d->log = QString::fromLatin1(logbuf); + qWarning() << "QGLShaderProgram::setProgramBinary:" << d->log; + delete [] logbuf; + } + return d->linked; +#else + Q_UNUSED(format); + Q_UNUSED(binary); + return false; +#endif +} + +/*! + Returns the list of program binary formats that are accepted by + this system for use with setProgramBinary(). + + \sa programBinary(), setProgramBinary() +*/ +QList<int> QGLShaderProgram::programBinaryFormats() +{ +#if defined(QT_OPENGL_ES_2) + GLint count = 0; + glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &count); + if (count <= 0) + return QList<int>(); + QVector<int> list; + list.resize(count); + glGetIntegerv(GL_PROGRAM_BINARY_FORMATS_OES, list.data()); + return list.toList(); +#else + return QList<int>(); +#endif +} + +/*! + Links together the shaders that were added to this program with + addShader(). Returns true if the link was successful or + false otherwise. If the link failed, the error messages can + be retrieved with log(). + + Subclasses can override this function to initialize attributes + and uniform variables for use in specific shader programs. + + If the shader program was already linked, calling this + function again will force it to be re-linked. + + \sa addShader(), log() +*/ +bool QGLShaderProgram::link() +{ + if (!d->program) + return false; + if (d->hasPartialShaders) { + // Compile the partial vertex and fragment shaders. + QByteArray vertexSource; + QByteArray fragmentSource; + foreach (QGLShader *shader, d->shaders) { + if (shader->shaderType() == QGLShader::PartialVertexShader) + vertexSource += shader->sourceCode(); + else if (shader->shaderType() == QGLShader::PartialFragmentShader) + fragmentSource += shader->sourceCode(); + } + if (vertexSource.isEmpty()) { + if (d->vertexShader) { + glDetachShader(d->program, d->vertexShader->d->shader); + delete d->vertexShader; + d->vertexShader = 0; + } + } else { + if (!d->vertexShader) { + d->vertexShader = + new QGLShader(QGLShader::VertexShader, this); + } + if (!d->vertexShader->setSourceCode(vertexSource)) { + d->log = d->vertexShader->log(); + return false; + } + glAttachShader(d->program, d->vertexShader->d->shader); + } + if (fragmentSource.isEmpty()) { + if (d->fragmentShader) { + glDetachShader(d->program, d->fragmentShader->d->shader); + delete d->fragmentShader; + d->fragmentShader = 0; + } + } else { + if (!d->fragmentShader) { + d->fragmentShader = + new QGLShader(QGLShader::FragmentShader, this); + } + if (!d->fragmentShader->setSourceCode(fragmentSource)) { + d->log = d->fragmentShader->log(); + return false; + } + glAttachShader(d->program, d->fragmentShader->d->shader); + } + } + glLinkProgram(d->program); + GLint value = 0; + glGetProgramiv(d->program, GL_LINK_STATUS, &value); + d->linked = (value != 0); + value = 0; + glGetProgramiv(d->program, GL_INFO_LOG_LENGTH, &value); + d->log = QString(); + if (value > 1) { + char *logbuf = new char [value]; + GLint len; + glGetProgramInfoLog(d->program, value, &len, logbuf); + d->log = QString::fromLatin1(logbuf); + qWarning() << "QGLShaderProgram::link:" << d->log; + delete [] logbuf; + } + return d->linked; +} + +/*! + Returns true if this shader program has been linked; false otherwise. + + \sa link() +*/ +bool QGLShaderProgram::isLinked() const +{ + return d->linked; +} + +/*! + Returns the errors and warnings that occurred during the last link() + or addShader() with explicitly specified source code. + + \sa link() +*/ +QString QGLShaderProgram::log() const +{ + return d->log; +} + +/*! + Enable use of this shader program in the currently active QGLContext. + Returns true if the program was successfully enabled; false + otherwise. If the shader program has not yet been linked, + or it needs to be re-linked, this function will call link(). + + \sa link(), disable() +*/ +bool QGLShaderProgram::enable() +{ + if (!d->program) + return false; + if (!d->linked && !link()) + return false; + glUseProgram(d->program); + return true; +} + +#undef ctx +#define ctx QGLContext::currentContext() + +/*! + Disables the active shader program in the current QGLContext. + This is equivalent to calling \c{glUseProgram(0)}. + + \sa enable() +*/ +void QGLShaderProgram::disable() +{ +#if defined(QT_OPENGL_ES_2) + glUseProgram(0); +#else + if (glUseProgram) + glUseProgram(0); +#endif +} + +#undef ctx +#define ctx d->context + +/*! + Returns the OpenGL identifier associated with this shader program. + + \sa QGLShader::shaderId() +*/ +GLuint QGLShaderProgram::programId() const +{ + return d->program; +} + +/*! + Binds the attribute \a name to the specified \a location. This + function can be called before or after the program has been linked. + Any attributes that have not been explicitly bound when the program + is linked will be assigned locations automatically. + + \sa attributeLocation() +*/ +void QGLShaderProgram::bindAttributeLocation(const char *name, int location) +{ + glBindAttribLocation(d->program, location, name); +} + +/*! + \overload + + Binds the attribute \a name to the specified \a location. This + function can be called before or after the program has been linked. + Any attributes that have not been explicitly bound when the program + is linked will be assigned locations automatically. + + \sa attributeLocation() +*/ +void QGLShaderProgram::bindAttributeLocation(const QByteArray& name, int location) +{ + glBindAttribLocation(d->program, location, name.constData()); +} + +/*! + \overload + + Binds the attribute \a name to the specified \a location. This + function can be called before or after the program has been linked. + Any attributes that have not been explicitly bound when the program + is linked will be assigned locations automatically. + + \sa attributeLocation() +*/ +void QGLShaderProgram::bindAttributeLocation(const QString& name, int location) +{ + glBindAttribLocation(d->program, location, name.toLatin1().constData()); +} + +/*! + Returns the location of the attribute \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + attribute for this shader program. + + \sa uniformLocation(), bindAttributeLocation() +*/ +int QGLShaderProgram::attributeLocation(const char *name) const +{ + if (d->linked) { + return glGetAttribLocation(d->program, name); + } else { + qWarning() << "QGLShaderProgram::attributeLocation(" << name + << "): shader program is not linked"; + return -1; + } +} + +/*! + \overload + + Returns the location of the attribute \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + attribute for this shader program. + + \sa uniformLocation(), bindAttributeLocation() +*/ +int QGLShaderProgram::attributeLocation(const QByteArray& name) const +{ + return attributeLocation(name.constData()); +} + +/*! + \overload + + Returns the location of the attribute \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + attribute for this shader program. + + \sa uniformLocation(), bindAttributeLocation() +*/ +int QGLShaderProgram::attributeLocation(const QString& name) const +{ + return attributeLocation(name.toLatin1().constData()); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, GLfloat value) +{ + if (location != -1) + glVertexAttrib1fv(location, &value); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, GLfloat value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to + the 2D vector (\a x, \a y). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, GLfloat x, GLfloat y) +{ + if (location != -1) { + GLfloat values[2] = {x, y}; + glVertexAttrib2fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to + the 2D vector (\a x, \a y). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, GLfloat x, GLfloat y) +{ + setAttributeValue(attributeLocation(name), x, y); +} + +/*! + Sets the attribute at \a location in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (int location, GLfloat x, GLfloat y, GLfloat z) +{ + if (location != -1) { + GLfloat values[3] = {x, y, z}; + glVertexAttrib3fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (const char *name, GLfloat x, GLfloat y, GLfloat z) +{ + setAttributeValue(attributeLocation(name), x, y, z); +} + +/*! + Sets the attribute at \a location in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + if (location != -1) { + GLfloat values[4] = {x, y, z, w}; + glVertexAttrib4fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + setAttributeValue(attributeLocation(name), x, y, z, w); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, const QVector2D& value) +{ + if (location != -1) + glVertexAttrib2fv(location, reinterpret_cast<const GLfloat *>(&value)); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, const QVector2D& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, const QVector3D& value) +{ + if (location != -1) + glVertexAttrib3fv(location, reinterpret_cast<const GLfloat *>(&value)); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, const QVector3D& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, const QVector4D& value) +{ + if (location != -1) + glVertexAttrib4fv(location, reinterpret_cast<const GLfloat *>(&value)); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, const QVector4D& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, const QColor& value) +{ + if (location != -1) { + GLfloat values[4] = {value.redF(), value.greenF(), value.blueF(), value.alphaF()}; + glVertexAttrib4fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, const QColor& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to the + contents of \a values, which contains \a columns elements, each + consisting of \a rows elements. The \a rows value should be + 1, 2, 3, or 4. This function is typically used to set matrix + values and column vectors. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (int location, const GLfloat *values, int columns, int rows) +{ + if (rows < 1 || rows > 4) { + qWarning() << "QGLShaderProgram::setAttributeValue: rows" << rows << "not supported"; + return; + } + if (location != -1) { + while (columns-- > 0) { + if (rows == 1) + glVertexAttrib1fv(location, values); + else if (rows == 2) + glVertexAttrib2fv(location, values); + else if (rows == 3) + glVertexAttrib3fv(location, values); + else + glVertexAttrib4fv(location, values); + values += rows; + ++location; + } + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to the + contents of \a values, which contains \a columns elements, each + consisting of \a rows elements. The \a rows value should be + 1, 2, 3, or 4. This function is typically used to set matrix + values and column vectors. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (const char *name, const GLfloat *values, int columns, int rows) +{ + setAttributeValue(attributeLocation(name), values, columns, rows); +} + +/*! + Sets an array of vertex \a values on the attribute at \a location + in this shader program. The \a size indicates the number of + components per vertex (1, 2, 3, or 4), and the \a stride indicates + the number of bytes between vertices. A default \a stride value + of zero indicates that the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (int location, const GLfloat *values, int size, int stride) +{ + if (location != -1) { + glVertexAttribPointer(location, size, GL_FLOAT, GL_FALSE, + stride, values); + glEnableVertexAttribArray(location); + } +} + +/*! + Sets an array of 2D vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (int location, const QVector2D *values, int stride) +{ + if (location != -1) { + glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, + stride, values); + glEnableVertexAttribArray(location); + } +} + +/*! + Sets an array of 3D vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (int location, const QVector3D *values, int stride) +{ + if (location != -1) { + glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, + stride, values); + glEnableVertexAttribArray(location); + } +} + +/*! + Sets an array of 4D vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (int location, const QVector4D *values, int stride) +{ + if (location != -1) { + glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, + stride, values); + glEnableVertexAttribArray(location); + } +} + +/*! + \overload + + Sets an array of vertex \a values on the attribute called \a name + in this shader program. The \a size indicates the number of + components per vertex (1, 2, 3, or 4), and the \a stride indicates + the number of bytes between vertices. A default \a stride value + of zero indicates that the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (const char *name, const GLfloat *values, int size, int stride) +{ + setAttributeArray(attributeLocation(name), values, size, stride); +} + +/*! + \overload + + Sets an array of 2D vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (const char *name, const QVector2D *values, int stride) +{ + setAttributeArray(attributeLocation(name), values, stride); +} + +/*! + \overload + + Sets an array of 3D vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (const char *name, const QVector3D *values, int stride) +{ + setAttributeArray(attributeLocation(name), values, stride); +} + +/*! + \overload + + Sets an array of 4D vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (const char *name, const QVector4D *values, int stride) +{ + setAttributeArray(attributeLocation(name), values, stride); +} + +/*! + Disables the vertex array at \a location in this shader program + that was enabled by a previous call to setAttributeArray(). + + \sa setAttributeArray(), setAttributeValue(), setUniformValue() +*/ +void QGLShaderProgram::disableAttributeArray(int location) +{ + if (location != -1) + glDisableVertexAttribArray(location); +} + +/*! + \overload + + Disables the vertex array called \a name in this shader program + that was enabled by a previous call to setAttributeArray(). + + \sa setAttributeArray(), setAttributeValue(), setUniformValue() +*/ +void QGLShaderProgram::disableAttributeArray(const char *name) +{ + disableAttributeArray(attributeLocation(name)); +} + +/*! + Returns the location of the uniform variable \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + uniform variable for this shader program. + + \sa attributeLocation() +*/ +int QGLShaderProgram::uniformLocation(const char *name) const +{ + if (d->linked) { + return glGetUniformLocation(d->program, name); + } else { + qWarning() << "QGLShaderProgram::uniformLocation(" << name + << "): shader program is not linked"; + return -1; + } +} + +/*! + \overload + + Returns the location of the uniform variable \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + uniform variable for this shader program. + + \sa attributeLocation() +*/ +int QGLShaderProgram::uniformLocation(const QByteArray& name) const +{ + return uniformLocation(name.constData()); +} + +/*! + \overload + + Returns the location of the uniform variable \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + uniform variable for this shader program. + + \sa attributeLocation() +*/ +int QGLShaderProgram::uniformLocation(const QString& name) const +{ + return uniformLocation(name.toLatin1().constData()); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, GLfloat value) +{ + if (location != -1) + glUniform1fv(location, 1, &value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, GLfloat value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, GLint value) +{ + if (location != -1) + glUniform1i(location, value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, GLint value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + This function should be used when setting sampler values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, GLuint value) +{ + if (location != -1) + glUniform1i(location, value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. This function should be used when setting sampler values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, GLuint value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to + the 2D vector (\a x, \a y). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, GLfloat x, GLfloat y) +{ + if (location != -1) { + GLfloat values[2] = {x, y}; + glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the 2D vector (\a x, \a y). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, GLfloat x, GLfloat y) +{ + setUniformValue(uniformLocation(name), x, y); +} + +/*! + Sets the uniform variable at \a location in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue + (int location, GLfloat x, GLfloat y, GLfloat z) +{ + if (location != -1) { + GLfloat values[3] = {x, y, z}; + glUniform3fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue + (const char *name, GLfloat x, GLfloat y, GLfloat z) +{ + setUniformValue(uniformLocation(name), x, y, z); +} + +/*! + Sets the uniform variable at \a location in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue + (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + if (location != -1) { + GLfloat values[4] = {x, y, z, w}; + glUniform4fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue + (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + setUniformValue(uniformLocation(name), x, y, z, w); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QVector2D& value) +{ + if (location != -1) + glUniform2fv(location, 1, reinterpret_cast<const GLfloat *>(&value)); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QVector2D& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QVector3D& value) +{ + if (location != -1) + glUniform3fv(location, 1, reinterpret_cast<const GLfloat *>(&value)); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QVector3D& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QVector4D& value) +{ + if (location != -1) + glUniform4fv(location, 1, reinterpret_cast<const GLfloat *>(&value)); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QVector4D& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to + the red, green, blue, and alpha components of \a color. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QColor& color) +{ + if (location != -1) { + GLfloat values[4] = {color.redF(), color.greenF(), color.blueF(), color.alphaF()}; + glUniform4fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the red, green, blue, and alpha components of \a color. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QColor& color) +{ + setUniformValue(uniformLocation(name), color); +} + +/*! + Sets the uniform variable at \a location in the current context to + the x and y coordinates of \a point. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QPoint& point) +{ + if (location != -1) { + GLfloat values[4] = {point.x(), point.y()}; + glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable associated with \a name in the current + context to the x and y coordinates of \a point. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QPoint& point) +{ + setUniformValue(uniformLocation(name), point); +} + +/*! + Sets the uniform variable at \a location in the current context to + the x and y coordinates of \a point. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QPointF& point) +{ + if (location != -1) { + GLfloat values[4] = {point.x(), point.y()}; + glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable associated with \a name in the current + context to the x and y coordinates of \a point. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QPointF& point) +{ + setUniformValue(uniformLocation(name), point); +} + +/*! + Sets the uniform variable at \a location in the current context to + the width and height of the given \a size. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QSize& size) +{ + if (location != -1) { + GLfloat values[4] = {size.width(), size.width()}; + glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable associated with \a name in the current + context to the width and height of the given \a size. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QSize& size) +{ + setUniformValue(uniformLocation(name), size); +} + +/*! + Sets the uniform variable at \a location in the current context to + the width and height of the given \a size. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QSizeF& size) +{ + if (location != -1) { + GLfloat values[4] = {size.width(), size.height()}; + glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable associated with \a name in the current + context to the width and height of the given \a size. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QSizeF& size) +{ + setUniformValue(uniformLocation(name), size); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 2x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix2x2& value) +{ + if (location != -1) + glUniformMatrix2fv(location, 1, GL_FALSE, value.data()); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x2& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 2x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix2x3& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix2x3fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix2x3fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform3fv(location, 2, value.data()); + } + } +#else + if (location != -1) + glUniform3fv(location, 2, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x3& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 2x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix2x4& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix2x4fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix2x4fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform4fv(location, 2, value.data()); + } + } +#else + if (location != -1) + glUniform4fv(location, 2, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x4& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 3x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix3x2& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix3x2fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix3x2fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform2fv(location, 3, value.data()); + } + } +#else + if (location != -1) + glUniform2fv(location, 3, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x2& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 3x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix3x3& value) +{ + if (location != -1) + glUniformMatrix3fv(location, 1, GL_FALSE, value.data()); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x3& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 3x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix3x4& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix3x4fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix3x4fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform4fv(location, 3, value.data()); + } + } +#else + if (location != -1) + glUniform4fv(location, 3, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x4& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 4x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix4x2& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix4x2fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix4x2fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform2fv(location, 4, value.data()); + } + } +#else + if (location != -1) + glUniform2fv(location, 4, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x2& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 4x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix4x3& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix4x3fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix4x3fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform3fv(location, 4, value.data()); + } + } +#else + if (location != -1) + glUniform3fv(location, 4, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x3& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 4x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix4x4& value) +{ + if (location != -1) + glUniformMatrix4fv(location, 1, GL_FALSE, value.data()); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x4& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + \overload + + Sets the uniform variable at \a location in the current context + to a 4x4 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const GLfloat value[4][4]) +{ + if (location != -1) + glUniformMatrix4fv(location, 1, GL_FALSE, value[0]); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x4 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[4][4]) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to a + 3x3 transformation matrix \a value that is specified as a QTransform value. + + To set a QTransform value as a 4x4 matrix in a shader, use + \c{setUniformValue(location, QMatrix4x4(value))}. +*/ +void QGLShaderProgram::setUniformValue(int location, const QTransform& value) +{ + if (location != -1) { + GLfloat mat[3][3] = { + {value.m11(), value.m12(), value.m13()}, + {value.m21(), value.m22(), value.m23()}, + {value.m31(), value.m32(), value.m33()} + }; + glUniformMatrix3fv(location, 1, GL_FALSE, mat[0]); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to a + 3x3 transformation matrix \a value that is specified as a QTransform value. + + To set a QTransform value as a 4x4 matrix in a shader, use + \c{setUniformValue(name, QMatrix4x4(value))}. +*/ +void QGLShaderProgram::setUniformValue + (const char *name, const QTransform& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const GLint *values, int count) +{ + if (location != -1) + glUniform1iv(location, count, values); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray + (const char *name, const GLint *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count elements of \a values. This overload + should be used when setting an array of sampler values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const GLuint *values, int count) +{ + if (location != -1) + glUniform1iv(location, count, reinterpret_cast<const GLint *>(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count elements of \a values. This overload + should be used when setting an array of sampler values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray + (const char *name, const GLuint *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count elements of \a values. Each element + has \a size components. The \a size must be 1, 2, 3, or 4. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int size) +{ + if (location != -1) { + if (size == 1) + glUniform1fv(location, count, values); + else if (size == 2) + glUniform2fv(location, count, values); + else if (size == 3) + glUniform3fv(location, count, values); + else if (size == 4) + glUniform4fv(location, count, values); + else + qWarning() << "QGLShaderProgram::setUniformValue: size" << size << "not supported"; + } +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count elements of \a values. Each element + has \a size components. The \a size must be 1, 2, 3, or 4. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray + (const char *name, const GLfloat *values, int count, int size) +{ + setUniformValueArray(uniformLocation(name), values, count, size); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QVector2D *values, int count) +{ + if (location != -1) + glUniform2fv(location, count, reinterpret_cast<const GLfloat *>(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QVector2D *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QVector3D *values, int count) +{ + if (location != -1) + glUniform3fv(location, count, reinterpret_cast<const GLfloat *>(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QVector3D *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QVector4D *values, int count) +{ + if (location != -1) + glUniform4fv(location, count, reinterpret_cast<const GLfloat *>(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +// We may have to repack matrix arrays if the matrix types +// contain additional flag bits. Especially QMatrix4x4. +#define setUniformMatrixArray(func,location,values,count,type,cols,rows) \ + if (location == -1 || count <= 0) \ + return; \ + if (count == 1 || sizeof(type) == cols * rows * sizeof(GLfloat)) { \ + func(location, count, GL_FALSE, values->constData()); \ + } else { \ + QVarLengthArray<GLfloat> temp(cols * rows * count); \ + for (int index = 0; index < count; ++index) { \ + qMemCopy(temp.data() + cols * rows * index, \ + values[index].constData(), cols * rows * sizeof(GLfloat)); \ + } \ + func(location, count, GL_FALSE, temp.constData()); \ + } +#if !defined(QT_OPENGL_ES_2) +#define setUniformGenericMatrixArray(func,colfunc,location,values,count,type,cols,rows) \ + if (location == -1 || count <= 0) \ + return; \ + if (count == 1 || sizeof(type) == cols * rows * sizeof(GLfloat)) { \ + if (func) \ + func(location, count, GL_FALSE, values->constData()); \ + else \ + colfunc(location, cols * count, values->constData()); \ + } else { \ + QVarLengthArray<GLfloat> temp(cols * rows * count); \ + for (int index = 0; index < count; ++index) { \ + qMemCopy(temp.data() + cols * rows * index, \ + values[index].constData(), cols * rows * sizeof(GLfloat)); \ + } \ + if (func) \ + func(location, count, GL_FALSE, temp.constData()); \ + else \ + colfunc(location, count * cols, temp.constData()); \ + } +#else +#define setUniformGenericMatrixArray(func,colfunc,location,values,count,type,cols,rows) \ + if (location == -1 || count <= 0) \ + return; \ + if (count == 1 || sizeof(type) == cols * rows * sizeof(GLfloat)) { \ + colfunc(location, cols * count, values->constData()); \ + } else { \ + QVarLengthArray<GLfloat> temp(cols * rows * count); \ + for (int index = 0; index < count; ++index) { \ + qMemCopy(temp.data() + cols * rows * index, \ + values[index].constData(), cols * rows * sizeof(GLfloat)); \ + } \ + colfunc(location, count * cols, temp.constData()); \ + } +#endif + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x2 *values, int count) +{ + setUniformMatrixArray + (glUniformMatrix2fv, location, values, count, QMatrix2x2, 2, 2); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x2 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x3 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix2x3fv, glUniform3fv, location, values, count, + QMatrix2x3, 2, 3); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x3 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x4 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix2x4fv, glUniform4fv, location, values, count, + QMatrix2x4, 2, 4); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x4 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x2 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix3x2fv, glUniform2fv, location, values, count, + QMatrix3x2, 3, 2); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x2 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x3 *values, int count) +{ + setUniformMatrixArray + (glUniformMatrix3fv, location, values, count, QMatrix3x3, 3, 3); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x3 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x4 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix3x4fv, glUniform4fv, location, values, count, + QMatrix3x4, 3, 4); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x4 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x2 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix4x2fv, glUniform2fv, location, values, count, + QMatrix4x2, 4, 2); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x2 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x3 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix4x3fv, glUniform3fv, location, values, count, + QMatrix4x3, 4, 3); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x3 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x4 *values, int count) +{ + setUniformMatrixArray + (glUniformMatrix4fv, location, values, count, QMatrix4x4, 4, 4); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Returns true if shader programs written in the OpenGL Shading + Language (GLSL) are supported on this system; false otherwise. + + The \a context is used to resolve the GLSL extensions. + If \a context is null, then QGLContext::currentContext() is used. +*/ +bool QGLShaderProgram::hasShaderPrograms(const QGLContext *context) +{ +#if !defined(QT_OPENGL_ES_2) + if (!context) + context = QGLContext::currentContext(); + if (!context) + return false; + return qt_resolve_glsl_extensions(const_cast<QGLContext *>(context)); +#else + Q_UNUSED(context); + return true; +#endif +} + +#endif + +QT_END_NAMESPACE diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h new file mode 100644 index 0000000..b69d28e --- /dev/null +++ b/src/opengl/qglshaderprogram.h @@ -0,0 +1,297 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGLSHADERPROGRAM_H +#define QGLSHADERPROGRAM_H + +#include <QtOpenGL/qgl.h> +#include <QtGui/qvector2d.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qvector4d.h> +#include <QtGui/qmatrix4x4.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(OpenGL) + +#if !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + +class QGLShaderProgram; +class QGLShaderPrivate; + +class Q_OPENGL_EXPORT QGLShader : public QObject +{ + Q_OBJECT +public: + enum ShaderType + { + VertexShader, + FragmentShader, + PartialVertexShader, + PartialFragmentShader + }; + + explicit QGLShader(QGLShader::ShaderType type, QObject *parent = 0); + explicit QGLShader(const QString& fileName, QObject *parent = 0); + QGLShader(const QString& fileName, QGLShader::ShaderType type, QObject *parent = 0); + QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0); + QGLShader(const QString& fileName, const QGLContext *context, QObject *parent = 0); + QGLShader(const QString& fileName, QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0); + virtual ~QGLShader(); + + bool isValid() const; + + QGLShader::ShaderType shaderType() const; + + bool setSourceCode(const char *source); + bool setSourceCode(const QByteArray& source); + bool setSourceCode(const QString& source); + bool setSourceCodeFile(const QString& fileName); + + bool setBinaryCode(GLenum format, const void *binary, int length); + bool setBinaryCode(QGLShader& otherShader, GLenum format, const void *binary, int length); + + static QList<GLenum> shaderBinaryFormats(); + + QByteArray sourceCode() const; + + bool isCompiled() const; + QString log() const; + + GLuint shaderId() const; + +private: + QGLShaderPrivate *d; + + friend class QGLShaderProgram; + + Q_DISABLE_COPY(QGLShader); +}; + +class QGLShaderProgramPrivate; + +class Q_OPENGL_EXPORT QGLShaderProgram : public QObject +{ + Q_OBJECT +public: + explicit QGLShaderProgram(QObject *parent = 0); + explicit QGLShaderProgram(const QGLContext *context, QObject *parent = 0); + virtual ~QGLShaderProgram(); + + bool isValid() const; + + bool addShader(QGLShader *shader); + void removeShader(QGLShader *shader); + QList<QGLShader *> shaders() const; + + bool addShader(QGLShader::ShaderType type, const char *source); + bool addShader(QGLShader::ShaderType type, const QByteArray& source); + bool addShader(QGLShader::ShaderType type, const QString& source); + + void removeAllShaders(); + + QByteArray programBinary(int *format) const; + bool setProgramBinary(int format, const QByteArray& binary); + static QList<int> programBinaryFormats(); + + virtual bool link(); + bool isLinked() const; + QString log() const; + + bool enable(); + static void disable(); + + GLuint programId() const; + + void bindAttributeLocation(const char *name, int location); + void bindAttributeLocation(const QByteArray& name, int location); + void bindAttributeLocation(const QString& name, int location); + + int attributeLocation(const char *name) const; + int attributeLocation(const QByteArray& name) const; + int attributeLocation(const QString& name) const; + + void setAttributeValue(int location, GLfloat value); + void setAttributeValue(int location, GLfloat x, GLfloat y); + void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z); + void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setAttributeValue(int location, const QVector2D& value); + void setAttributeValue(int location, const QVector3D& value); + void setAttributeValue(int location, const QVector4D& value); + void setAttributeValue(int location, const QColor& value); + void setAttributeValue(int location, const GLfloat *values, int columns, int rows); + + void setAttributeValue(const char *name, GLfloat value); + void setAttributeValue(const char *name, GLfloat x, GLfloat y); + void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z); + void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setAttributeValue(const char *name, const QVector2D& value); + void setAttributeValue(const char *name, const QVector3D& value); + void setAttributeValue(const char *name, const QVector4D& value); + void setAttributeValue(const char *name, const QColor& value); + void setAttributeValue(const char *name, const GLfloat *values, int columns, int rows); + + void setAttributeArray + (int location, const GLfloat *values, int size, int stride = 0); + void setAttributeArray + (int location, const QVector2D *values, int stride = 0); + void setAttributeArray + (int location, const QVector3D *values, int stride = 0); + void setAttributeArray + (int location, const QVector4D *values, int stride = 0); + void setAttributeArray + (const char *name, const GLfloat *values, int size, int stride = 0); + void setAttributeArray + (const char *name, const QVector2D *values, int stride = 0); + void setAttributeArray + (const char *name, const QVector3D *values, int stride = 0); + void setAttributeArray + (const char *name, const QVector4D *values, int stride = 0); + void disableAttributeArray(int location); + void disableAttributeArray(const char *name); + + int uniformLocation(const char *name) const; + int uniformLocation(const QByteArray& name) const; + int uniformLocation(const QString& name) const; + + void setUniformValue(int location, GLfloat value); + void setUniformValue(int location, GLint value); + void setUniformValue(int location, GLuint value); + void setUniformValue(int location, GLfloat x, GLfloat y); + void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z); + void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setUniformValue(int location, const QVector2D& value); + void setUniformValue(int location, const QVector3D& value); + void setUniformValue(int location, const QVector4D& value); + void setUniformValue(int location, const QColor& color); + void setUniformValue(int location, const QPoint& point); + void setUniformValue(int location, const QPointF& point); + void setUniformValue(int location, const QSize& size); + void setUniformValue(int location, const QSizeF& size); + void setUniformValue(int location, const QMatrix2x2& value); + void setUniformValue(int location, const QMatrix2x3& value); + void setUniformValue(int location, const QMatrix2x4& value); + void setUniformValue(int location, const QMatrix3x2& value); + void setUniformValue(int location, const QMatrix3x3& value); + void setUniformValue(int location, const QMatrix3x4& value); + void setUniformValue(int location, const QMatrix4x2& value); + void setUniformValue(int location, const QMatrix4x3& value); + void setUniformValue(int location, const QMatrix4x4& value); + void setUniformValue(int location, const GLfloat value[4][4]); + void setUniformValue(int location, const QTransform& value); + + void setUniformValue(const char *name, GLfloat value); + void setUniformValue(const char *name, GLint value); + void setUniformValue(const char *name, GLuint value); + void setUniformValue(const char *name, GLfloat x, GLfloat y); + void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z); + void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setUniformValue(const char *name, const QVector2D& value); + void setUniformValue(const char *name, const QVector3D& value); + void setUniformValue(const char *name, const QVector4D& value); + void setUniformValue(const char *name, const QColor& color); + void setUniformValue(const char *name, const QPoint& point); + void setUniformValue(const char *name, const QPointF& point); + void setUniformValue(const char *name, const QSize& size); + void setUniformValue(const char *name, const QSizeF& size); + void setUniformValue(const char *name, const QMatrix2x2& value); + void setUniformValue(const char *name, const QMatrix2x3& value); + void setUniformValue(const char *name, const QMatrix2x4& value); + void setUniformValue(const char *name, const QMatrix3x2& value); + void setUniformValue(const char *name, const QMatrix3x3& value); + void setUniformValue(const char *name, const QMatrix3x4& value); + void setUniformValue(const char *name, const QMatrix4x2& value); + void setUniformValue(const char *name, const QMatrix4x3& value); + void setUniformValue(const char *name, const QMatrix4x4& value); + void setUniformValue(const char *name, const GLfloat value[4][4]); + void setUniformValue(const char *name, const QTransform& value); + + void setUniformValueArray(int location, const GLfloat *values, int count, int size); + void setUniformValueArray(int location, const GLint *values, int count); + void setUniformValueArray(int location, const GLuint *values, int count); + void setUniformValueArray(int location, const QVector2D *values, int count); + void setUniformValueArray(int location, const QVector3D *values, int count); + void setUniformValueArray(int location, const QVector4D *values, int count); + void setUniformValueArray(int location, const QMatrix2x2 *values, int count); + void setUniformValueArray(int location, const QMatrix2x3 *values, int count); + void setUniformValueArray(int location, const QMatrix2x4 *values, int count); + void setUniformValueArray(int location, const QMatrix3x2 *values, int count); + void setUniformValueArray(int location, const QMatrix3x3 *values, int count); + void setUniformValueArray(int location, const QMatrix3x4 *values, int count); + void setUniformValueArray(int location, const QMatrix4x2 *values, int count); + void setUniformValueArray(int location, const QMatrix4x3 *values, int count); + void setUniformValueArray(int location, const QMatrix4x4 *values, int count); + + void setUniformValueArray(const char *name, const GLfloat *values, int count, int size); + void setUniformValueArray(const char *name, const GLint *values, int count); + void setUniformValueArray(const char *name, const GLuint *values, int count); + void setUniformValueArray(const char *name, const QVector2D *values, int count); + void setUniformValueArray(const char *name, const QVector3D *values, int count); + void setUniformValueArray(const char *name, const QVector4D *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x4 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x4 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x4 *values, int count); + + static bool hasShaderPrograms(const QGLContext *context = 0); + +private: + QGLShaderProgramPrivate *d; + + Q_DISABLE_COPY(QGLShaderProgram); + + bool init(); +}; + +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index 77ff9fb..e3d8a1d 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -39,7 +39,6 @@ ** ****************************************************************************/ -#include <private/qtextengine_p.h> #include <qdebug.h> #include <private/qfontengine_p.h> #include <qmath.h> @@ -57,13 +56,11 @@ #include "qpen.h" #include "qvarlengtharray.h" #include <private/qpainter_p.h> -#include <qglpixelbuffer.h> #include <private/qglpixelbuffer_p.h> #include <private/qbezier_p.h> #include <qglframebufferobject.h> #include "private/qtessellator_p.h" -#include "private/qwindowsurface_gl_p.h" #include "util/fragmentprograms_p.h" @@ -125,35 +122,6 @@ struct QT_PointF { qreal y; }; -void qt_add_rect_to_array(const QRectF &r, q_vertexType *array) -{ - qreal left = r.left(); - qreal right = r.right(); - qreal top = r.top(); - qreal bottom = r.bottom(); - - array[0] = f2vt(left); - array[1] = f2vt(top); - array[2] = f2vt(right); - array[3] = f2vt(top); - array[4] = f2vt(right); - array[5] = f2vt(bottom); - array[6] = f2vt(left); - array[7] = f2vt(bottom); -} - -void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array) -{ - array[0] = f2vt(x1); - array[1] = f2vt(y1); - array[2] = f2vt(x2); - array[3] = f2vt(y1); - array[4] = f2vt(x2); - array[5] = f2vt(y2); - array[6] = f2vt(x1); - array[7] = f2vt(y2); -} - struct QGLTrapezoid { QGLTrapezoid() @@ -190,180 +158,6 @@ const QGLTrapezoid QGLTrapezoid::translated(const QPointF &delta) const return trap; } -class QGLDrawable { -public: - QGLDrawable() : widget(0), buffer(0), fbo(0) - , wsurf(0) - {} - inline void setDevice(QPaintDevice *pdev); - inline void swapBuffers(); - inline void makeCurrent(); - inline void doneCurrent(); - inline QSize size() const; - inline QGLFormat format() const; - inline GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA); - inline GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA); - inline QColor backgroundColor() const; - inline QGLContext *context() const; - inline bool autoFillBackground() const; - -private: - bool wasBound; - QGLWidget *widget; - QGLPixelBuffer *buffer; - QGLFramebufferObject *fbo; -#ifdef Q_WS_QWS - QWSGLWindowSurface *wsurf; -#else - QGLWindowSurface *wsurf; -#endif -}; - -void QGLDrawable::setDevice(QPaintDevice *pdev) -{ - wasBound = false; - widget = 0; - buffer = 0; - fbo = 0; -#ifdef Q_WS_QWS - wsurf = 0; -#endif - if (pdev->devType() == QInternal::Widget) - widget = static_cast<QGLWidget *>(pdev); - else if (pdev->devType() == QInternal::Pbuffer) - buffer = static_cast<QGLPixelBuffer *>(pdev); - else if (pdev->devType() == QInternal::FramebufferObject) - fbo = static_cast<QGLFramebufferObject *>(pdev); - else if (pdev->devType() == QInternal::UnknownDevice) -#ifdef Q_WS_QWS - wsurf = static_cast<QWSGLPaintDevice*>(pdev)->windowSurface(); -#else - wsurf = static_cast<QGLWindowSurface *>(pdev); -#endif -} - -inline void QGLDrawable::swapBuffers() -{ - if (widget) { - if (widget->autoBufferSwap()) - widget->swapBuffers(); - } else { - glFlush(); - } -} - -inline void QGLDrawable::makeCurrent() -{ - if (widget) - widget->makeCurrent(); - else if (buffer) - buffer->makeCurrent(); - else if (wsurf) - wsurf->context()->makeCurrent(); - else if (fbo) { - wasBound = fbo->isBound(); - if (!wasBound) - fbo->bind(); - } -} - -inline void QGLDrawable::doneCurrent() -{ - if (fbo && !wasBound) - fbo->release(); -} - -inline QSize QGLDrawable::size() const -{ - if (widget) { - return QSize(widget->d_func()->glcx->device()->width(), - widget->d_func()->glcx->device()->height()); - } else if (buffer) { - return buffer->size(); - } else if (fbo) { - return fbo->size(); - } else if (wsurf) { -#ifdef Q_WS_QWS - return wsurf->window()->frameSize(); -#else - return QSize(wsurf->width(), wsurf->height()); -#endif - } - return QSize(); -} - -inline QGLFormat QGLDrawable::format() const -{ - if (widget) - return widget->format(); - else if (buffer) - return buffer->format(); - else if (wsurf) - return wsurf->context()->format(); - else if (fbo && QGLContext::currentContext()) { - QGLFormat fmt = QGLContext::currentContext()->format(); - fmt.setStencil(fbo->attachment() == QGLFramebufferObject::CombinedDepthStencil); - fmt.setDepth(fbo->attachment() != QGLFramebufferObject::NoAttachment); - return fmt; - } - - return QGLFormat(); -} - -inline GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format) -{ - if (widget) - return widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true); - else if (buffer) - return buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true); - else if (fbo && QGLContext::currentContext()) - return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true); - else if (wsurf) - return wsurf->context()->d_func()->bindTexture(image, target, format, true); - return 0; -} - -inline GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) -{ - if (widget) - return widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true); - else if (buffer) - return buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true); - else if (fbo && QGLContext::currentContext()) - return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true); - else if (wsurf) - return wsurf->context()->d_func()->bindTexture(pixmap, target, format, true); - return 0; -} - -inline QColor QGLDrawable::backgroundColor() const -{ - if (widget) - return widget->palette().brush(widget->backgroundRole()).color(); - return QApplication::palette().brush(QPalette::Background).color(); -} - -inline QGLContext *QGLDrawable::context() const -{ - if (widget) - return widget->d_func()->glcx; - else if (buffer) - return buffer->d_func()->qctx; - else if (fbo) - return const_cast<QGLContext *>(QGLContext::currentContext()); - else if (wsurf) - return wsurf->context(); - return 0; -} - -inline bool QGLDrawable::autoFillBackground() const -{ - if (widget) - return widget->autoFillBackground(); - else - return false; -} - class QOpenGLImmediateModeTessellator; class QGLMaskGenerator; @@ -1536,9 +1330,15 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev) d->offscreen.begin(); - const QColor &c = d->drawable.backgroundColor(); - glClearColor(c.redF(), c.greenF(), c.blueF(), 1.0); if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) { + + if (d->drawable.hasTransparentBackground()) + glClearColor(0.0, 0.0, 0.0, 0.0); + else { + const QColor &c = d->drawable.backgroundColor(); + glClearColor(c.redF(), c.greenF(), c.blueF(), 1.0); + } + GLbitfield clearBits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; #ifndef QT_OPENGL_ES clearBits |= GL_ACCUM_BUFFER_BIT; @@ -2233,7 +2033,7 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule) // Enable color writes. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilMask(0); + glStencilMask(stencilMask); setGradientOps(cbrush, QRectF(QPointF(min_x, min_y), QSizeF(max_x - min_x, max_y - min_y))); @@ -2245,12 +2045,14 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule) // Enable stencil func. glStencilFunc(GL_NOTEQUAL, 0, stencilMask); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); composite(rect); } else { DEBUG_ONCE qDebug() << "QOpenGLPaintEnginePrivate: Drawing polygon using stencil method (no fragment programs)"; // Enable stencil func. glStencilFunc(GL_NOTEQUAL, 0, stencilMask); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); #ifndef QT_OPENGL_ES glBegin(GL_QUADS); glVertex2f(min_x, min_y); @@ -2261,24 +2063,6 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule) #endif } - glStencilMask(~0); - glStencilFunc(GL_ALWAYS, 0, 0); - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); - - // clear all stencil values to 0 - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - -#ifndef QT_OPENGL_ES - glBegin(GL_QUADS); - glVertex2f(min_x, min_y); - glVertex2f(max_x, min_y); - glVertex2f(max_x, max_y); - glVertex2f(min_x, max_y); - glEnd(); -#endif - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - // Disable stencil writes. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilMask(0); @@ -2460,11 +2244,12 @@ void QOpenGLPaintEnginePrivate::updateDepthClip() return; } -#ifndef QT_OPENGL_ES - glClearDepth(0.0f); -#else +#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_ES_1_CL) glClearDepthf(0.0f); +#else + glClearDepth(0.0f); #endif + glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glClear(GL_DEPTH_BUFFER_BIT); @@ -3300,6 +3085,9 @@ QGLTrapezoidMaskGenerator::QGLTrapezoidMaskGenerator(const QPainterPath &path, c { } +extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array); +extern void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array); + void QGLTrapezoidMaskGenerator::drawMask(const QRect &rect) { #ifdef QT_OPENGL_ES @@ -5067,9 +4855,8 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte // fall back to drawing a polygon if the scale factor is large, or // we use a gradient pen - if (ti.fontEngine->fontDef.pixelSize >= 64 - || (d->matrix.det() > 1) || (d->pen_brush_style >= Qt::LinearGradientPattern - && d->pen_brush_style <= Qt::ConicalGradientPattern)) { + if ((d->matrix.det() > 1) || (d->pen_brush_style >= Qt::LinearGradientPattern + && d->pen_brush_style <= Qt::ConicalGradientPattern)) { QPaintEngine::drawTextItem(p, textItem); return; } @@ -5783,9 +5570,11 @@ void QOpenGLPaintEnginePrivate::ensureDrawableTexture() QPixmapFilter *QOpenGLPaintEngine::createPixmapFilter(int type) const { +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) if (QGLContext::currentContext()) return QGLContext::currentContext()->d_func()->createPixmapFilter(type); else +#endif return 0; } diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index b079557..85bcda5 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qpixmap.h" +#include "qglframebufferobject.h" #include <private/qpaintengine_raster_p.h> @@ -48,6 +49,8 @@ #include <private/qgl_p.h> #include <private/qdrawhelper_p.h> +#include <private/qpaintengineex_opengl2_p.h> + QT_BEGIN_NAMESPACE extern QGLWidget* qt_gl_share_widget(); @@ -57,12 +60,14 @@ class QGLShareContextScope public: QGLShareContextScope(const QGLContext *ctx) : m_oldContext(0) - , m_ctx(const_cast<QGLContext *>(ctx)) { - const QGLContext *currentContext = QGLContext::currentContext(); + QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext()); if (currentContext != ctx && !qgl_share_reg()->checkSharing(ctx, currentContext)) { - m_oldContext = const_cast<QGLContext *>(currentContext); + m_oldContext = currentContext; + m_ctx = const_cast<QGLContext *>(ctx); m_ctx->makeCurrent(); + } else { + m_ctx = currentContext; } } @@ -87,58 +92,29 @@ private: QGLContext *m_ctx; }; -void qt_gl_convertFromGLImage(QImage *img) -{ - const int w = img->width(); - const int h = img->height(); - - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - uint *p = (uint*)img->bits(); - uint *end = p + w*h; - - while (p < end) { - uint a = *p << 24; - *p = (*p >> 8) | a; - p++; - } - - *img = img->mirrored(); - } else { - // mirror image - uint *data = (uint *)img->bits(); - - const int mid = h/2; - - for (int y = 0; y < mid; ++y) { - uint *p = data + y * w; - uint *end = p + w; - uint *q = data + (h - y - 1) * w; - - while (p < end) - qSwap(*p++, *q++); - } - } -} - - static int qt_gl_pixmap_serial = 0; QGLPixmapData::QGLPixmapData(PixelType type) : QPixmapData(type, OpenGLClass) , m_width(0) , m_height(0) - , m_texture(0) + , m_renderFbo(0) + , m_textureId(0) + , m_engine(0) + , m_ctx(0) , m_dirty(false) + , m_hasFillColor(false) { setSerialNumber(++qt_gl_pixmap_serial); } QGLPixmapData::~QGLPixmapData() { - if (m_texture && qt_gl_share_widget()) { - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - glDeleteTextures(1, &m_texture); - } + QGLWidget *shareWidget = qt_gl_share_widget(); + if (!shareWidget) + return; + QGLShareContextScope ctx(shareWidget->context()); + glDeleteTextures(1, &m_textureId); } bool QGLPixmapData::isValid() const @@ -148,6 +124,9 @@ bool QGLPixmapData::isValid() const 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 || qgl_share_reg()->checkSharing(ctx, share_ctx); } @@ -160,6 +139,12 @@ void QGLPixmapData::resize(int width, int height) m_width = width; m_height = height; + if (m_textureId) { + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + glDeleteTextures(1, &m_textureId); + m_textureId = 0; + } + m_source = QImage(); m_dirty = isValid(); setSerialNumber(++qt_gl_pixmap_serial); @@ -173,28 +158,37 @@ void QGLPixmapData::ensureCreated() const m_dirty = false; QGLShareContextScope ctx(qt_gl_share_widget()->context()); + m_ctx = ctx; const GLenum format = qt_gl_preferredTextureFormat(); - const GLenum target = qt_gl_preferredTextureTarget(); - - if (!m_texture) - glGenTextures(1, &m_texture); - - glBindTexture(target, m_texture); + const GLenum target = GL_TEXTURE_2D; + + if (!m_textureId) { + glGenTextures(1, &m_textureId); + glBindTexture(target, m_textureId); + glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } - if (m_source.isNull()) { - glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format, GL_UNSIGNED_BYTE, 0); - } else { + if (!m_source.isNull()) { const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, format); - glBindTexture(target, m_texture); - glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format, - GL_UNSIGNED_BYTE, tx.bits()); + glBindTexture(target, m_textureId); + glTexSubImage2D(target, 0, 0, 0, m_width, m_height, format, + GL_UNSIGNED_BYTE, tx.bits()); - m_source = QImage(); + if (useFramebufferObjects()) + m_source = QImage(); } } +QGLFramebufferObject *QGLPixmapData::fbo() const +{ + return m_renderFbo; +} + void QGLPixmapData::fromImage(const QImage &image, Qt::ImageConversionFlags) { @@ -203,6 +197,13 @@ void QGLPixmapData::fromImage(const QImage &image, resize(image.width(), image.height()); m_source = image; m_dirty = true; + m_hasFillColor = false; + + if (m_textureId) { + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + glDeleteTextures(1, &m_textureId); + m_textureId = 0; + } } bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect) @@ -213,12 +214,27 @@ bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect) return false; } +void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect) +{ + if (data->classId() != QPixmapData::OpenGLClass) { + QPixmapData::copy(data, rect); + return; + } + + // can be optimized to do a framebuffer blit or similar ... + QPixmapData::copy(data, rect); +} + void QGLPixmapData::fill(const QColor &color) { if (!isValid()) return; - if (!m_source.isNull()) { + if (useFramebufferObjects()) { + m_source = QImage(); + m_hasFillColor = true; + m_fillColor = color; + } else if (!m_source.isNull()) { m_source.fill(PREMUL(color.rgba())); } else { // ## TODO: improve performance here @@ -239,29 +255,114 @@ QImage QGLPixmapData::toImage() const if (!isValid()) return QImage(); - if (!m_source.isNull()) + if (m_renderFbo) { + copyBackFromRenderFbo(true); + } else if (!m_source.isNull()) { return m_source; - else if (m_dirty) - return QImage(m_width, m_height, QImage::Format_ARGB32_Premultiplied); + } else if (m_dirty || m_hasFillColor) { + QImage img(m_width, m_height, QImage::Format_ARGB32_Premultiplied); + if (m_hasFillColor) + img.fill(PREMUL(m_fillColor.rgba())); + return img; + } else { + ensureCreated(); + } + + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha); + glBindTexture(GL_TEXTURE_2D, m_textureId); + return qt_gl_read_texture(QSize(m_width, m_height), true, true); +} + +struct TextureBuffer +{ + QGLFramebufferObject *fbo; + QGL2PaintEngineEx *engine; +}; + +static QVector<TextureBuffer> textureBufferStack; +static int currentTextureBuffer = 0; + +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(); - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - QImage img(m_width, m_height, QImage::Format_ARGB32_Premultiplied); + if (!ctx->d_ptr->fbo) + glGenFramebuffers(1, &ctx->d_ptr->fbo); + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, m_textureId, 0); + + const int x0 = 0; + const int x1 = m_width; + const int y0 = 0; + const int y1 = m_height; + + 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); +} + +void QGLPixmapData::swapBuffers() +{ + if (!isValid()) + return; + + copyBackFromRenderFbo(false); + m_renderFbo->release(); + + --currentTextureBuffer; + + m_renderFbo = 0; + m_engine = 0; +} + +void QGLPixmapData::makeCurrent() +{ + if (isValid() && m_renderFbo) + m_renderFbo->bind(); +} - GLenum format = qt_gl_preferredTextureFormat(); - GLenum target = qt_gl_preferredTextureTarget(); +void QGLPixmapData::doneCurrent() +{ + if (isValid() && m_renderFbo) + m_renderFbo->release(); +} - glBindTexture(target, m_texture); -#ifndef QT_OPENGL_ES - glGetTexImage(target, 0, format, GL_UNSIGNED_BYTE, img.bits()); -#else - // XXX - cannot download textures this way on OpenGL/ES. -#endif +static TextureBuffer createTextureBuffer(const QSize &size, QGL2PaintEngineEx *engine = 0) +{ + TextureBuffer buffer; + QGLFramebufferObjectFormat fmt; + fmt.setAttachment(QGLFramebufferObject::CombinedDepthStencil); + fmt.setSamples(4); - qt_gl_convertFromGLImage(&img); + buffer.fbo = new QGLFramebufferObject(size, fmt); + buffer.engine = engine ? engine : new QGL2PaintEngineEx; - return img; + return buffer; +} + +bool QGLPixmapData::useFramebufferObjects() +{ + return QGLFramebufferObject::hasOpenGLFramebufferObjects() + && QGLFramebufferObject::hasOpenGLFramebufferBlit(); } QPaintEngine* QGLPixmapData::paintEngine() const @@ -269,23 +370,72 @@ QPaintEngine* QGLPixmapData::paintEngine() const if (!isValid()) return 0; - m_source = toImage(); - m_dirty = true; + if (m_engine) + return m_engine; + else if (!useFramebufferObjects()) { + m_dirty = true; + if (m_source.size() != size()) + m_source = QImage(size(), QImage::Format_ARGB32_Premultiplied); + if (m_hasFillColor) { + m_source.fill(PREMUL(m_fillColor.rgba())); + m_hasFillColor = false; + } + return m_source.paintEngine(); + } + + extern QGLWidget* qt_gl_share_widget(); - return m_source.paintEngine(); + if (!QGLContext::currentContext()) + qt_gl_share_widget()->makeCurrent(); + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + + if (textureBufferStack.size() <= currentTextureBuffer) { + textureBufferStack << createTextureBuffer(size()); + } else { + QSize sz = textureBufferStack.at(currentTextureBuffer).fbo->size(); + if (sz.width() < m_width || sz.height() < m_height) { + if (sz.width() < m_width) + sz.setWidth(qMax(m_width, qRound(sz.width() * 1.5))); + if (sz.height() < m_height) + sz.setHeight(qMax(m_height, qRound(sz.height() * 1.5))); + delete textureBufferStack.at(currentTextureBuffer).fbo; + textureBufferStack[currentTextureBuffer] = + createTextureBuffer(sz, textureBufferStack.at(currentTextureBuffer).engine); + qDebug() << "Creating new pixmap texture buffer:" << sz; + } + } + + m_renderFbo = textureBufferStack.at(currentTextureBuffer).fbo; + m_engine = textureBufferStack.at(currentTextureBuffer).engine; + + ++currentTextureBuffer; + + return m_engine; } -GLuint QGLPixmapData::bind() const +GLuint QGLPixmapData::bind(bool copyBack) const { - ensureCreated(); - glBindTexture(qt_gl_preferredTextureTarget(), m_texture); - return m_texture; + if (m_renderFbo && copyBack) { + copyBackFromRenderFbo(true); + } else { + if (m_hasFillColor) { + m_dirty = true; + m_source = QImage(m_width, m_height, QImage::Format_ARGB32_Premultiplied); + m_source.fill(PREMUL(m_fillColor.rgba())); + m_hasFillColor = false; + } + ensureCreated(); + } + + GLuint id = m_textureId; + glBindTexture(GL_TEXTURE_2D, id); + return id; } GLuint QGLPixmapData::textureId() const { ensureCreated(); - return m_texture; + return m_textureId; } extern int qt_defaultDpiX(); diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h index e450f01..1b6b7ae 100644 --- a/src/opengl/qpixmapdata_gl_p.h +++ b/src/opengl/qpixmapdata_gl_p.h @@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE class QPaintEngine; +class QGLFramebufferObject; class QGLPixmapData : public QPixmapData { @@ -72,6 +73,7 @@ public: void resize(int width, int height); void fromImage(const QImage &image, Qt::ImageConversionFlags flags); + void copy(const QPixmapData *data, const QRect &rect); bool scroll(int dx, int dy, const QRect &rect); @@ -80,13 +82,28 @@ public: QImage toImage() const; QPaintEngine* paintEngine() const; - GLuint bind() const; + GLuint bind(bool copyBack = true) const; GLuint textureId() const; bool isValidContext(const QGLContext *ctx) const; void ensureCreated() const; + bool isUninitialized() const { return m_dirty && m_source.isNull(); } + + bool needsFill() const { return m_hasFillColor; } + QColor fillColor() const { return m_fillColor; } + + QSize size() const { return QSize(m_width, m_height); } + int width() const { return m_width; } + int height() const { return m_height; } + + QGLFramebufferObject *fbo() const; + + void makeCurrent(); + void doneCurrent(); + void swapBuffers(); + protected: int metric(QPaintDevice::PaintDeviceMetric metric) const; @@ -94,12 +111,26 @@ private: QGLPixmapData(const QGLPixmapData &other); QGLPixmapData &operator=(const QGLPixmapData &other); + void copyBackFromRenderFbo(bool keepCurrentFboBound) const; + + static bool useFramebufferObjects(); + int m_width; int m_height; - mutable GLuint m_texture; - mutable bool m_dirty; + mutable QGLFramebufferObject *m_renderFbo; + mutable GLuint m_textureId; + mutable QPaintEngine *m_engine; + mutable QGLContext *m_ctx; mutable QImage m_source; + + // the texture is not in sync with the source image + mutable bool m_dirty; + + // fill has been called and no painting has been done, so the pixmap is + // represented by a single fill color + mutable QColor m_fillColor; + mutable bool m_hasFillColor; }; QT_END_NAMESPACE diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index b41adf9..965c7a5 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -69,7 +69,8 @@ #include <private/qglpixelbuffer_p.h> #include <private/qgraphicssystem_gl_p.h> -#include <private/qpaintengine_opengl_p.h> + +#include <private/qpaintengineex_opengl2_p.h> #ifndef GLX_ARB_multisample #define GLX_SAMPLE_BUFFERS_ARB 100000 @@ -100,17 +101,19 @@ QGLGraphicsSystem::QGLGraphicsSystem() int i = 0; int spec[16]; spec[i++] = GLX_RGBA; -#if 0 spec[i++] = GLX_DOUBLEBUFFER; - spec[i++] = GLX_DEPTH_SIZE; - spec[i++] = 8; - spec[i++] = GLX_STENCIL_SIZE; - spec[i++] = 8; - spec[i++] = GLX_SAMPLE_BUFFERS_ARB; - spec[i++] = 1; - spec[i++] = GLX_SAMPLES_ARB; - spec[i++] = 4; -#endif + + if (!qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull()) { + spec[i++] = GLX_DEPTH_SIZE; + spec[i++] = 8; + spec[i++] = GLX_STENCIL_SIZE; + spec[i++] = 8; + spec[i++] = GLX_SAMPLE_BUFFERS_ARB; + spec[i++] = 1; + spec[i++] = GLX_SAMPLES_ARB; + spec[i++] = 4; + } + spec[i++] = XNone; XVisualInfo *vi = glXChooseVisual(X11->display, X11->defaultScreen, spec); @@ -187,9 +190,10 @@ public: } void cleanup() { - delete widget; - widget = 0; + QGLWidget *w = widget; cleanedUp = true; + widget = 0; + delete w; } static bool cleanedUp; @@ -227,6 +231,7 @@ struct QGLWindowSurfacePrivate int tried_fbo : 1; int tried_pb : 1; + int destructive_swap_buffers : 1; QGLContext *ctx; @@ -250,6 +255,7 @@ QGLWindowSurface::QGLWindowSurface(QWidget *window) d_ptr->ctx = 0; d_ptr->tried_fbo = false; d_ptr->tried_pb = false; + d_ptr->destructive_swap_buffers = qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull(); } QGLWindowSurface::~QGLWindowSurface() @@ -287,18 +293,12 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size(); } -#if !defined(QT_OPENGL_ES_2) -Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_window_surface_paintengine) -#endif +Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_window_surface_2_engine) /*! \reimp */ QPaintEngine *QGLWindowSurface::paintEngine() const { -#if !defined(QT_OPENGL_ES_2) - return qt_gl_window_surface_paintengine(); -#else - return 0; -#endif + return qt_gl_window_surface_2_engine(); } int QGLWindowSurface::metric(PaintDeviceMetric m) const @@ -313,6 +313,8 @@ QGLContext *QGLWindowSurface::context() const QPaintDevice *QGLWindowSurface::paintDevice() { + updateGeometry(); + if (d_ptr->pb) return d_ptr->pb; @@ -328,6 +330,7 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, void QGLWindowSurface::beginPaint(const QRegion &) { + updateGeometry(); } void QGLWindowSurface::endPaint(const QRegion &rgn) @@ -343,6 +346,9 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint & QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget(); Q_ASSERT(parent); + if (!geometry().isValid()) + return; + hijackWindow(parent); QRect br = rgn.boundingRect().translated(offset); @@ -350,53 +356,57 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint & QPoint wOffset = qt_qwidget_data(parent)->wrect.topLeft(); QRect rect = br.translated(-offset - wOffset); - const GLenum target = qt_gl_preferredTextureTarget(); + const GLenum target = GL_TEXTURE_2D; if (context()) { context()->makeCurrent(); if (context()->format().doubleBuffer()) { - glBindTexture(target, d_ptr->tex_id); +#if !defined(QT_OPENGL_ES_2) + if (d_ptr->destructive_swap_buffers) { + glBindTexture(target, d_ptr->tex_id); - QVector<QRect> rects = d_ptr->paintedRegion.rects(); - for (int i = 0; i < rects.size(); ++i) { - QRect br = rects.at(i); - if (br.isEmpty()) - continue; + QVector<QRect> rects = d_ptr->paintedRegion.rects(); + for (int i = 0; i < rects.size(); ++i) { + QRect br = rects.at(i); + if (br.isEmpty()) + continue; - const uint bottom = window()->height() - (br.y() + br.height()); - glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height()); - } + const uint bottom = window()->height() - (br.y() + br.height()); + glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height()); + } - glBindTexture(target, 0); + glBindTexture(target, 0); - QRegion dirtyRegion = QRegion(window()->rect()) - d_ptr->paintedRegion; + QRegion dirtyRegion = QRegion(window()->rect()) - d_ptr->paintedRegion; - if (!dirtyRegion.isEmpty()) { - context()->makeCurrent(); + if (!dirtyRegion.isEmpty()) { + context()->makeCurrent(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); #ifndef QT_OPENGL_ES - glOrtho(0, window()->width(), window()->height(), 0, -999999, 999999); + glOrtho(0, window()->width(), window()->height(), 0, -999999, 999999); #else - glOrthof(0, window()->width(), window()->height(), 0, -999999, 999999); + glOrthof(0, window()->width(), window()->height(), 0, -999999, 999999); #endif - glViewport(0, 0, window()->width(), window()->height()); + glViewport(0, 0, window()->width(), window()->height()); - QVector<QRect> rects = dirtyRegion.rects(); - glColor4f(1, 1, 1, 1); - for (int i = 0; i < rects.size(); ++i) { - QRect rect = rects.at(i); - if (rect.isEmpty()) - continue; + QVector<QRect> rects = dirtyRegion.rects(); + glColor4f(1, 1, 1, 1); + for (int i = 0; i < rects.size(); ++i) { + QRect rect = rects.at(i); + if (rect.isEmpty()) + continue; - drawTexture(rect, d_ptr->tex_id, window()->size(), rect); + drawTexture(rect, d_ptr->tex_id, window()->size(), rect); + } } } +#endif d_ptr->paintedRegion = QRegion(); context()->swapBuffers(); @@ -421,48 +431,75 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint & } QSize size = widget->rect().size(); - if (ctx->format().doubleBuffer()) { + if (d_ptr->destructive_swap_buffers && ctx->format().doubleBuffer()) { rect = parent->rect(); br = rect.translated(wOffset); size = parent->size(); } - ctx->makeCurrent(); + glDisable(GL_SCISSOR_TEST); + + if (d_ptr->fbo && QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit) { + const int h = d_ptr->fbo->height(); + + const int x0 = rect.left(); + const int x1 = rect.left() + rect.width(); + const int y0 = h - (rect.top() + rect.height()); + const int y1 = h - rect.top(); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0); + + glBlitFramebufferEXT(x0, y0, x1, y1, + x0, y0, x1, y1, + GL_COLOR_BUFFER_BIT, + GL_NEAREST); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, d_ptr->fbo->handle()); + } +#if !defined(QT_OPENGL_ES_2) + else { + glDisable(GL_DEPTH_TEST); + + if (d_ptr->fbo) { + d_ptr->fbo->release(); + } else { + ctx->makeCurrent(); #ifdef Q_WS_MAC - ctx->updatePaintDevice(); + ctx->updatePaintDevice(); #endif - if (d_ptr->fbo) - d_ptr->fbo->release(); + } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); #ifndef QT_OPENGL_ES - glOrtho(0, size.width(), size.height(), 0, -999999, 999999); + glOrtho(0, size.width(), size.height(), 0, -999999, 999999); #else - glOrthof(0, size.width(), size.height(), 0, -999999, 999999); + glOrthof(0, size.width(), size.height(), 0, -999999, 999999); #endif - glViewport(0, 0, size.width(), size.height()); + glViewport(0, 0, size.width(), size.height()); - glColor4f(1, 1, 1, 1); - drawTexture(rect, texture, window()->size(), br); + glColor4f(1, 1, 1, 1); + drawTexture(rect, texture, window()->size(), br); + + if (d_ptr->fbo) + d_ptr->fbo->bind(); + } +#endif if (ctx->format().doubleBuffer()) ctx->swapBuffers(); else glFlush(); - - if (d_ptr->fbo) - d_ptr->fbo->bind(); } -void QGLWindowSurface::setGeometry(const QRect &rect) +void QGLWindowSurface::updateGeometry() { - QWindowSurface::setGeometry(rect); + QRect rect = QWindowSurface::geometry(); - const GLenum target = qt_gl_preferredTextureTarget(); + const GLenum target = GL_TEXTURE_2D; if (rect.width() <= 0 || rect.height() <= 0) return; @@ -473,13 +510,51 @@ void QGLWindowSurface::setGeometry(const QRect &rect) d_ptr->size = rect.size(); if (d_ptr->ctx) { - glBindTexture(target, d_ptr->tex_id); - glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glBindTexture(target, 0); + if (d_ptr->destructive_swap_buffers) { + glBindTexture(target, d_ptr->tex_id); + glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glBindTexture(target, 0); + } return; } - if (d_ptr->pb || !d_ptr->tried_pb) { + if (d_ptr->destructive_swap_buffers + && (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject) +#ifdef QT_OPENGL_ES_2 + && (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit) +#endif + && (d_ptr->fbo || !d_ptr->tried_fbo)) + { + d_ptr->tried_fbo = true; + hijackWindow(window()); + QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext); + ctx->d_ptr->internal_context = true; + ctx->makeCurrent(); + delete d_ptr->fbo; + + QGLFramebufferObjectFormat format; + format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); + format.setInternalFormat(GL_RGBA); + format.setTextureTarget(target); + + if (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit) + format.setSamples(8); + + d_ptr->fbo = new QGLFramebufferObject(rect.size(), format); + d_ptr->fbo->bind(); + if (d_ptr->fbo->isValid()) { + qDebug() << "Created Window Surface FBO" << rect.size() + << "with samples" << d_ptr->fbo->format().samples(); + return; + } else { + qDebug() << "QGLWindowSurface: Failed to create valid FBO, falling back"; + delete d_ptr->fbo; + d_ptr->fbo = 0; + } + } + +#if !defined(QT_OPENGL_ES_2) + if (d_ptr->destructive_swap_buffers && (d_ptr->pb || !d_ptr->tried_pb)) { d_ptr->tried_pb = true; if (d_ptr->pb) { @@ -494,7 +569,7 @@ void QGLWindowSurface::setGeometry(const QRect &rect) qt_gl_share_widget()); if (d_ptr->pb->isValid()) { - qDebug() << "PB Sample buffers:" << d_ptr->pb->format().sampleBuffers(); + qDebug() << "Created Window Surface Pixelbuffer, Sample buffers:" << d_ptr->pb->format().sampleBuffers(); d_ptr->pb->makeCurrent(); glGenTextures(1, &d_ptr->pb_tex_id); @@ -521,44 +596,32 @@ void QGLWindowSurface::setGeometry(const QRect &rect) d_ptr->pb = 0; } } - - if ((QGLExtensions::glExtensions & QGLExtensions::FramebufferObject) && (d_ptr->fbo || !d_ptr->tried_fbo)) { - d_ptr->tried_fbo = true; - hijackWindow(window()); - QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext); - ctx->d_ptr->internal_context = true; - ctx->makeCurrent(); - delete d_ptr->fbo; - d_ptr->fbo = new QGLFramebufferObject(rect.size(), QGLFramebufferObject::CombinedDepthStencil, - GLenum(target), GLenum(GL_RGBA)); - - d_ptr->fbo->bind(); - if (d_ptr->fbo->isValid()) { - return; - } else { - qDebug() << "QGLWindowSurface: Failed to create valid FBO, falling back"; - delete d_ptr->fbo; - d_ptr->fbo = 0; - } - } +#endif // !defined(QT_OPENGL_ES_2) hijackWindow(window()); QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext); ctx->makeCurrent(); - glGenTextures(1, &d_ptr->tex_id); - glBindTexture(target, d_ptr->tex_id); - glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + if (d_ptr->destructive_swap_buffers) { + glGenTextures(1, &d_ptr->tex_id); + glBindTexture(target, d_ptr->tex_id); + glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindTexture(target, 0); + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glBindTexture(target, 0); + } qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this;; d_ptr->ctx = ctx; d_ptr->ctx->d_ptr->internal_context = true; } +void QGLWindowSurface::setGeometry(const QRect &rect) +{ + QWindowSurface::setGeometry(rect); +} + bool QGLWindowSurface::scroll(const QRegion &area, int dx, int dy) { // this code randomly fails currently for unknown reasons @@ -582,7 +645,7 @@ bool QGLWindowSurface::scroll(const QRegion &area, int dx, int dy) return true; #endif - const GLenum target = qt_gl_preferredTextureTarget(); + const GLenum target = GL_TEXTURE_2D; glBindTexture(target, d_ptr->tex_id); glCopyTexImage2D(target, 0, GL_RGBA, br.x(), d_ptr->pb->height() - (br.y() + br.height()), br.width(), br.height(), 0); @@ -595,7 +658,7 @@ bool QGLWindowSurface::scroll(const QRegion &area, int dx, int dy) static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &br) { - const GLenum target = qt_gl_preferredTextureTarget(); + const GLenum target = GL_TEXTURE_2D; QRectF src = br.isEmpty() ? QRectF(QPointF(), texSize) : QRectF(QPointF(br.x(), texSize.height() - br.bottom()), br.size()); @@ -623,6 +686,7 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array); // qpaintengine_opengl.cpp qt_add_rect_to_array(rect, vertexArray); +#if !defined(QT_OPENGL_ES_2) glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray); glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray); @@ -634,6 +698,7 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); +#endif glDisable(target); glBindTexture(target, 0); diff --git a/src/opengl/qwindowsurface_gl_p.h b/src/opengl/qwindowsurface_gl_p.h index 0194378..d47e3e3 100644 --- a/src/opengl/qwindowsurface_gl_p.h +++ b/src/opengl/qwindowsurface_gl_p.h @@ -74,6 +74,7 @@ public: QPaintDevice *paintDevice(); void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); void setGeometry(const QRect &rect); + void updateGeometry(); bool scroll(const QRegion &area, int dx, int dy); void beginPaint(const QRegion ®ion); diff --git a/src/opengl/util/generator.cpp b/src/opengl/util/generator.cpp index de2450d..dac5a2d 100644 --- a/src/opengl/util/generator.cpp +++ b/src/opengl/util/generator.cpp @@ -116,7 +116,7 @@ QList<QStringPair> readConf(const QString &confFile) lineStream >> enumerator; if (lineStream.atEnd()) { - qDebug() << "Error in file" << confFile << "(" << enumerator << ")"; + qDebug() << "Error in file" << confFile << '(' << enumerator << ')'; exit(0); } diff --git a/src/plugins/accessible/widgets/rangecontrols.cpp b/src/plugins/accessible/widgets/rangecontrols.cpp index 9297d6e..6d8c184 100644 --- a/src/plugins/accessible/widgets/rangecontrols.cpp +++ b/src/plugins/accessible/widgets/rangecontrols.cpp @@ -799,7 +799,7 @@ int QAccessibleSlider::defaultAction(int /*child*/) const /*! \internal */ QString QAccessibleSlider::actionText(int /*action*/, Text /*t*/, int /*child*/) const { - return QString(QLatin1String("")); + return QLatin1String(""); } QAccessibleAbstractSlider::QAccessibleAbstractSlider(QWidget *w, Role r) diff --git a/src/plugins/accessible/widgets/rangecontrols.h b/src/plugins/accessible/widgets/rangecontrols.h index aea91e1..57073ee 100644 --- a/src/plugins/accessible/widgets/rangecontrols.h +++ b/src/plugins/accessible/widgets/rangecontrols.h @@ -60,6 +60,7 @@ class QDial; #ifndef QT_NO_SPINBOX class QAccessibleAbstractSpinBox: public QAccessibleWidgetEx, public QAccessibleValueInterface { + Q_ACCESSIBLE_OBJECT public: explicit QAccessibleAbstractSpinBox(QWidget *w); @@ -132,6 +133,7 @@ protected: class QAccessibleAbstractSlider: public QAccessibleWidgetEx, public QAccessibleValueInterface { + Q_ACCESSIBLE_OBJECT public: explicit QAccessibleAbstractSlider(QWidget *w, Role r = Slider); diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h index d4552e3..d1fd0da 100644 --- a/src/plugins/accessible/widgets/simplewidgets.h +++ b/src/plugins/accessible/widgets/simplewidgets.h @@ -115,6 +115,7 @@ public: class QAccessibleLineEdit : public QAccessibleWidgetEx, public QAccessibleTextInterface, public QAccessibleSimpleEditableTextInterface { + Q_ACCESSIBLE_OBJECT public: explicit QAccessibleLineEdit(QWidget *o, const QString &name = QString()); diff --git a/src/plugins/gfxdrivers/directfb/directfb.pro b/src/plugins/gfxdrivers/directfb/directfb.pro index 67f5d61..5c60b2f 100644 --- a/src/plugins/gfxdrivers/directfb/directfb.pro +++ b/src/plugins/gfxdrivers/directfb/directfb.pro @@ -6,6 +6,7 @@ QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers # These defines might be necessary if your DirectFB driver doesn't # support all of the DirectFB API. # +#DEFINES += QT_DIRECTFB_IMAGECACHE #DEFINES += QT_NO_DIRECTFB_WM #DEFINES += QT_NO_DIRECTFB_LAYER #DEFINES += QT_NO_DIRECTFB_PALETTE @@ -22,7 +23,7 @@ target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers INSTALLS += target HEADERS = qdirectfbscreen.h \ - qdirectfbsurface.h \ + qdirectfbwindowsurface.h \ qdirectfbpaintengine.h \ qdirectfbpaintdevice.h \ qdirectfbpixmap.h \ @@ -31,7 +32,7 @@ HEADERS = qdirectfbscreen.h \ SOURCES = qdirectfbscreen.cpp \ qdirectfbscreenplugin.cpp \ - qdirectfbsurface.cpp \ + qdirectfbwindowsurface.cpp \ qdirectfbpaintengine.cpp \ qdirectfbpaintdevice.cpp \ qdirectfbpixmap.cpp \ @@ -40,4 +41,4 @@ SOURCES = qdirectfbscreen.cpp \ QMAKE_CXXFLAGS += $$QT_CFLAGS_DIRECTFB LIBS += $$QT_LIBS_DIRECTFB - +DEFINES += $$QT_DEFINES_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp index 924090c..72e0ce5 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp @@ -56,15 +56,20 @@ IDirectFBSurface *QDirectFBPaintDevice::directFBSurface() const } -void QDirectFBPaintDevice::lockDirectFB() +void QDirectFBPaintDevice::lockDirectFB(uint flags) { - if (lockedImage) - return; // Already locked - - if (uchar *mem = QDirectFBScreen::lockSurface(dfbSurface, DSLF_WRITE, &bpl)) { - const QSize s = size(); - lockedImage = new QImage(mem, s.width(), s.height(), bpl, - QDirectFBScreen::getImageFormat(dfbSurface)); + if (!(lock & flags)) { + if (lock) + unlockDirectFB(); + if ((mem = QDirectFBScreen::lockSurface(dfbSurface, flags, &bpl))) { + const QSize s = size(); + lockedImage = new QImage(mem, s.width(), s.height(), bpl, + QDirectFBScreen::getImageFormat(dfbSurface)); + lock = flags; + Q_ASSERT(mem); + } else { + lock = 0; + } } } @@ -77,15 +82,19 @@ void QDirectFBPaintDevice::unlockDirectFB() dfbSurface->Unlock(dfbSurface); delete lockedImage; lockedImage = 0; + mem = 0; + lock = 0; } -void* QDirectFBPaintDevice::memory() const +void *QDirectFBPaintDevice::memory() const { - QDirectFBPaintDevice* that = const_cast<QDirectFBPaintDevice*>(this); - that->lockDirectFB(); - Q_ASSERT(that->lockedImage); - return that->lockedImage->bits(); + if (lock != (DSLF_READ|DSLF_WRITE)) { + QDirectFBPaintDevice *that = const_cast<QDirectFBPaintDevice*>(this); + that->lockDirectFB(DSLF_READ|DSLF_WRITE); + Q_ASSERT(that->lockedImage); + } + return mem; } @@ -101,7 +110,7 @@ int QDirectFBPaintDevice::bytesPerLine() const // Can only get the stride when we lock the surface Q_ASSERT(!lockedImage); QDirectFBPaintDevice* that = const_cast<QDirectFBPaintDevice*>(this); - that->lockDirectFB(); + that->lockDirectFB(DSLF_READ); Q_ASSERT(bpl != -1); } return bpl; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h index a11064b..13f0a8f 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h @@ -58,7 +58,7 @@ public: IDirectFBSurface *directFBSurface() const; - void lockDirectFB(); + void lockDirectFB(uint flags); void unlockDirectFB(); inline bool forceRasterPrimitives() const { return forceRaster; } @@ -69,6 +69,7 @@ public: int bytesPerLine() const; QSize size() const; int metric(QPaintDevice::PaintDeviceMetric metric) const; + uint lockFlags() const { return lock; } protected: // Shouldn't create QDirectFBPaintDevice by itself but only sub-class it: QDirectFBPaintDevice(QDirectFBScreen *scr = QDirectFBScreen::instance()) @@ -76,7 +77,10 @@ protected: dfbSurface(0), lockedImage(0), screen(scr), - forceRaster(false) {} + forceRaster(false), + lock(0), + mem(0) + {} inline int dotsPerMeterX() const { @@ -92,6 +96,8 @@ protected: QDirectFBScreen *screen; int bpl; bool forceRaster; + uint lock; + uchar *mem; private: Q_DISABLE_COPY(QDirectFBPaintDevice) }; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index 14d2146..a68bc8f 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -43,7 +43,7 @@ #ifndef QT_NO_DIRECTFB -#include "qdirectfbsurface.h" +#include "qdirectfbwindowsurface.h" #include "qdirectfbscreen.h" #include "qdirectfbpixmap.h" #include <directfb.h> @@ -80,7 +80,7 @@ template <typename T> inline const T *ptr(const T &t) { return &t; } template <> inline const bool* ptr<bool>(const bool &) { return 0; } template <typename device, typename T1, typename T2, typename T3> static void rasterFallbackWarn(const char *msg, const char *func, const device *dev, - bool matrixScale, bool matrixRotShear, bool simplePen, + int scale, bool matrixRotShear, bool simplePen, bool dfbHandledClip, bool forceRasterPrimitives, const char *nameOne, const T1 &one, const char *nameTwo, const T2 &two, @@ -95,7 +95,7 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device * dbg << dev << "of type" << dev->devType(); } - dbg << "matrixScale" << matrixScale + dbg << "scale" << scale << "matrixRotShear" << matrixRotShear << "simplePen" << simplePen << "dfbHandledClip" << dfbHandledClip @@ -123,7 +123,7 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device * if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)) \ rasterFallbackWarn("Disabled raster engine operation", \ __FUNCTION__, state()->painter->device(), \ - d_func()->matrixScale, d_func()->matrixRotShear, \ + d_func()->scale, d_func()->matrixRotShear, \ d_func()->simplePen, d_func()->dfbCanHandleClip(), \ d_func()->forceRasterPrimitives, \ #one, one, #two, two, #three, three); \ @@ -138,7 +138,7 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device * if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)) \ rasterFallbackWarn("Falling back to raster engine for", \ __FUNCTION__, state()->painter->device(), \ - d_func()->matrixScale, d_func()->matrixRotShear, \ + d_func()->scale, d_func()->matrixRotShear, \ d_func()->simplePen, d_func()->dfbCanHandleClip(), \ d_func()->forceRasterPrimitives, \ #one, one, #two, two, #three, three); @@ -156,129 +156,66 @@ static inline uint ALPHA_MUL(uint x, uint a) class SurfaceCache { public: - SurfaceCache(); - ~SurfaceCache(); + SurfaceCache() : surface(0), buffer(0), bufsize(0) {} + ~SurfaceCache() { clear(); } - inline IDirectFBSurface *getSurface(const uint *buffer, int size); - inline void clear(); -private: - IDirectFBSurface *surface; - uint *buffer; - int bufsize; -}; - -SurfaceCache::SurfaceCache() - : surface(0), buffer(0), bufsize(0) -{ -} + IDirectFBSurface *getSurface(const uint *buf, int size) + { + if (buffer == buf && bufsize == size) + return surface; -class CachedImage -{ -public: - CachedImage(const QImage &image); - ~CachedImage(); + clear(); - IDirectFBSurface *surface() { return s; } + const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size); + surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface); + if (!surface) + qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface"); -private: - IDirectFBSurface *s; -}; - -CachedImage::CachedImage(const QImage &image) - : s(0) -{ - IDirectFBSurface *tmpSurface = 0; - DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(image); - QDirectFBScreen* screen = QDirectFBScreen::instance(); + buffer = const_cast<uint*>(buf); + bufsize = size; - tmpSurface = screen->createDFBSurface(description, QDirectFBScreen::TrackSurface); - if (!tmpSurface) { - qWarning("CachedImage CreateSurface failed!"); - return; + return surface; } -#ifndef QT_NO_DIRECTFB_PALETTE - QDirectFBScreen::setSurfaceColorTable(tmpSurface, image); -#endif - - description.flags = DFBSurfaceDescriptionFlags(description.flags & ~DSDESC_PREALLOCATED); - - s = screen->createDFBSurface(description, QDirectFBScreen::TrackSurface); - if (!s) - qWarning("QDirectFBPaintEngine failed caching image"); - -#ifndef QT_NO_DIRECTFB_PALETTE - QDirectFBScreen::setSurfaceColorTable(s, image); -#endif - - if (s) { - s->SetBlittingFlags(s, DSBLIT_NOFX); - s->Blit(s, tmpSurface, 0, 0, 0); - s->ReleaseSource(s); + void clear() + { + if (surface && QDirectFBScreen::instance()) + QDirectFBScreen::instance()->releaseDFBSurface(surface); + surface = 0; + buffer = 0; + bufsize = 0; } - if (tmpSurface) - screen->releaseDFBSurface(tmpSurface); -} - -CachedImage::~CachedImage() -{ - if (s && QDirectFBScreen::instance()) - QDirectFBScreen::instance()->releaseDFBSurface(s); -} - -static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB - -IDirectFBSurface* SurfaceCache::getSurface(const uint *buf, int size) -{ - if (buffer == buf && bufsize == size) - return surface; - - clear(); - - const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size); - surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface); - if (!surface) - qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface"); - - buffer = const_cast<uint*>(buf); - bufsize = size; - - return surface; -} +private: + IDirectFBSurface *surface; + uint *buffer; + int bufsize; +}; -void SurfaceCache::clear() -{ - if (surface) - QDirectFBScreen::instance()->releaseDFBSurface(surface); - surface = 0; - buffer = 0; - bufsize = 0; -} -SurfaceCache::~SurfaceCache() +#ifdef QT_DIRECTFB_IMAGECACHE +#include <private/qimage_p.h> +struct CachedImage { - clear(); -} + IDirectFBSurface *surface; + ~CachedImage() + { + if (surface && QDirectFBScreen::instance()) { + QDirectFBScreen::instance()->releaseDFBSurface(surface); + } + } +}; +static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB +#endif class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate { public: + enum Scale { NoScale, Scaled, NegativeScale }; + QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p); ~QDirectFBPaintEnginePrivate(); - IDirectFBSurface *surface; - - QPen pen; - - bool antialiased; - bool forceRasterPrimitives; - - bool simplePen; - - bool matrixRotShear; - bool matrixScale; - void setTransform(const QTransform &m); void setPen(const QPen &pen); void setCompositionMode(QPainter::CompositionMode mode); @@ -304,26 +241,40 @@ public: void fillRects(const QRectF *rects, int count); void drawRects(const QRectF *rects, int count); - - void drawPixmap(const QRectF &dest, - const QPixmap &pixmap, const QRectF &src); void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap); - void drawImage(const QRectF &dest, const QImage &image, const QRectF &src); + void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src); inline void updateClip(); - inline void setClipDirty(); void systemStateChanged(); void begin(QPaintDevice *device); void end(); + static IDirectFBSurface *getSurface(const QImage &img, bool *release); + +#ifdef QT_DIRECTFB_IMAGECACHE + static inline int cacheCost(const QImage &img) { return img.width() * img.height() * img.depth() / 8; } +#endif + void prepareForBlit(bool alpha); +private: + IDirectFBSurface *surface; + + QPen pen; + + bool antialiased; + bool forceRasterPrimitives; + + bool simplePen; + + bool matrixRotShear; + Scale scale; + SurfaceCache *surfaceCache; QTransform transform; int lastLockedHeight; -private: + IDirectFB *fb; - DFBSurfaceDescription fbDescription; int fbWidth; int fbHeight; @@ -336,469 +287,12 @@ private: bool dfbHandledClip; bool ignoreSystemClip; QDirectFBPaintDevice *dfbDevice; + void *lockedMemory; QDirectFBPaintEngine *q; + friend class QDirectFBPaintEngine; }; -QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p) - : surface(0), antialiased(false), forceRasterPrimitives(false), simplePen(false), - matrixRotShear(false), matrixScale(false), lastLockedHeight(-1), - fbWidth(-1), fbHeight(-1), opacity(255), drawFlagsFromCompositionMode(0), - blitFlagsFromCompositionMode(0), porterDuffRule(DSPD_SRC_OVER), dirtyClip(true), - dfbHandledClip(false), dfbDevice(0), q(p) -{ - fb = QDirectFBScreen::instance()->dfb(); - ignoreSystemClip = QDirectFBScreen::instance()->directFBFlags() & QDirectFBScreen::IgnoreSystemClip; - surfaceCache = new SurfaceCache; - static int cacheLimit = qgetenv("QT_DIRECTFB_IMAGECACHE").toInt(); - if (cacheLimit > 0) - imageCache.setMaxCost(cacheLimit * 1024); -} - -QDirectFBPaintEnginePrivate::~QDirectFBPaintEnginePrivate() -{ - delete surfaceCache; -} - -bool QDirectFBPaintEnginePrivate::dfbCanHandleClip(const QRect &rect) const -{ - // TODO: Check to see if DirectFB can handle the clip for the given rect - return dfbHandledClip; -} - -bool QDirectFBPaintEnginePrivate::dfbCanHandleClip(const QRectF &rect) const -{ - // TODO: Check to see if DirectFB can handle the clip for the given rect - return dfbHandledClip; -} - -bool QDirectFBPaintEnginePrivate::dfbCanHandleClip() const -{ - return dfbHandledClip; -} - -bool QDirectFBPaintEnginePrivate::isSimpleBrush(const QBrush &brush) const -{ - return (brush.style() == Qt::NoBrush) || (brush.style() == Qt::SolidPattern && !antialiased); -} - -void QDirectFBPaintEnginePrivate::setClipDirty() -{ - dirtyClip = true; -} - -void QDirectFBPaintEnginePrivate::lock() -{ - // We will potentially get a new pointer to the buffer after a - // lock so we need to call the base implementation of prepare so - // it updates its rasterBuffer to point to the new buffer address. - lastLockedHeight = dfbDevice->height(); - - Q_ASSERT(dfbDevice); - prepare(dfbDevice); -} - -void QDirectFBPaintEnginePrivate::unlock() -{ - Q_ASSERT(dfbDevice); - dfbDevice->unlockDirectFB(); -} - -void QDirectFBPaintEnginePrivate::setTransform(const QTransform &m) -{ - transform = m; - matrixRotShear = (transform.m12() != 0 || transform.m21() != 0); - matrixScale = (transform.m11() != 1 || transform.m22() != 1); -} - -void QDirectFBPaintEnginePrivate::begin(QPaintDevice *device) -{ - lastLockedHeight = -1; - if (device->devType() == QInternal::CustomRaster) - dfbDevice = static_cast<QDirectFBPaintDevice*>(device); - else if (device->devType() == QInternal::Pixmap) { - QPixmapData *data = static_cast<QPixmap*>(device)->pixmapData(); - Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); - QDirectFBPixmapData* dfbPixmapData = static_cast<QDirectFBPixmapData*>(data); - dfbDevice = static_cast<QDirectFBPaintDevice*>(dfbPixmapData); - } - - if (dfbDevice) - surface = dfbDevice->directFBSurface(); - - if (!surface) { - qFatal("QDirectFBPaintEngine used on an invalid device: 0x%x", - device->devType()); - } - forceRasterPrimitives = dfbDevice->forceRasterPrimitives(); - - surface->GetSize(surface, &fbWidth, &fbHeight); - - setTransform(QTransform()); - antialiased = false; - opacity = 255; - setCompositionMode(q->state()->compositionMode()); - dirtyClip = true; - setPen(q->state()->pen); - setDFBColor(pen.color()); -} - -void QDirectFBPaintEnginePrivate::end() -{ - dfbDevice = 0; - surface->ReleaseSource(surface); - surface->SetClip(surface, NULL); - surface = 0; -} - -void QDirectFBPaintEnginePrivate::setPen(const QPen &p) -{ - pen = p; - simplePen = (pen.style() == Qt::NoPen) || - (pen.style() == Qt::SolidLine - && !antialiased - && (pen.brush().style() == Qt::SolidPattern) - && (pen.widthF() <= 1 && !matrixScale)); -} - -void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode mode) -{ - blitFlagsFromCompositionMode = DSBLIT_NOFX; - drawFlagsFromCompositionMode = DSDRAW_NOFX; - - bool blend = true; - switch (mode) { - case QPainter::CompositionMode_SourceOver: - porterDuffRule = DSPD_SRC_OVER; - break; - case QPainter::CompositionMode_DestinationOver: - porterDuffRule = DSPD_DST_OVER; - break; - case QPainter::CompositionMode_Clear: - porterDuffRule = DSPD_CLEAR; - blend = false; - break; - case QPainter::CompositionMode_Source: - porterDuffRule = DSPD_SRC; - blend = false; - break; - case QPainter::CompositionMode_Destination: - porterDuffRule = DSPD_NONE; // ### need to double check this - blend = false; - return; - case QPainter::CompositionMode_SourceIn: - porterDuffRule = DSPD_SRC_IN; - break; - case QPainter::CompositionMode_DestinationIn: - porterDuffRule = DSPD_DST_IN; - break; - case QPainter::CompositionMode_SourceOut: - porterDuffRule = DSPD_SRC_OUT; - break; - case QPainter::CompositionMode_DestinationOut: - porterDuffRule = DSPD_DST_OUT; - break; - case QPainter::CompositionMode_Xor: - porterDuffRule = DSPD_XOR; - blitFlagsFromCompositionMode |= DSBLIT_XOR; - drawFlagsFromCompositionMode |= DSDRAW_XOR; - break; -// case QPainter::CompositionMode_Plus: // ??? -// porterDuffRule = DSPD_ADD; -// break; - default: - qWarning("QDirectFBPaintEnginePrivate::setCompositionMode(): " - "mode %d not implemented", mode); - return; - } - // intentially not comparing with current porterDuffRule. surface might have changed. - if (blend) { - blitFlagsFromCompositionMode |= DSBLIT_BLEND_ALPHACHANNEL; - drawFlagsFromCompositionMode |= DSDRAW_BLEND; - } - if (opacity != 255) { - setOpacity(opacity); - } -} - -void QDirectFBPaintEnginePrivate::setOpacity(quint8 op) -{ - opacity = op; - if (opacity == 255) { - blitFlagsFromCompositionMode &= ~DSBLIT_BLEND_COLORALPHA; - } else { - blitFlagsFromCompositionMode |= DSBLIT_BLEND_COLORALPHA; - } -} - -void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints) -{ - const bool old = antialiased; - antialiased = bool(hints & QPainter::Antialiasing); - if (old != antialiased) { - setPen(q->state()->pen); - } -} - -void QDirectFBPaintEnginePrivate::prepareForBlit(bool alpha) -{ - quint32 blittingFlags = blitFlagsFromCompositionMode; - if (alpha) { - surface->SetPorterDuff(surface, - (blittingFlags & DSBLIT_BLEND_COLORALPHA) - ? DSPD_NONE - : porterDuffRule); - } else { - blittingFlags &= ~DSBLIT_BLEND_ALPHACHANNEL; - surface->SetPorterDuff(surface, DSPD_NONE); - } - surface->SetColor(surface, 0xff, 0xff, 0xff, opacity); - surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(blittingFlags)); -} - -void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color) -{ - Q_ASSERT(surface); - const quint8 alpha = (opacity == 255 ? - color.alpha() : ALPHA_MUL(color.alpha(), opacity)); - surface->SetColor(surface, - color.red(), color.green(), color.blue(), alpha); - quint32 drawingFlags = drawFlagsFromCompositionMode; - if (alpha == 255) { - drawingFlags &= ~DSDRAW_BLEND; - } - surface->SetPorterDuff(surface, DSPD_NONE); - // PorterDuff messes up alpha values for primitives - surface->SetDrawingFlags(surface, DFBSurfaceDrawingFlags(drawingFlags)); -} - -void QDirectFBPaintEnginePrivate::drawLines(const QLine *lines, int n) -{ - for (int i = 0; i < n; ++i) { - const QLine l = transform.map(lines[i]); - surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); - } -} - -void QDirectFBPaintEnginePrivate::drawLines(const QLineF *lines, int n) -{ - for (int i = 0; i < n; ++i) { - const QLine l = transform.map(lines[i]).toLine(); - surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); - } -} - -void QDirectFBPaintEnginePrivate::fillRegion(const QRegion ®ion) -{ - Q_ASSERT(isSimpleBrush(q->state()->brush)); - setDFBColor(q->state()->brush.color()); - const QVector<QRect> rects = region.rects(); - const int n = rects.size(); - fillRects(rects.constData(), n); -} - -void QDirectFBPaintEnginePrivate::fillRects(const QRect *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]); - surface->FillRectangle(surface, r.x(), r.y(), - r.width(), r.height()); - } -} - -void QDirectFBPaintEnginePrivate::fillRects(const QRectF *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]).toRect(); - surface->FillRectangle(surface, r.x(), r.y(), - r.width(), r.height()); - } -} - -void QDirectFBPaintEnginePrivate::drawRects(const QRect *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]); - surface->DrawRectangle(surface, r.x(), r.y(), - r.width() + 1, r.height() + 1); - } -} - -void QDirectFBPaintEnginePrivate::drawRects(const QRectF *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]).toRect(); - surface->DrawRectangle(surface, r.x(), r.y(), - r.width() + 1, r.height() + 1); - } -} - -void QDirectFBPaintEnginePrivate::drawPixmap(const QRectF &dest, - const QPixmap &pixmap, - const QRectF &src) -{ - prepareForBlit(pixmap.hasAlphaChannel()); - QPixmapData *data = pixmap.pixmapData(); - Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); - QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); - IDirectFBSurface *s = dfbData->directFBSurface(); - const QRect sr = src.toRect(); - const QRect dr = transform.mapRect(dest).toRect(); - const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() }; - DFBResult result; - - if (dr.size() == sr.size()) { - result = surface->Blit(surface, s, &sRect, dr.x(), dr.y()); - } else { - const DFBRectangle dRect = { dr.x(), dr.y(), dr.width(), dr.height() }; - result = surface->StretchBlit(surface, s, &sRect, &dRect); - } - if (result != DFB_OK) - DirectFBError("QDirectFBPaintEngine::drawPixmap()", result); -} - -void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, - const QPixmap &pixmap) -{ - prepareForBlit(pixmap.hasAlphaChannel()); - QPixmapData *data = pixmap.pixmapData(); - Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); - QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); - IDirectFBSurface *s = dfbData->directFBSurface(); - const QRect dr = transform.mapRect(dest).toRect(); - DFBResult result = DFB_OK; - - if (!matrixScale && dr == QRect(0, 0, fbWidth, fbHeight)) { - result = surface->TileBlit(surface, s, 0, 0, 0); - } else if (!matrixScale) { - const int dx = pixmap.width(); - const int dy = pixmap.height(); - const DFBRectangle rect = { 0, 0, dx, dy }; - QVarLengthArray<DFBRectangle> rects; - QVarLengthArray<DFBPoint> points; - - for (int y = dr.y(); y <= dr.bottom(); y += dy) { - for (int x = dr.x(); x <= dr.right(); x += dx) { - rects.append(rect); - const DFBPoint point = { x, y }; - points.append(point); - } - } - result = surface->BatchBlit(surface, s, rects.constData(), - points.constData(), points.size()); - } else { - const QRect sr = transform.mapRect(QRect(0, 0, pixmap.width(), pixmap.height())); - const int dx = sr.width(); - const int dy = sr.height(); - const DFBRectangle sRect = { 0, 0, dx, dy }; - - for (int y = dr.y(); y <= dr.bottom(); y += dy) { - for (int x = dr.x(); x <= dr.right(); x += dx) { - const DFBRectangle dRect = { x, y, dx, dy }; - result = surface->StretchBlit(surface, s, &sRect, &dRect); - if (result != DFB_OK) { - y = dr.bottom() + 1; - break; - } - } - } - } - - if (result != DFB_OK) - DirectFBError("QDirectFBPaintEngine::drawTiledPixmap()", result); -} - -void QDirectFBPaintEnginePrivate::drawImage(const QRectF &dest, - const QImage &image, - const QRectF &src) -{ - Q_ASSERT(QDirectFBScreen::getSurfacePixelFormat(image.format()) != DSPF_UNKNOWN); - CachedImage *img = imageCache[image.cacheKey()]; - IDirectFBSurface *imgSurface = 0; - bool doRelease = false; - - if (img) { - imgSurface = img->surface(); - } else { - const int cost = image.width() * image.height() * image.depth() / 8; - if (cost <= imageCache.maxCost()) { - img = new CachedImage(image); - imgSurface = img->surface(); - if (imgSurface) { - imageCache.insert(image.cacheKey(), img, cost); - } else { - delete img; - img = 0; - } - } - - if (!imgSurface) { - DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(image); - imgSurface = QDirectFBScreen::instance()->createDFBSurface(description, - QDirectFBScreen::DontTrackSurface); - if (!imgSurface) { - qWarning("QDirectFBPaintEnginePrivate::drawImage"); - return; - } - -#ifndef QT_NO_DIRECTFB_PALETTE - QDirectFBScreen::setSurfaceColorTable(surface, image); -#endif - doRelease = (imgSurface != 0); - } - } - - const QRect sr = src.toRect(); - const QRect dr = transform.mapRect(dest).toRect(); - const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() }; - - prepareForBlit(image.hasAlphaChannel()); - if (dr.size() == sr.size()) { - surface->Blit(surface, imgSurface, &sRect, dr.x(), dr.y()); - } else { - const DFBRectangle dRect = { dr.x(), dr.y(), - dr.width(), dr.height() }; - surface->StretchBlit(surface, imgSurface, &sRect, &dRect); - } - if (doRelease) { - surface->ReleaseSource(surface); - imgSurface->Release(imgSurface); - } -} - -void QDirectFBPaintEnginePrivate::updateClip() -{ - if (!dirtyClip) - return; - - const QClipData *clipData = clip(); - if (!clipData || !clipData->enabled) { - surface->SetClip(surface, NULL); - dfbHandledClip = true; - } else if (clipData->hasRectClip) { - const DFBRegion r = { - clipData->clipRect.x(), - clipData->clipRect.y(), - clipData->clipRect.x() + clipData->clipRect.width(), - clipData->clipRect.y() + clipData->clipRect.height() - }; - surface->SetClip(surface, &r); - dfbHandledClip = true; - } else if (clipData->hasRegionClip && ignoreSystemClip && clipData->clipRegion == systemClip) { - dfbHandledClip = true; - } else { - dfbHandledClip = false; - } - - dirtyClip = false; -} - -void QDirectFBPaintEnginePrivate::systemStateChanged() -{ - setClipDirty(); - QRasterPaintEnginePrivate::systemStateChanged(); -} - QDirectFBPaintEngine::QDirectFBPaintEngine(QPaintDevice *device) : QRasterPaintEngine(*(new QDirectFBPaintEnginePrivate(this)), device) { @@ -827,12 +321,10 @@ bool QDirectFBPaintEngine::end() return QRasterPaintEngine::end(); } - - void QDirectFBPaintEngine::clipEnabledChanged() { Q_D(QDirectFBPaintEngine); - d->setClipDirty(); + d->dirtyClip = true; QRasterPaintEngine::clipEnabledChanged(); } @@ -868,9 +360,9 @@ void QDirectFBPaintEngine::renderHintsChanged() void QDirectFBPaintEngine::transformChanged() { Q_D(QDirectFBPaintEngine); - const bool old = d->matrixScale; + const QDirectFBPaintEnginePrivate::Scale old = d->scale; d->setTransform(state()->transform()); - if (d->matrixScale != old) { + if (d->scale != old) { d->setPen(state()->pen); } QRasterPaintEngine::transformChanged(); @@ -880,7 +372,7 @@ void QDirectFBPaintEngine::setState(QPainterState *s) { Q_D(QDirectFBPaintEngine); QRasterPaintEngine::setState(s); - d->setClipDirty(); + d->dirtyClip = true; d->setPen(state()->pen); d->setOpacity(quint8(state()->opacity * 255)); d->setCompositionMode(state()->compositionMode()); @@ -890,8 +382,8 @@ void QDirectFBPaintEngine::setState(QPainterState *s) void QDirectFBPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) { Q_D(QDirectFBPaintEngine); - d->setClipDirty(); - const QPoint bottom = d->transform.map(QPoint(0, path.controlPointRect().y2)); + d->dirtyClip = true; + const QPoint bottom = d->transform.map(QPoint(0, int(path.controlPointRect().y2))); if (bottom.y() >= d->lastLockedHeight) d->lock(); QRasterPaintEngine::clip(path, op); @@ -900,7 +392,7 @@ void QDirectFBPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) void QDirectFBPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) { Q_D(QDirectFBPaintEngine); - d->setClipDirty(); + d->dirtyClip = true; if (d->clip() && !d->clip()->hasRectClip && d->clip()->enabled) { const QPoint bottom = d->transform.map(QPoint(0, rect.bottom())); if (bottom.y() >= d->lastLockedHeight) @@ -1003,12 +495,36 @@ void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, Qt::ImageConversionFlags flags) { Q_D(QDirectFBPaintEngine); - Q_UNUSED(flags); // XXX + Q_UNUSED(flags); + + /* This is hard to read. The way it works is like this: + + - If you do not have support for preallocated surfaces and do not use an + image cache we always fall back to raster engine. + + - If it's rotated/sheared/mirrored (negative scale) or we can't + clip it we fall back to raster engine. + + - If we don't cache the image, but we do have support for + preallocated surfaces we fall back to the raster engine if the + image is in a format DirectFB can't handle. + + - If we do cache the image but don't have support for preallocated + images and the cost of caching the image (bytes used) is higher + than the max image cache size we fall back to raster engine. + */ -#ifndef QT_NO_DIRECTFB_PREALLOCATED d->updateClip(); - if (!d->dfbCanHandleClip(r) || d->matrixRotShear - || QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN) +#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE + if (d->matrixRotShear + || d->scale == QDirectFBPaintEnginePrivate::NegativeScale + || !d->dfbCanHandleClip(r) +#ifndef QT_DIRECTFB_IMAGECACHE + || QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN +#elif defined QT_NO_DIRECTFB_PREALLOCATED + || QDirectFBPaintEnginePrivate::cacheCost(image) > imageCache.maxCost() +#endif + ) #endif { RASTERFALLBACK(DRAW_IMAGE, r, image.size(), sr); @@ -1016,10 +532,16 @@ void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, QRasterPaintEngine::drawImage(r, image, sr, flags); return; } - -#ifndef QT_NO_DIRECTFB_PREALLOCATED +#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE d->unlock(); - d->drawImage(r, image, sr); + bool release; + IDirectFBSurface *imgSurface = d->getSurface(image, &release); + d->prepareForBlit(QDirectFBScreen::hasAlpha(imgSurface)); + d->blit(r, imgSurface, sr); + if (release) { + imgSurface->ReleaseSource(imgSurface); + imgSurface->Release(imgSurface); + } #endif } @@ -1038,14 +560,20 @@ void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); d->lock(); QRasterPaintEngine::drawPixmap(r, pixmap, sr); - } else if (!d->dfbCanHandleClip(r) || d->matrixRotShear) { + } else if (!d->dfbCanHandleClip(r) || d->matrixRotShear + || d->scale == QDirectFBPaintEnginePrivate::NegativeScale) { RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); - const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(); + const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(DSLF_READ); d->lock(); QRasterPaintEngine::drawImage(r, *img, sr); } else { d->unlock(); - d->drawPixmap(r, pixmap, sr); + d->prepareForBlit(pixmap.hasAlphaChannel()); + QPixmapData *data = pixmap.pixmapData(); + Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); + QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); + IDirectFBSurface *s = dfbData->directFBSurface(); + d->blit(r, s, sr); } } @@ -1064,9 +592,10 @@ void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r, RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), sp); d->lock(); QRasterPaintEngine::drawTiledPixmap(r, pixmap, sp); - } else if (!d->dfbCanHandleClip(r) || d->matrixRotShear || !sp.isNull()) { + } else if (!d->dfbCanHandleClip(r) || d->matrixRotShear || !sp.isNull() + || d->scale == QDirectFBPaintEnginePrivate::NegativeScale) { RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), sp); - const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(); + const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(DSLF_READ); d->lock(); QRasterPixmapData *data = new QRasterPixmapData(QPixmapData::PixmapType); data->fromImage(*img, Qt::AutoColor); @@ -1254,4 +783,457 @@ void QDirectFBPaintEngine::drawBufferSpan(const uint *buffer, int bufsize, d->surface->Blit(d->surface, src, &rect, x, y); } +#ifdef QT_DIRECTFB_IMAGECACHE +static void cachedImageCleanupHook(qint64 key) +{ + delete imageCache.take(key); +} +void QDirectFBPaintEngine::initImageCache(int size) +{ + Q_ASSERT(size >= 0); + imageCache.setMaxCost(size); + typedef void (*_qt_image_cleanup_hook_64)(qint64); + extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64; + qt_image_cleanup_hook_64 = ::cachedImageCleanupHook; +} + +#endif // QT_DIRECTFB_IMAGECACHE + +// ---- QDirectFBPaintEnginePrivate ---- + + +QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p) + : surface(0), antialiased(false), forceRasterPrimitives(false), simplePen(false), + matrixRotShear(false), scale(NoScale), lastLockedHeight(-1), + fbWidth(-1), fbHeight(-1), opacity(255), drawFlagsFromCompositionMode(0), + blitFlagsFromCompositionMode(0), porterDuffRule(DSPD_SRC_OVER), dirtyClip(true), + dfbHandledClip(false), dfbDevice(0), lockedMemory(0), q(p) +{ + fb = QDirectFBScreen::instance()->dfb(); + ignoreSystemClip = QDirectFBScreen::instance()->directFBFlags() & QDirectFBScreen::IgnoreSystemClip; + surfaceCache = new SurfaceCache; +} + +QDirectFBPaintEnginePrivate::~QDirectFBPaintEnginePrivate() +{ + delete surfaceCache; +} + +bool QDirectFBPaintEnginePrivate::dfbCanHandleClip(const QRect &rect) const +{ + // TODO: Check to see if DirectFB can handle the clip for the given rect + return dfbHandledClip; +} + +bool QDirectFBPaintEnginePrivate::dfbCanHandleClip(const QRectF &rect) const +{ + // TODO: Check to see if DirectFB can handle the clip for the given rect + return dfbHandledClip; +} + +bool QDirectFBPaintEnginePrivate::dfbCanHandleClip() const +{ + return dfbHandledClip; +} + +bool QDirectFBPaintEnginePrivate::isSimpleBrush(const QBrush &brush) const +{ + return (brush.style() == Qt::NoBrush) || (brush.style() == Qt::SolidPattern && !antialiased); +} + +void QDirectFBPaintEnginePrivate::lock() +{ + // We will potentially get a new pointer to the buffer after a + // lock so we need to call the base implementation of prepare so + // it updates its rasterBuffer to point to the new buffer address. + Q_ASSERT(dfbDevice); + if (dfbDevice->lockFlags() != (DSLF_WRITE|DSLF_READ) + || dfbDevice->height() != lastLockedHeight + || dfbDevice->memory() != lockedMemory) { + prepare(dfbDevice); + lastLockedHeight = dfbDevice->height(); + lockedMemory = dfbDevice->memory(); + } +} + +void QDirectFBPaintEnginePrivate::unlock() +{ + Q_ASSERT(dfbDevice); + dfbDevice->unlockDirectFB(); + lockedMemory = 0; +} + +void QDirectFBPaintEnginePrivate::setTransform(const QTransform &m) +{ + transform = m; + matrixRotShear = (transform.m12() != 0 || transform.m21() != 0); + if (qMin(transform.m11(), transform.m22()) < 0) { + scale = NegativeScale; + } else if (transform.m11() != 1 || transform.m22() != 1) { + scale = Scaled; + } else { + scale = NoScale; + } +} + +void QDirectFBPaintEnginePrivate::begin(QPaintDevice *device) +{ + lastLockedHeight = -1; + if (device->devType() == QInternal::CustomRaster) + dfbDevice = static_cast<QDirectFBPaintDevice*>(device); + else if (device->devType() == QInternal::Pixmap) { + QPixmapData *data = static_cast<QPixmap*>(device)->pixmapData(); + Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); + QDirectFBPixmapData* dfbPixmapData = static_cast<QDirectFBPixmapData*>(data); + dfbDevice = static_cast<QDirectFBPaintDevice*>(dfbPixmapData); + } + + if (dfbDevice) + surface = dfbDevice->directFBSurface(); + + if (!surface) { + qFatal("QDirectFBPaintEngine used on an invalid device: 0x%x", + device->devType()); + } + lockedMemory = 0; + forceRasterPrimitives = dfbDevice->forceRasterPrimitives(); + + surface->GetSize(surface, &fbWidth, &fbHeight); + + setTransform(QTransform()); + antialiased = false; + opacity = 255; + setCompositionMode(q->state()->compositionMode()); + dirtyClip = true; + setPen(q->state()->pen); + setDFBColor(pen.color()); +} + +void QDirectFBPaintEnginePrivate::end() +{ + lockedMemory = 0; + dfbDevice = 0; + surface->ReleaseSource(surface); + surface->SetClip(surface, NULL); + surface = 0; +} + +void QDirectFBPaintEnginePrivate::setPen(const QPen &p) +{ + pen = p; + simplePen = (pen.style() == Qt::NoPen) || + (pen.style() == Qt::SolidLine + && !antialiased + && (pen.brush().style() == Qt::SolidPattern) + && (pen.widthF() <= 1 && scale != NoScale)); +} + +void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode mode) +{ + blitFlagsFromCompositionMode = DSBLIT_NOFX; + drawFlagsFromCompositionMode = DSDRAW_NOFX; + + bool blend = true; + switch (mode) { + case QPainter::CompositionMode_SourceOver: + porterDuffRule = DSPD_SRC_OVER; + break; + case QPainter::CompositionMode_DestinationOver: + porterDuffRule = DSPD_DST_OVER; + break; + case QPainter::CompositionMode_Clear: + porterDuffRule = DSPD_CLEAR; + blend = false; + break; + case QPainter::CompositionMode_Source: + porterDuffRule = DSPD_SRC; + blend = false; + break; + case QPainter::CompositionMode_Destination: + porterDuffRule = DSPD_NONE; // ### need to double check this + blend = false; + return; + case QPainter::CompositionMode_SourceIn: + porterDuffRule = DSPD_SRC_IN; + break; + case QPainter::CompositionMode_DestinationIn: + porterDuffRule = DSPD_DST_IN; + break; + case QPainter::CompositionMode_SourceOut: + porterDuffRule = DSPD_SRC_OUT; + break; + case QPainter::CompositionMode_DestinationOut: + porterDuffRule = DSPD_DST_OUT; + break; + case QPainter::CompositionMode_Xor: + porterDuffRule = DSPD_XOR; + blitFlagsFromCompositionMode |= DSBLIT_XOR; + drawFlagsFromCompositionMode |= DSDRAW_XOR; + break; +// case QPainter::CompositionMode_Plus: // ??? +// porterDuffRule = DSPD_ADD; +// break; + default: + qWarning("QDirectFBPaintEnginePrivate::setCompositionMode(): " + "mode %d not implemented", mode); + return; + } + // intentially not comparing with current porterDuffRule. surface might have changed. + if (blend) { + blitFlagsFromCompositionMode |= DSBLIT_BLEND_ALPHACHANNEL; + drawFlagsFromCompositionMode |= DSDRAW_BLEND; + } + if (opacity != 255) { + setOpacity(opacity); + } +} + +void QDirectFBPaintEnginePrivate::setOpacity(quint8 op) +{ + opacity = op; + if (opacity == 255) { + blitFlagsFromCompositionMode &= ~DSBLIT_BLEND_COLORALPHA; + } else { + blitFlagsFromCompositionMode |= DSBLIT_BLEND_COLORALPHA; + } +} + +void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints) +{ + const bool old = antialiased; + antialiased = bool(hints & QPainter::Antialiasing); + if (old != antialiased) { + setPen(q->state()->pen); + } +} + +void QDirectFBPaintEnginePrivate::prepareForBlit(bool alpha) +{ + quint32 blittingFlags = blitFlagsFromCompositionMode; + if (alpha) { + surface->SetPorterDuff(surface, + (blittingFlags & DSBLIT_BLEND_COLORALPHA) + ? DSPD_NONE + : porterDuffRule); + } else { + blittingFlags &= ~DSBLIT_BLEND_ALPHACHANNEL; + surface->SetPorterDuff(surface, DSPD_NONE); + } + surface->SetColor(surface, 0xff, 0xff, 0xff, opacity); + surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(blittingFlags)); +} + +void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color) +{ + Q_ASSERT(surface); + const quint8 alpha = (opacity == 255 ? + color.alpha() : ALPHA_MUL(color.alpha(), opacity)); + surface->SetColor(surface, + color.red(), color.green(), color.blue(), alpha); + quint32 drawingFlags = drawFlagsFromCompositionMode; + if (alpha == 255) { + drawingFlags &= ~DSDRAW_BLEND; + } + surface->SetPorterDuff(surface, DSPD_NONE); + // PorterDuff messes up alpha values for primitives + surface->SetDrawingFlags(surface, DFBSurfaceDrawingFlags(drawingFlags)); +} + +void QDirectFBPaintEnginePrivate::drawLines(const QLine *lines, int n) +{ + for (int i = 0; i < n; ++i) { + const QLine l = transform.map(lines[i]); + surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); + } +} + +void QDirectFBPaintEnginePrivate::drawLines(const QLineF *lines, int n) +{ + for (int i = 0; i < n; ++i) { + const QLine l = transform.map(lines[i]).toLine(); + surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); + } +} + +void QDirectFBPaintEnginePrivate::fillRegion(const QRegion ®ion) +{ + Q_ASSERT(isSimpleBrush(q->state()->brush)); + setDFBColor(q->state()->brush.color()); + const QVector<QRect> rects = region.rects(); + const int n = rects.size(); + fillRects(rects.constData(), n); +} + +void QDirectFBPaintEnginePrivate::fillRects(const QRect *rects, int n) +{ + for (int i = 0; i < n; ++i) { + const QRect r = transform.mapRect(rects[i]); + surface->FillRectangle(surface, r.x(), r.y(), + r.width(), r.height()); + } +} + +void QDirectFBPaintEnginePrivate::fillRects(const QRectF *rects, int n) +{ + for (int i = 0; i < n; ++i) { + const QRect r = transform.mapRect(rects[i]).toRect(); + surface->FillRectangle(surface, r.x(), r.y(), + r.width(), r.height()); + } +} + +void QDirectFBPaintEnginePrivate::drawRects(const QRect *rects, int n) +{ + for (int i = 0; i < n; ++i) { + const QRect r = transform.mapRect(rects[i]); + surface->DrawRectangle(surface, r.x(), r.y(), + r.width() + 1, r.height() + 1); + } +} + +void QDirectFBPaintEnginePrivate::drawRects(const QRectF *rects, int n) +{ + for (int i = 0; i < n; ++i) { + const QRect r = transform.mapRect(rects[i]).toRect(); + surface->DrawRectangle(surface, r.x(), r.y(), + r.width() + 1, r.height() + 1); + } +} + +IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, bool *release) +{ +#ifndef QT_DIRECTFB_IMAGECACHE + *release = true; + return QDirectFBScreen::instance()->createDFBSurface(img, QDirectFBScreen::DontTrackSurface); +#else + const qint64 key = img.cacheKey(); + *release = false; + if (imageCache.contains(key)) { + return imageCache[key]->surface; + } + + const int cost = cacheCost(img); + const bool cache = cost <= imageCache.maxCost(); + QDirectFBScreen *screen = QDirectFBScreen::instance(); + const QImage::Format format = (img.format() == screen->alphaPixmapFormat() || QDirectFBPixmapData::hasAlphaChannel(img) + ? screen->alphaPixmapFormat() : screen->pixelFormat()); + + IDirectFBSurface *surface = screen->copyToDFBSurface(img, format, + cache + ? QDirectFBScreen::TrackSurface + : QDirectFBScreen::DontTrackSurface); + if (cache) { + CachedImage *cachedImage = new CachedImage; + const_cast<QImage&>(img).data_ptr()->is_cached = true; + cachedImage->surface = surface; + imageCache.insert(key, cachedImage, cost); + } else { + *release = true; + } + return surface; +#endif +} + + +void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, const QRectF &src) +{ + const QRect sr = src.toRect(); + const QRect dr = transform.mapRect(dest).toRect(); + const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() }; + DFBResult result; + + if (dr.size() == sr.size()) { + result = surface->Blit(surface, s, &sRect, dr.x(), dr.y()); + } else { + const DFBRectangle dRect = { dr.x(), dr.y(), dr.width(), dr.height() }; + result = surface->StretchBlit(surface, s, &sRect, &dRect); + } + if (result != DFB_OK) + DirectFBError("QDirectFBPaintEngine::drawPixmap()", result); +} + +void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, + const QPixmap &pixmap) +{ + prepareForBlit(pixmap.hasAlphaChannel()); + QPixmapData *data = pixmap.pixmapData(); + Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); + QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); + IDirectFBSurface *s = dfbData->directFBSurface(); + const QRect dr = transform.mapRect(dest).toRect(); + DFBResult result = DFB_OK; + + if (scale == NoScale && dr == QRect(0, 0, fbWidth, fbHeight)) { + result = surface->TileBlit(surface, s, 0, 0, 0); + } else if (scale == NoScale) { + const int dx = pixmap.width(); + const int dy = pixmap.height(); + const DFBRectangle rect = { 0, 0, dx, dy }; + QVarLengthArray<DFBRectangle> rects; + QVarLengthArray<DFBPoint> points; + + for (int y = dr.y(); y <= dr.bottom(); y += dy) { + for (int x = dr.x(); x <= dr.right(); x += dx) { + rects.append(rect); + const DFBPoint point = { x, y }; + points.append(point); + } + } + result = surface->BatchBlit(surface, s, rects.constData(), + points.constData(), points.size()); + } else { + const QRect sr = transform.mapRect(QRect(0, 0, pixmap.width(), pixmap.height())); + const int dx = sr.width(); + const int dy = sr.height(); + const DFBRectangle sRect = { 0, 0, dx, dy }; + + for (int y = dr.y(); y <= dr.bottom(); y += dy) { + for (int x = dr.x(); x <= dr.right(); x += dx) { + const DFBRectangle dRect = { x, y, dx, dy }; + result = surface->StretchBlit(surface, s, &sRect, &dRect); + if (result != DFB_OK) { + y = dr.bottom() + 1; + break; + } + } + } + } + + if (result != DFB_OK) + DirectFBError("QDirectFBPaintEngine::drawTiledPixmap()", result); +} + +void QDirectFBPaintEnginePrivate::updateClip() +{ + if (!dirtyClip) + return; + + const QClipData *clipData = clip(); + if (!clipData || !clipData->enabled) { + surface->SetClip(surface, NULL); + dfbHandledClip = true; + } else if (clipData->hasRectClip) { + const DFBRegion r = { + clipData->clipRect.x(), + clipData->clipRect.y(), + clipData->clipRect.x() + clipData->clipRect.width(), + clipData->clipRect.y() + clipData->clipRect.height() + }; + surface->SetClip(surface, &r); + dfbHandledClip = true; + } else if (clipData->hasRegionClip && ignoreSystemClip && clipData->clipRegion == systemClip) { + dfbHandledClip = true; + } else { + dfbHandledClip = false; + } + + dirtyClip = false; +} + +void QDirectFBPaintEnginePrivate::systemStateChanged() +{ + dirtyClip = true; + QRasterPaintEnginePrivate::systemStateChanged(); +} + #endif // QT_NO_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h index e79ec61..d33255b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h @@ -106,6 +106,7 @@ public: virtual void clip(const QVectorPath &path, Qt::ClipOperation op); virtual void clip(const QRect &rect, Qt::ClipOperation op); + static void initImageCache(int size); }; QT_END_HEADER diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp index ea9bb3a..c9b676a 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -157,6 +157,16 @@ static bool checkForAlphaPixels(const QImage &img) return false; } +bool QDirectFBPixmapData::hasAlphaChannel(const QImage &img) +{ +#ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION + return ::checkForAlphaPixels(img); +#else + return img.hasAlphaChannel(); +#endif +} + + void QDirectFBPixmapData::fromImage(const QImage &i, Qt::ImageConversionFlags flags) { @@ -166,7 +176,7 @@ void QDirectFBPixmapData::fromImage(const QImage &i, const QImage img = (i.depth() == 1 ? i.convertToFormat(screen->alphaPixmapFormat()) : i); if (img.hasAlphaChannel() #ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION - && (flags & Qt::NoOpaqueDetection || ::checkForAlphaPixels(img)) + && (flags & Qt::NoOpaqueDetection || QDirectFBPixmapData::hasAlphaChannel(img)) #endif ) { alpha = true; @@ -261,7 +271,7 @@ void QDirectFBPixmapData::fill(const QColor &color) forceRaster = false; setSerialNumber(++global_ser_no); if (!dfbSurface) { - qWarning("QDirecttFBPixmapData::fill()"); + qWarning("QDirectFBPixmapData::fill()"); invalidate(); return; } @@ -357,7 +367,7 @@ QImage QDirectFBPixmapData::toImage() const return img->copy(); } -QPaintEngine* QDirectFBPixmapData::paintEngine() const +QPaintEngine *QDirectFBPixmapData::paintEngine() const { if (!engine) { // QDirectFBPixmapData is also a QCustomRasterPaintDevice, so pass @@ -368,10 +378,15 @@ QPaintEngine* QDirectFBPixmapData::paintEngine() const return engine; } +QImage *QDirectFBPixmapData::buffer() +{ + lockDirectFB(DSLF_READ|DSLF_WRITE); + return lockedImage; +} -QImage* QDirectFBPixmapData::buffer() +QImage * QDirectFBPixmapData::buffer(uint lockFlags) { - lockDirectFB(); + lockDirectFB(lockFlags); return lockedImage; } @@ -381,3 +396,4 @@ void QDirectFBPixmapData::invalidate() alpha = false; format = QImage::Format_Invalid; } + diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h index 6cfafcd..7cd60d6 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h @@ -69,11 +69,13 @@ public: Qt::TransformationMode mode) const; QImage toImage() const; QPaintEngine* paintEngine() const; - QImage *buffer(); + virtual QImage *buffer(); + QImage *buffer(uint lockFlags); // Pure virtual in QPixmapData, so re-implement here and delegate to QDirectFBPaintDevice int metric(QPaintDevice::PaintDeviceMetric m) const {return QDirectFBPaintDevice::metric(m);} inline QImage::Format pixelFormat() const { return format; } + static bool hasAlphaChannel(const QImage &img); private: void invalidate(); QDirectFBPaintEngine *engine; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp index c1b75c5..98e32ed 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include "qdirectfbscreen.h" -#include "qdirectfbsurface.h" +#include "qdirectfbwindowsurface.h" #include "qdirectfbpixmap.h" #include "qdirectfbmouse.h" #include "qdirectfbkeyboard.h" @@ -113,9 +113,9 @@ QDirectFBScreenPrivate::~QDirectFBScreenPrivate() delete keyboard; #endif - foreach (IDirectFBSurface *surf, allocatedSurfaces) - surf->Release(surf); - allocatedSurfaces.clear(); + for (QSet<IDirectFBSurface*>::const_iterator it = allocatedSurfaces.begin(); it != allocatedSurfaces.end(); ++it) { + (*it)->Release(*it); + } if (dfbSurface) dfbSurface->Release(dfbSurface); @@ -205,6 +205,7 @@ IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QSize &size, SurfaceCreationOptions options) { DFBSurfaceDescription desc; + memset(&desc, 0, sizeof(DFBSurfaceDescription)); desc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH|DSDESC_HEIGHT); if (!QDirectFBScreen::initSurfaceDescriptionPixelFormat(&desc, format)) return 0; @@ -213,7 +214,6 @@ IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QSize &size, return createDFBSurface(desc, options); } - IDirectFBSurface *QDirectFBScreen::createDFBSurface(DFBSurfaceDescription desc, SurfaceCreationOptions options) { DFBResult result = DFB_OK; @@ -247,6 +247,7 @@ IDirectFBSurface *QDirectFBScreen::createDFBSurface(DFBSurfaceDescription desc, } desc.caps = DFBSurfaceCapabilities(desc.caps & ~DSCAPS_VIDEOONLY); } + if (d_ptr->directFBFlags & SystemOnly) desc.caps = DFBSurfaceCapabilities(desc.caps | DSCAPS_SYSTEMONLY); @@ -293,14 +294,14 @@ IDirectFBSurface *QDirectFBScreen::copyToDFBSurface(const QImage &img, IDirectFBSurface *dfbSurface = createDFBSurface(image.size(), pixmapFormat, options); if (!dfbSurface) { - qWarning("QDirectFBPixmapData::fromImage() Couldn't create surface"); + qWarning("QDirectFBScreen::copyToDFBSurface() Couldn't create surface"); return 0; } #ifndef QT_NO_DIRECTFB_PREALLOCATED IDirectFBSurface *imgSurface = createDFBSurface(image, DontTrackSurface); if (!imgSurface) { - qWarning("QDirectFBPixmapData::fromImage()"); + qWarning("QDirectFBScreen::copyToDFBSurface()"); QDirectFBScreen::releaseDFBSurface(dfbSurface); return 0; } @@ -315,7 +316,7 @@ IDirectFBSurface *QDirectFBScreen::copyToDFBSurface(const QImage &img, dfbSurface->SetBlittingFlags(dfbSurface, flags); DFBResult result = dfbSurface->Blit(dfbSurface, imgSurface, 0, 0, 0); if (result != DFB_OK) - DirectFBError("QDirectFBPixmapData::fromImage()", result); + DirectFBError("QDirectFBScreen::copyToDFBSurface()", result); dfbSurface->ReleaseSource(dfbSurface); imgSurface->Release(imgSurface); #else // QT_NO_DIRECTFB_PREALLOCATED @@ -350,6 +351,7 @@ QDirectFBScreen::DirectFBFlags QDirectFBScreen::directFBFlags() const { return d_ptr->directFBFlags; } + IDirectFB *QDirectFBScreen::dfb() { return d_ptr->dfb; @@ -444,6 +446,7 @@ QImage::Format QDirectFBScreen::getImageFormat(IDirectFBSurface *surface) DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const QImage &image) { DFBSurfaceDescription description; + memset(&description, 0, sizeof(DFBSurfaceDescription)); const DFBSurfacePixelFormat format = getSurfacePixelFormat(image.format()); @@ -478,6 +481,7 @@ DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const uint *buffer, int length) { DFBSurfaceDescription description; + memset(&description, 0, sizeof(DFBSurfaceDescription)); description.flags = DFBSurfaceDescriptionFlags(DSDESC_CAPS | DSDESC_WIDTH @@ -751,43 +755,43 @@ struct FlagDescription { }; static const FlagDescription accelerationDescriptions[] = { - { "DFXL_NONE ", DFXL_NONE }, - { "DFXL_FILLRECTANGLE", DFXL_FILLRECTANGLE }, - { "DFXL_DRAWRECTANGLE", DFXL_DRAWRECTANGLE }, - { "DFXL_DRAWLINE", DFXL_DRAWLINE }, - { "DFXL_FILLTRIANGLE", DFXL_FILLTRIANGLE }, - { "DFXL_BLIT", DFXL_BLIT }, - { "DFXL_STRETCHBLIT", DFXL_STRETCHBLIT }, - { "DFXL_TEXTRIANGLES", DFXL_TEXTRIANGLES }, - { "DFXL_DRAWSTRING", DFXL_DRAWSTRING }, + { " DFXL_NONE ", DFXL_NONE }, + { " DFXL_FILLRECTANGLE", DFXL_FILLRECTANGLE }, + { " DFXL_DRAWRECTANGLE", DFXL_DRAWRECTANGLE }, + { " DFXL_DRAWLINE", DFXL_DRAWLINE }, + { " DFXL_FILLTRIANGLE", DFXL_FILLTRIANGLE }, + { " DFXL_BLIT", DFXL_BLIT }, + { " DFXL_STRETCHBLIT", DFXL_STRETCHBLIT }, + { " DFXL_TEXTRIANGLES", DFXL_TEXTRIANGLES }, + { " DFXL_DRAWSTRING", DFXL_DRAWSTRING }, { 0, 0 } }; static const FlagDescription blitDescriptions[] = { - { "DSBLIT_NOFX", DSBLIT_NOFX }, - { "DSBLIT_BLEND_ALPHACHANNEL", DSBLIT_BLEND_ALPHACHANNEL }, - { "DSBLIT_BLEND_COLORALPHA", DSBLIT_BLEND_COLORALPHA }, - { "DSBLIT_COLORIZE", DSBLIT_COLORIZE }, - { "DSBLIT_SRC_COLORKEY", DSBLIT_SRC_COLORKEY }, - { "DSBLIT_DST_COLORKEY", DSBLIT_DST_COLORKEY }, - { "DSBLIT_SRC_PREMULTIPLY", DSBLIT_SRC_PREMULTIPLY }, - { "DSBLIT_DST_PREMULTIPLY", DSBLIT_DST_PREMULTIPLY }, - { "DSBLIT_DEMULTIPLY", DSBLIT_DEMULTIPLY }, - { "DSBLIT_DEINTERLACE", DSBLIT_DEINTERLACE }, - { "DSBLIT_SRC_PREMULTCOLOR", DSBLIT_SRC_PREMULTCOLOR }, - { "DSBLIT_XOR", DSBLIT_XOR }, - { "DSBLIT_INDEX_TRANSLATION", DSBLIT_INDEX_TRANSLATION }, + { " DSBLIT_NOFX", DSBLIT_NOFX }, + { " DSBLIT_BLEND_ALPHACHANNEL", DSBLIT_BLEND_ALPHACHANNEL }, + { " DSBLIT_BLEND_COLORALPHA", DSBLIT_BLEND_COLORALPHA }, + { " DSBLIT_COLORIZE", DSBLIT_COLORIZE }, + { " DSBLIT_SRC_COLORKEY", DSBLIT_SRC_COLORKEY }, + { " DSBLIT_DST_COLORKEY", DSBLIT_DST_COLORKEY }, + { " DSBLIT_SRC_PREMULTIPLY", DSBLIT_SRC_PREMULTIPLY }, + { " DSBLIT_DST_PREMULTIPLY", DSBLIT_DST_PREMULTIPLY }, + { " DSBLIT_DEMULTIPLY", DSBLIT_DEMULTIPLY }, + { " DSBLIT_DEINTERLACE", DSBLIT_DEINTERLACE }, + { " DSBLIT_SRC_PREMULTCOLOR", DSBLIT_SRC_PREMULTCOLOR }, + { " DSBLIT_XOR", DSBLIT_XOR }, + { " DSBLIT_INDEX_TRANSLATION", DSBLIT_INDEX_TRANSLATION }, { 0, 0 } }; static const FlagDescription drawDescriptions[] = { - { "DSDRAW_NOFX", DSDRAW_NOFX }, - { "DSDRAW_BLEND", DSDRAW_BLEND }, - { "DSDRAW_DST_COLORKEY", DSDRAW_DST_COLORKEY }, - { "DSDRAW_SRC_PREMULTIPLY", DSDRAW_SRC_PREMULTIPLY }, - { "DSDRAW_DST_PREMULTIPLY", DSDRAW_DST_PREMULTIPLY }, - { "DSDRAW_DEMULTIPLY", DSDRAW_DEMULTIPLY }, - { "DSDRAW_XOR", DSDRAW_XOR }, + { " DSDRAW_NOFX", DSDRAW_NOFX }, + { " DSDRAW_BLEND", DSDRAW_BLEND }, + { " DSDRAW_DST_COLORKEY", DSDRAW_DST_COLORKEY }, + { " DSDRAW_SRC_PREMULTIPLY", DSDRAW_SRC_PREMULTIPLY }, + { " DSDRAW_DST_PREMULTIPLY", DSDRAW_DST_PREMULTIPLY }, + { " DSDRAW_DEMULTIPLY", DSDRAW_DEMULTIPLY }, + { " DSDRAW_XOR", DSDRAW_XOR }, { 0, 0 } }; #endif @@ -817,7 +821,7 @@ static const QByteArray flagDescriptions(uint mask, const FlagDescription *flags -static void printDirectFBInfo(IDirectFB *fb) +static void printDirectFBInfo(IDirectFB *fb, IDirectFBSurface *primarySurface) { DFBResult result; DFBGraphicsDeviceDescription dev; @@ -828,10 +832,14 @@ static void printDirectFBInfo(IDirectFB *fb) return; } - qDebug("Device: %s (%s), Driver: %s v%i.%i (%s)\n" - " acceleration: 0x%x%s,\nblit: 0x%x%s,\ndraw: 0x%0x%s\nvideo: %iKB\n", + DFBSurfacePixelFormat pixelFormat; + primarySurface->GetPixelFormat(primarySurface, &pixelFormat); + + qDebug("Device: %s (%s), Driver: %s v%i.%i (%s) Pixelformat: %d (%d)\n" + "acceleration: 0x%x%s\nblit: 0x%x%s\ndraw: 0x%0x%s\nvideo: %iKB\n", dev.name, dev.vendor, dev.driver.name, dev.driver.major, - dev.driver.minor, dev.driver.vendor, dev.acceleration_mask, + dev.driver.minor, dev.driver.vendor, DFB_PIXELFORMAT_INDEX(pixelFormat), + QDirectFBScreen::getImageFormat(primarySurface), dev.acceleration_mask, ::flagDescriptions(dev.acceleration_mask, accelerationDescriptions).constData(), dev.blitting_flags, ::flagDescriptions(dev.blitting_flags, blitDescriptions).constData(), dev.drawing_flags, ::flagDescriptions(dev.drawing_flags, drawDescriptions).constData(), @@ -882,9 +890,6 @@ bool QDirectFBScreen::connect(const QString &displaySpec) return false; } - if (displayArgs.contains(QLatin1String("debug"), Qt::CaseInsensitive)) - printDirectFBInfo(d_ptr->dfb); - if (displayArgs.contains(QLatin1String("videoonly"), Qt::CaseInsensitive)) d_ptr->directFBFlags |= VideoOnly; @@ -900,6 +905,12 @@ bool QDirectFBScreen::connect(const QString &displaySpec) d_ptr->directFBFlags |= BoundingRectFlip; } +#ifdef QT_DIRECTFB_IMAGECACHE + int imageCacheSize = 4 * 1024 * 1024; // 4 MB + ::setIntOption(displayArgs, QLatin1String("imagecachesize"), &imageCacheSize); + QDirectFBPaintEngine::initImageCache(imageCacheSize); +#endif + if (displayArgs.contains(QLatin1String("ignoresystemclip"), Qt::CaseInsensitive)) d_ptr->directFBFlags |= IgnoreSystemClip; @@ -909,6 +920,8 @@ bool QDirectFBScreen::connect(const QString &displaySpec) d_ptr->dfb->SetCooperativeLevel(d_ptr->dfb, DFSCL_FULLSCREEN); DFBSurfaceDescription description; + memset(&description, 0, sizeof(DFBSurfaceDescription)); + description.flags = DFBSurfaceDescriptionFlags(DSDESC_CAPS); if (::setIntOption(displayArgs, QLatin1String("width"), &description.width)) description.flags = DFBSurfaceDescriptionFlags(description.flags | DSDESC_WIDTH); @@ -945,6 +958,9 @@ bool QDirectFBScreen::connect(const QString &displaySpec) return false; } + if (displayArgs.contains(QLatin1String("debug"), Qt::CaseInsensitive)) + printDirectFBInfo(d_ptr->dfb, d_ptr->dfbSurface); + // Work out what format we're going to use for surfaces with an alpha channel d_ptr->alphaPixmapFormat = QDirectFBScreen::getImageFormat(d_ptr->dfbSurface); setPixelFormat(d_ptr->alphaPixmapFormat); @@ -1102,19 +1118,19 @@ QWSWindowSurface *QDirectFBScreen::createSurface(QWidget *widget) const { #ifdef QT_NO_DIRECTFB_WM if (QApplication::type() == QApplication::GuiServer) { - return new QDirectFBSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this), widget); + return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this), widget); } else { return QScreen::createSurface(widget); } #else - return new QDirectFBSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this), widget); + return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this), widget); #endif } QWSWindowSurface *QDirectFBScreen::createSurface(const QString &key) const { if (key == QLatin1String("directfb")) { - return new QDirectFBSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this)); + return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this)); } return QScreen::createSurface(key); } @@ -1147,7 +1163,7 @@ void QDirectFBScreen::compose(const QRegion ®ion) const QPoint offset = win->requestedRegion().boundingRect().topLeft(); if (surface->key() == QLatin1String("directfb")) { - QDirectFBSurface *s = static_cast<QDirectFBSurface*>(surface); + QDirectFBWindowSurface *s = static_cast<QDirectFBWindowSurface*>(surface); blit(s->directFBSurface(), offset, r); } else { blit(surface->image(), offset, r); @@ -1196,7 +1212,7 @@ void QDirectFBScreen::compose(const QRegion ®ion) const QPoint offset = win->requestedRegion().boundingRect().topLeft(); if (surface->key() == QLatin1String("directfb")) { - QDirectFBSurface *s = static_cast<QDirectFBSurface*>(surface); + QDirectFBWindowSurface *s = static_cast<QDirectFBWindowSurface*>(surface); blit(s->directFBSurface(), offset, r); } else { blit(surface->image(), offset, r); @@ -1336,12 +1352,12 @@ bool QDirectFBScreen::initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *d return true; } -uchar *QDirectFBScreen::lockSurface(IDirectFBSurface *surface, DFBSurfaceLockFlags flags, int *bpl) +uchar *QDirectFBScreen::lockSurface(IDirectFBSurface *surface, uint flags, int *bpl) { void *mem; - const DFBResult result = surface->Lock(surface, flags, static_cast<void**>(&mem), bpl); + const DFBResult result = surface->Lock(surface, static_cast<DFBSurfaceLockFlags>(flags), static_cast<void**>(&mem), bpl); if (result != DFB_OK) { - DirectFBError("QDirectFBPixmapData::lockSurface()", result); + DirectFBError("QDirectFBScreen::lockSurface()", result); } return reinterpret_cast<uchar*>(mem); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h index 42d0ebe..84199a2 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h @@ -105,8 +105,6 @@ public: TrackSurface = 1 }; Q_DECLARE_FLAGS(SurfaceCreationOptions, SurfaceCreationOption); - IDirectFBSurface *createDFBSurface(DFBSurfaceDescription desc, - SurfaceCreationOptions options); IDirectFBSurface *createDFBSurface(const QImage &image, SurfaceCreationOptions options); IDirectFBSurface *createDFBSurface(const QSize &size, @@ -130,6 +128,7 @@ public: static bool initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *description, QImage::Format format); static inline bool isPremultiplied(QImage::Format format); static inline bool hasAlpha(DFBSurfacePixelFormat format); + static inline bool hasAlpha(IDirectFBSurface *surface); QImage::Format alphaPixmapFormat() const; #ifndef QT_NO_DIRECTFB_PALETTE @@ -137,14 +136,17 @@ public: const QImage &image); #endif - static uchar *lockSurface(IDirectFBSurface *surface, DFBSurfaceLockFlags flags, int *bpl = 0); + static uchar *lockSurface(IDirectFBSurface *surface, uint flags, int *bpl = 0); private: + IDirectFBSurface *createDFBSurface(DFBSurfaceDescription desc, + SurfaceCreationOptions options); void compose(const QRegion &r); void blit(IDirectFBSurface *src, const QPoint &topLeft, const QRegion ®ion); QDirectFBScreenPrivate *d_ptr; + friend class SurfaceCache; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QDirectFBScreen::SurfaceCreationOptions); @@ -186,6 +188,14 @@ inline bool QDirectFBScreen::hasAlpha(DFBSurfacePixelFormat format) } } +inline bool QDirectFBScreen::hasAlpha(IDirectFBSurface *surface) +{ + Q_ASSERT(surface); + DFBSurfacePixelFormat format; + surface->GetPixelFormat(surface, &format); + return QDirectFBScreen::hasAlpha(format); +} + QT_END_HEADER #endif // QDIRECTFBSCREEN_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp index beb9b5f..cd8796b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qdirectfbsurface.h" +#include "qdirectfbwindowsurface.h" #include "qdirectfbscreen.h" #include "qdirectfbpaintengine.h" @@ -50,7 +50,7 @@ //#define QT_DIRECTFB_DEBUG_SURFACES 1 -QDirectFBSurface::QDirectFBSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr) +QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr) : QDirectFBPaintDevice(scr) #ifndef QT_NO_DIRECTFB_WM , dfbWindow(0) @@ -66,7 +66,7 @@ QDirectFBSurface::QDirectFBSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *sc #endif } -QDirectFBSurface::QDirectFBSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr, QWidget *widget) +QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr, QWidget *widget) : QWSWindowSurface(widget), QDirectFBPaintDevice(scr) #ifndef QT_NO_DIRECTFB_WM , dfbWindow(0) @@ -86,17 +86,17 @@ QDirectFBSurface::QDirectFBSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *sc #endif } -QDirectFBSurface::~QDirectFBSurface() +QDirectFBWindowSurface::~QDirectFBWindowSurface() { } -bool QDirectFBSurface::isValid() const +bool QDirectFBWindowSurface::isValid() const { return true; } #ifndef QT_NO_DIRECTFB_WM -void QDirectFBSurface::createWindow() +void QDirectFBWindowSurface::createWindow() { #ifdef QT_NO_DIRECTFB_LAYER #warning QT_NO_DIRECTFB_LAYER requires QT_NO_DIRECTFB_WM @@ -132,7 +132,7 @@ void QDirectFBSurface::createWindow() } #endif // QT_NO_DIRECTFB_WM -void QDirectFBSurface::setGeometry(const QRect &rect, const QRegion &mask) +void QDirectFBWindowSurface::setGeometry(const QRect &rect, const QRegion &mask) { if (rect.isNull()) { #ifndef QT_NO_DIRECTFB_WM @@ -178,15 +178,7 @@ void QDirectFBSurface::setGeometry(const QRect &rect, const QRegion &mask) "Unable to get DirectFB handle!"); } - DFBSurfaceDescription description; - description.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | - DSDESC_HEIGHT | - DSDESC_PIXELFORMAT); - description.width = rect.width(); - description.height = rect.height(); - QDirectFBScreen::initSurfaceDescriptionPixelFormat(&description, - screen->pixelFormat()); - dfbSurface = screen->createDFBSurface(description, false); + dfbSurface = screen->createDFBSurface(rect.size(), screen->pixelFormat(), QDirectFBScreen::DontTrackSurface); forceRaster = (dfbSurface && QDirectFBScreen::getImageFormat(dfbSurface) == QImage::Format_RGB32); } else { Q_ASSERT(dfbSurface); @@ -211,13 +203,13 @@ void QDirectFBSurface::setGeometry(const QRect &rect, const QRegion &mask) } if (result != DFB_OK) - DirectFBErrorFatal("QDirectFBSurface::setGeometry()", result); + DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result); } QWSWindowSurface::setGeometry(rect, mask); } -QByteArray QDirectFBSurface::permanentState() const +QByteArray QDirectFBWindowSurface::permanentState() const { QByteArray array; #ifdef QT_NO_DIRECTFB_WM @@ -236,7 +228,7 @@ QByteArray QDirectFBSurface::permanentState() const return array; } -void QDirectFBSurface::setPermanentState(const QByteArray &state) +void QDirectFBWindowSurface::setPermanentState(const QByteArray &state) { SurfaceFlags flags; const char *ptr = state.constData(); @@ -250,7 +242,7 @@ void QDirectFBSurface::setPermanentState(const QByteArray &state) #endif } -bool QDirectFBSurface::scroll(const QRegion ®ion, int dx, int dy) +bool QDirectFBWindowSurface::scroll(const QRegion ®ion, int dx, int dy) { if (!dfbSurface || !(flipFlags & DSFLIP_BLIT)) return false; @@ -278,7 +270,7 @@ bool QDirectFBSurface::scroll(const QRegion ®ion, int dx, int dy) return true; } -bool QDirectFBSurface::move(const QPoint &offset) +bool QDirectFBWindowSurface::move(const QPoint &offset) { QWSWindowSurface::move(offset); @@ -293,7 +285,7 @@ bool QDirectFBSurface::move(const QPoint &offset) #endif } -QRegion QDirectFBSurface::move(const QPoint &offset, const QRegion &newClip) +QRegion QDirectFBWindowSurface::move(const QPoint &offset, const QRegion &newClip) { #ifdef QT_NO_DIRECTFB_WM return QWSWindowSurface::move(offset, newClip); @@ -306,10 +298,10 @@ QRegion QDirectFBSurface::move(const QPoint &offset, const QRegion &newClip) #endif } -QPaintEngine* QDirectFBSurface::paintEngine() const +QPaintEngine* QDirectFBWindowSurface::paintEngine() const { if (!engine) { - QDirectFBSurface *that = const_cast<QDirectFBSurface*>(this); + QDirectFBWindowSurface *that = const_cast<QDirectFBWindowSurface*>(this); that->engine = new QDirectFBPaintEngine(that); return that->engine; } @@ -339,8 +331,8 @@ inline bool isWidgetOpaque(const QWidget *w) return false; } -void QDirectFBSurface::flush(QWidget *widget, const QRegion ®ion, - const QPoint &offset) +void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion ®ion, + const QPoint &offset) { Q_UNUSED(widget); #ifdef QT_NO_DIRECTFB_WM @@ -402,15 +394,15 @@ void QDirectFBSurface::flush(QWidget *widget, const QRegion ®ion, } -void QDirectFBSurface::beginPaint(const QRegion &) +void QDirectFBWindowSurface::beginPaint(const QRegion &) { } -void QDirectFBSurface::endPaint(const QRegion &) +void QDirectFBWindowSurface::endPaint(const QRegion &) { #ifdef QT_DIRECTFB_DEBUG_SURFACES if (bufferImages.count()) { - qDebug("QDirectFBSurface::endPaint() this=%p", this); + qDebug("QDirectFBWindowSurface::endPaint() this=%p", this); foreach(QImage* bufferImg, bufferImages) qDebug(" Deleting buffer image %p", bufferImg); @@ -423,7 +415,7 @@ void QDirectFBSurface::endPaint(const QRegion &) } -QImage* QDirectFBSurface::buffer(const QWidget *widget) +QImage *QDirectFBWindowSurface::buffer(const QWidget *widget) { if (!lockedImage) return 0; @@ -441,7 +433,7 @@ QImage* QDirectFBSurface::buffer(const QWidget *widget) bufferImages.append(img); #ifdef QT_DIRECTFB_DEBUG_SURFACES - qDebug("QDirectFBSurface::buffer() Created & returned %p", img); + qDebug("QDirectFBWindowSurface::buffer() Created & returned %p", img); #endif return img; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbsurface.h b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h index 54c14a5..75998c4 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbsurface.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h @@ -58,12 +58,12 @@ QT_BEGIN_HEADER QT_MODULE(Gui) -class QDirectFBSurface: public QWSWindowSurface, public QDirectFBPaintDevice +class QDirectFBWindowSurface : public QWSWindowSurface, public QDirectFBPaintDevice { public: - QDirectFBSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen* scr); - QDirectFBSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen* scr, QWidget *widget); - ~QDirectFBSurface(); + QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen* scr); + QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen* scr, QWidget *widget); + ~QDirectFBWindowSurface(); bool isValid() const; @@ -79,15 +79,15 @@ public: QRegion move(const QPoint &offset, const QRegion &newClip); QImage image() const { return QImage(); } - QPaintDevice* paintDevice() { return this; } - QPaintEngine* paintEngine() const; + QPaintDevice *paintDevice() { return this; } + QPaintEngine *paintEngine() const; void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); void beginPaint(const QRegion &); void endPaint(const QRegion &); - QImage* buffer(const QWidget *widget); + QImage *buffer(const QWidget *widget); private: #ifndef QT_NO_DIRECTFB_WM diff --git a/src/plugins/gfxdrivers/hybrid/hybridscreen.cpp b/src/plugins/gfxdrivers/hybrid/hybridscreen.cpp index 3a40b4c..da61a22 100644 --- a/src/plugins/gfxdrivers/hybrid/hybridscreen.cpp +++ b/src/plugins/gfxdrivers/hybrid/hybridscreen.cpp @@ -103,11 +103,11 @@ bool HybridScreen::connect(const QString &displaySpec) { QString dspec = displaySpec; if (dspec.startsWith(QLatin1String("hybrid:"), Qt::CaseInsensitive)) - dspec = dspec.mid(QString(QLatin1String("hybrid:")).size()); + dspec = dspec.mid(QString::fromLatin1("hybrid:").size()); else if (dspec.compare(QLatin1String("hybrid"), Qt::CaseInsensitive) == 0) dspec = QString(); - const QString displayIdSpec = QString(QLatin1String(" :%1")).arg(displayId); + const QString displayIdSpec = QString::fromLatin1(" :%1").arg(displayId); if (dspec.endsWith(displayIdSpec)) dspec = dspec.left(dspec.size() - displayIdSpec.size()); diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro b/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro index b62894d..9331d0a 100644 --- a/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro @@ -22,3 +22,5 @@ LIBS += -lpvr2d DESTDIR = $$QMAKE_LIBDIR_QT target.path = $$[QT_INSTALL_LIBS] INSTALLS += target + +include(../powervr.pri)
\ No newline at end of file diff --git a/src/plugins/gfxdrivers/powervr/README b/src/plugins/gfxdrivers/powervr/README index ec02efb..4dce87f 100644 --- a/src/plugins/gfxdrivers/powervr/README +++ b/src/plugins/gfxdrivers/powervr/README @@ -29,12 +29,13 @@ strictly Unix-style markers. *************************************************************************** * IMPORTANT: To build the QScreen plugin and the WSEGL library it depends * -* on, the pvr2d.h, wsegl.h headers for your platform are required. These * -* can be obtained either through your platform provider or directly from * -* Imagination Technologies. * +* on, the pvr2d.h, wsegl.h headers for your platform are required. You * +* can find a copy of these headers in src/3rdparty/powervr for SGX based * +* platforms like the TI OMAP3xxx. They may also work on MBX platforms too * +* depending on how old your libEGL is. You can tell Qt where to find * +* these headers by setting QMAKE_INCDIR_POWERVR in the mkspec. * *************************************************************************** - When you start a Qt/Embedded application, you should modify the QWS_DISPLAY environment variable to use the "powervr" driver instead of "LinuxFb". For example, if your original QWS_DISPLAY variable was: diff --git a/src/plugins/gfxdrivers/powervr/powervr.pri b/src/plugins/gfxdrivers/powervr/powervr.pri new file mode 100644 index 0000000..9df8c0e --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/powervr.pri @@ -0,0 +1,2 @@ + +INCLUDEPATH += $$QMAKE_INCDIR_POWERVR diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro index 691cd2d..675be85 100644 --- a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro @@ -9,9 +9,10 @@ DEFINES += QT_QWS_CLIENTBLIT INCLUDEPATH += ../QWSWSEGL + HEADERS = \ - pvreglscreen.h \ - pvreglwindowsurface.h + pvreglscreen.h \ + pvreglwindowsurface.h SOURCES = \ pvreglscreenplugin.cpp \ @@ -22,3 +23,5 @@ QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers INSTALLS += target + +include(../powervr.pri)
\ No newline at end of file diff --git a/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp b/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp index b7f03ba..8be3672 100644 --- a/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp +++ b/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp @@ -2100,11 +2100,11 @@ bool QVNCScreen::connect(const QString &displaySpec) { QString dspec = displaySpec; if (dspec.startsWith(QLatin1String("vnc:"), Qt::CaseInsensitive)) - dspec = dspec.mid(QString(QLatin1String("vnc:")).size()); + dspec = dspec.mid(QString::fromLatin1("vnc:").size()); else if (dspec.compare(QLatin1String("vnc"), Qt::CaseInsensitive) == 0) dspec = QString(); - const QString displayIdSpec = QString(QLatin1String(" :%1")).arg(displayId); + const QString displayIdSpec = QString::fromLatin1(" :%1").arg(displayId); if (dspec.endsWith(displayIdSpec)) dspec = dspec.left(dspec.size() - displayIdSpec.size()); diff --git a/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp b/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp index c7249d3..3273513 100644 --- a/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp +++ b/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp @@ -122,16 +122,10 @@ QSize QSvgIconEngine::actualSize(const QSize &size, QIcon::Mode mode, return size; } - QSvgRenderer renderer; - d->loadDataForModeAndState(&renderer, mode, state); - if (renderer.isValid()) { - QSize defaultSize = renderer.defaultSize(); - if (!defaultSize.isNull()) - defaultSize.scale(size, Qt::KeepAspectRatio); - return defaultSize; - } else { + QPixmap pm = pixmap(size, mode, state); + if (pm.isNull()) return QSize(); - } + return pm.size(); } void QSvgIconEnginePrivate::loadDataForModeAndState(QSvgRenderer *renderer, QIcon::Mode mode, QIcon::State state) diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp index 518e6d1..77dfeb3 100644 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp @@ -168,7 +168,7 @@ bool QTiffHandler::read(QImage *image) break; default: // do nothing as defaults have already - // been set within the QImage class + // been set within the QImage class break; } for (uint32 y=0; y<height; ++y) @@ -218,6 +218,24 @@ bool QTiffHandler::write(const QImage &image) return false; } + // set the resolution + bool resolutionSet = false; + const int dotPerMeterX = image.dotsPerMeterX(); + const int dotPerMeterY = image.dotsPerMeterY(); + if ((dotPerMeterX % 100) == 0 + && (dotPerMeterY % 100) == 0) { + resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER) + && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, dotPerMeterX/100.0) + && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, dotPerMeterY/100.0); + } else { + resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH) + && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, static_cast<float>(image.logicalDpiX())) + && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, static_cast<float>(image.logicalDpiY())); + } + if (!resolutionSet) { + TIFFClose(tiff); + return false; + } // try to do the ARGB32 conversion in chunks no greater than 16 MB int chunks = (width * height * 4 / (1024 * 1024 * 16)) + 1; int chunkHeight = qMax(height / chunks, 1); diff --git a/src/plugins/sqldrivers/odbc/odbc.pro b/src/plugins/sqldrivers/odbc/odbc.pro index 0835ce1..3de8ab2 100644 --- a/src/plugins/sqldrivers/odbc/odbc.pro +++ b/src/plugins/sqldrivers/odbc/odbc.pro @@ -4,15 +4,9 @@ HEADERS = ../../../sql/drivers/odbc/qsql_odbc.h SOURCES = main.cpp \ ../../../sql/drivers/odbc/qsql_odbc.cpp -mac { - !contains( LIBS, .*odbc.* ) { - LIBS *= -liodbc - } -} - unix { !contains( LIBS, .*odbc.* ) { - LIBS *= -lodbc + LIBS *= $$QT_LFLAGS_ODBC } } diff --git a/src/qbase.pri b/src/qbase.pri index 9ba8e70..0ab04e6 100644 --- a/src/qbase.pri +++ b/src/qbase.pri @@ -67,11 +67,6 @@ mac:!static:contains(QT_CONFIG, qt_framework) { mac { CONFIG += explicitlib - true { #we want to use O2 on Qt itself (Os was used to fix other failures in older GCC) - QMAKE_CFLAGS_RELEASE ~= s,-Os,-O2, - QMAKE_CXXFLAGS_RELEASE ~= s,-Os,-O2, - QMAKE_OBJECTIVE_CFLAGS_RELEASE ~= s,-Os,-O2, - } macx-g++ { QMAKE_CFLAGS += -fconstant-cfstrings QMAKE_CXXFLAGS += -fconstant-cfstrings diff --git a/src/qt3support/dialogs/q3filedialog.cpp b/src/qt3support/dialogs/q3filedialog.cpp index b9f8196..e41941b 100644 --- a/src/qt3support/dialogs/q3filedialog.cpp +++ b/src/qt3support/dialogs/q3filedialog.cpp @@ -3879,7 +3879,7 @@ void Q3FileDialog::detailViewSelectionChanged() d->moreFiles->setSelected(f->i, i->isSelected()); } if (i->isSelected() && !((Q3FileDialogPrivate::File *)i)->info.isDir()) - str += QString(QLatin1String("\"%1\" ")).arg(i->text(0)); + str += QString::fromLatin1("\"%1\" ").arg(i->text(0)); i = i->nextSibling(); } d->moreFiles->blockSignals(false); @@ -3931,7 +3931,7 @@ void Q3FileDialog::listBoxSelectionChanged() } if (d->moreFiles->isSelected(i) && !((Q3FileDialogPrivate::File*)(mcitem)->i)->info.isDir()) { - str += QString(QLatin1String("\"%1\" ")).arg(i->text()); + str += QString::fromLatin1("\"%1\" ").arg(i->text()); if (j == 0) j = i; } @@ -5757,8 +5757,8 @@ void Q3FileDialog::insertEntry(const Q3ValueList<QUrlInfo> &lst, Q3NetworkOperat if (!bShowHiddenFiles && inf.name() != QLatin1String("..")) { if (d->url.isLocalFile()) { QString file = d->url.path(); - if (!file.endsWith(QLatin1String("/"))) - file.append(QLatin1String("/")); + if (!file.endsWith(QLatin1Char('/'))) + file.append(QLatin1Char('/')); file += inf.name(); QT_WA({ if (GetFileAttributesW((TCHAR*)file.ucs2()) & FILE_ATTRIBUTE_HIDDEN) diff --git a/src/qt3support/dialogs/q3filedialog_mac.cpp b/src/qt3support/dialogs/q3filedialog_mac.cpp index f1c749ec..18bebf1 100644 --- a/src/qt3support/dialogs/q3filedialog_mac.cpp +++ b/src/qt3support/dialogs/q3filedialog_mac.cpp @@ -554,7 +554,7 @@ QString Q3FileDialog::macGetSaveFileName(const QString &start, const QString &fi retstr = QString::fromUtf8((const char *)str_buffer); //now filename CFStringGetCString(ret.saveFileName, (char *)str_buffer, 1024, kCFStringEncodingUTF8); - retstr += QLatin1String("/") + QString::fromUtf8((const char *)str_buffer); + retstr += QLatin1Char('/') + QString::fromUtf8((const char *)str_buffer); } NavDisposeReply(&ret); if(selectedFilter) diff --git a/src/qt3support/dialogs/q3filedialog_win.cpp b/src/qt3support/dialogs/q3filedialog_win.cpp index 1be797a..a1c98f3 100644 --- a/src/qt3support/dialogs/q3filedialog_win.cpp +++ b/src/qt3support/dialogs/q3filedialog_win.cpp @@ -737,7 +737,7 @@ QString Q3FileDialog::winGetExistingDirectory(const QString& initialDirectory, QDir::setCurrent(currentDir); if (!result.isEmpty()) - result.replace(QLatin1String("\\"), QLatin1String("/")); + result.replace(QLatin1Char('\\'), QLatin1Char('/')); return result; #else return QString(); diff --git a/src/qt3support/itemviews/q3iconview.cpp b/src/qt3support/itemviews/q3iconview.cpp index d1a9c1e..a5664de 100644 --- a/src/qt3support/itemviews/q3iconview.cpp +++ b/src/qt3support/itemviews/q3iconview.cpp @@ -614,7 +614,7 @@ QByteArray Q3IconDrag::encodedData(const char* mime) const (*it).item.textRect().x()).arg((*it).item.textRect().y()). arg((*it).item.textRect().width()).arg( (*it).item.textRect().height()); - k += QString(QLatin1String((*it).data.data())) + QLatin1String("$@@$"); + k += QString::fromLatin1((*it).data.data()) + QLatin1String("$@@$"); s += k; } @@ -1820,8 +1820,8 @@ void Q3IconViewItem::calcRect(const QString &text_) tw = r.width(); th = r.height(); - if (tw < view->d->fm->width(QLatin1String("X"))) - tw = view->d->fm->width(QLatin1String("X")); + if (tw < view->d->fm->width(QLatin1Char('X'))) + tw = view->d->fm->width(QLatin1Char('X')); itemTextRect.setWidth(tw); itemTextRect.setHeight(th); diff --git a/src/qt3support/network/q3dns.cpp b/src/qt3support/network/q3dns.cpp index c53f2ff..3ca3977 100644 --- a/src/qt3support/network/q3dns.cpp +++ b/src/qt3support/network/q3dns.cpp @@ -1738,7 +1738,7 @@ void Q3Dns::setLabel( const QString & label ) const char * dom; while( (dom=it.current()) != 0 ) { ++it; - n.append( l.lower() + QLatin1String(".") + QLatin1String(dom) ); + n.append( l.lower() + QLatin1Char('.') + QLatin1String(dom) ); } } n.append( l.lower() ); @@ -1902,8 +1902,8 @@ QString Q3Dns::toInAddrArpaDomain( const QHostAddress &address ) s = QLatin1String("ip6.arpa"); uint b = 0; while( b < 16 ) { - s = QString::number( i.c[b]%16, 16 ) + QLatin1String(".") + - QString::number( i.c[b]/16, 16 ) + QLatin1String(".") + s; + s = QString::number( i.c[b]%16, 16 ) + QLatin1Char('.') + + QString::number( i.c[b]/16, 16 ) + QLatin1Char('.') + s; b++; } } @@ -2347,7 +2347,7 @@ void Q3Dns::doResInit() nameServer += QLatin1String(dnsServer->IpAddress.String); dnsServer = dnsServer->Next; if ( dnsServer != 0 ) - nameServer += QLatin1String(" "); + nameServer += QLatin1Char(' '); } searchList = QLatin1String(""); separator = ' '; @@ -2360,12 +2360,12 @@ void Q3Dns::doResInit() } if ( !gotNetworkParams ) { if ( getDnsParamsFromRegistry( - QString( QLatin1String("System\\CurrentControlSet\\Services\\Tcpip\\Parameters") ), + QLatin1String("System\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &domainName, &nameServer, &searchList )) { // for NT separator = ' '; } else if ( getDnsParamsFromRegistry( - QString( QLatin1String("System\\CurrentControlSet\\Services\\VxD\\MSTCP") ), + QLatin1String("System\\CurrentControlSet\\Services\\VxD\\MSTCP"), &domainName, &nameServer, &searchList )) { // for Windows 98 separator = ','; @@ -2395,7 +2395,7 @@ void Q3Dns::doResInit() } while( first < (int)nameServer.length() ); } - searchList = searchList + QLatin1String(" ") + domainName; + searchList += QLatin1Char(' ') + domainName; searchList = searchList.simplifyWhiteSpace().lower(); first = 0; do { @@ -2488,7 +2488,7 @@ void Q3Dns::doResInit() while ( !stream.atEnd() ) { line = stream.readLine(); QStringList list = QStringList::split( QLatin1String(" "), line ); - if( line.startsWith( QLatin1String("#") ) || list.size() < 2 ) + if( line.startsWith( QLatin1Char('#') ) || list.size() < 2 ) continue; const QString type = list[0].lower(); diff --git a/src/qt3support/network/q3ftp.cpp b/src/qt3support/network/q3ftp.cpp index 5ab84cc..44c1f5c 100644 --- a/src/qt3support/network/q3ftp.cpp +++ b/src/qt3support/network/q3ftp.cpp @@ -485,7 +485,7 @@ bool Q3FtpDTP::parseDir( const QString &buffer, const QString &userName, QUrlInf dateStr += lst[ 6 ]; dateStr += QLatin1Char(' '); - if ( lst[ 7 ].contains( QLatin1String(":") ) ) { + if ( lst[ 7 ].contains( QLatin1Char(':') ) ) { time = QTime( lst[ 7 ].left( 2 ).toInt(), lst[ 7 ].right( 2 ).toInt() ); dateStr += QString::number( QDate::currentDate().year() ); } else { @@ -495,7 +495,7 @@ bool Q3FtpDTP::parseDir( const QString &buffer, const QString &userName, QUrlInf QDate date = QDate::fromString( dateStr ); info->setLastModified( QDateTime( date, time ) ); - if ( lst[ 7 ].contains( QLatin1String(":") ) ) { + if ( lst[ 7 ].contains( QLatin1Char(':') ) ) { const int futureTolerance = 600; if( info->lastModified().secsTo( QDateTime::currentDateTime() ) < -futureTolerance ) { QDateTime dt = info->lastModified(); @@ -512,7 +512,7 @@ bool Q3FtpDTP::parseDir( const QString &buffer, const QString &userName, QUrlInf else { QString n; for ( uint i = 8; i < (uint) lst.count(); ++i ) - n += lst[ i ] + QLatin1String(" "); + n += lst[ i ] + QLatin1Char(' '); n = n.stripWhiteSpace(); info->setName( n ); } @@ -897,7 +897,7 @@ bool Q3FtpPI::processReply() // ### error handling } else { QStringList lst = addrPortPattern.capturedTexts(); - QString host = lst[1] + QLatin1String(".") + lst[2] + QLatin1String(".") + lst[3] + QLatin1String(".") + lst[4]; + QString host = lst[1] + QLatin1Char('.') + lst[2] + QLatin1Char('.') + lst[3] + QLatin1Char('.') + lst[4]; Q_UINT16 port = ( lst[5].toUInt() << 8 ) + lst[6].toUInt(); waitForDtpToConnect = true; dtp.connectToHost( host, port ); @@ -1435,8 +1435,8 @@ int Q3Ftp::connectToHost( const QString &host, Q_UINT16 port ) int Q3Ftp::login( const QString &user, const QString &password ) { QStringList cmds; - cmds << ( QString(QLatin1String("USER ")) + ( user.isNull() ? QString(QLatin1String("anonymous")) : user ) + QLatin1String("\r\n") ); - cmds << ( QString(QLatin1String("PASS ")) + ( password.isNull() ? QString(QLatin1String("anonymous@")) : password ) + QLatin1String("\r\n") ); + cmds << ( QString::fromLatin1("USER ") + ( user.isNull() ? QString::fromLatin1("anonymous") : user ) + QLatin1String("\r\n") ); + cmds << ( QString::fromLatin1("PASS ") + ( password.isNull() ? QString::fromLatin1("anonymous@") : password ) + QLatin1String("\r\n") ); return addCommand( new Q3FtpCommand( Login, cmds ) ); } @@ -2095,7 +2095,7 @@ void Q3Ftp::operationListChildren( Q3NetworkOperation *op ) { op->setState( StInProgress ); - cd( ( url()->path().isEmpty() ? QString( QLatin1String("/") ) : url()->path() ) ); + cd( ( url()->path().isEmpty() ? QString::fromLatin1("/") : url()->path() ) ); list(); emit start( op ); } @@ -2115,7 +2115,7 @@ void Q3Ftp::operationRemove( Q3NetworkOperation *op ) { op->setState( StInProgress ); - cd( ( url()->path().isEmpty() ? QString( QLatin1String("/") ) : url()->path() ) ); + cd( ( url()->path().isEmpty() ? QString::fromLatin1("/") : url()->path() ) ); remove( Q3Url( op->arg( 0 ) ).path() ); } @@ -2125,7 +2125,7 @@ void Q3Ftp::operationRename( Q3NetworkOperation *op ) { op->setState( StInProgress ); - cd( ( url()->path().isEmpty() ? QString( QLatin1String("/") ) : url()->path() ) ); + cd( ( url()->path().isEmpty() ? QString::fromLatin1("/") : url()->path() ) ); rename( op->arg( 0 ), op->arg( 1 )); } @@ -2179,8 +2179,8 @@ bool Q3Ftp::checkConnection( Q3NetworkOperation *op ) connectToHost( url()->host(), url()->port() != -1 ? url()->port() : 21 ); break; } - QString user = url()->user().isEmpty() ? QString( QLatin1String("anonymous") ) : url()->user(); - QString pass = url()->password().isEmpty() ? QString( QLatin1String("anonymous@") ) : url()->password(); + QString user = url()->user().isEmpty() ? QString::fromLatin1("anonymous") : url()->user(); + QString pass = url()->password().isEmpty() ? QString::fromLatin1("anonymous@") : url()->password(); login( user, pass ); } diff --git a/src/qt3support/network/q3http.cpp b/src/qt3support/network/q3http.cpp index f1590a6..aabf4a3 100644 --- a/src/qt3support/network/q3http.cpp +++ b/src/qt3support/network/q3http.cpp @@ -468,7 +468,7 @@ bool Q3HttpHeader::parse( const QString& str ) if ( !(*it).isEmpty() ) { if ( (*it)[0].isSpace() ) { if ( !lines.isEmpty() ) { - lines.last() += QLatin1String(" "); + lines.last() += QLatin1Char(' '); lines.last() += (*it).stripWhiteSpace(); } } else { @@ -562,7 +562,7 @@ void Q3HttpHeader::removeValue( const QString& key ) */ bool Q3HttpHeader::parseLine( const QString& line, int ) { - int i = line.find( QLatin1String(":") ); + int i = line.find( QLatin1Char(':') ); if ( i == -1 ) return false; @@ -626,7 +626,7 @@ void Q3HttpHeader::setContentLength( int len ) } /*! - Returns true if the header has an entry for the the special HTTP + Returns true if the header has an entry for the special HTTP header field \c content-type; otherwise returns false. \sa contentType() setContentType() @@ -647,7 +647,7 @@ QString Q3HttpHeader::contentType() const if ( type.isEmpty() ) return QString(); - int pos = type.find( QLatin1String(";") ); + int pos = type.find( QLatin1Char(';') ); if ( pos == -1 ) return type; @@ -2210,7 +2210,7 @@ void Q3Http::clientReply( const Q3HttpResponseHeader &rep ) if ( rep.statusCode() >= 400 && rep.statusCode() < 600 ) { op->setState( StFailed ); op->setProtocolDetail( - QString(QLatin1String("%1 %2")).arg(rep.statusCode()).arg(rep.reasonPhrase()) + QString::fromLatin1("%1 %2").arg(rep.statusCode()).arg(rep.reasonPhrase()) ); switch ( rep.statusCode() ) { case 401: diff --git a/src/qt3support/network/q3url.cpp b/src/qt3support/network/q3url.cpp index fc2fdb2..68753b6 100644 --- a/src/qt3support/network/q3url.cpp +++ b/src/qt3support/network/q3url.cpp @@ -211,8 +211,8 @@ Q3Url::Q3Url( const Q3Url& url ) bool Q3Url::isRelativeUrl( const QString &url ) { - int colon = url.find( QLatin1String(":") ); - int slash = url.find( QLatin1String("/") ); + int colon = url.find( QLatin1Char(':') ); + int slash = url.find( QLatin1Char('/') ); return ( slash != 0 && ( colon == -1 || ( slash != -1 && colon > slash ) ) ); } @@ -280,8 +280,8 @@ Q3Url::Q3Url( const Q3Url& url, const QString& relUrl, bool checkSlash ) if ( !d->host.isEmpty() && !d->user.isEmpty() && !d->pass.isEmpty() ) p = QLatin1String("/"); } - if ( !p.isEmpty() && p.right(1)!=QLatin1String("/") ) - p += QLatin1String("/"); + if ( !p.isEmpty() && !p.endsWith(QLatin1Char('/')) ) + p += QLatin1Char('/'); p += rel; d->path = p; d->cleanPathDirty = true; @@ -678,7 +678,7 @@ bool Q3Url::parse( const QString& url ) ++cs; while ( url_[ cs ] == QLatin1Char('/') ) ++cs; - int slash = url_.find( QLatin1String("/"), cs ); + int slash = url_.find( QLatin1Char('/'), cs ); if ( slash == -1 ) slash = url_.length() - 1; QString tmp = url_.mid( cs, slash - cs + 1 ); @@ -686,7 +686,7 @@ bool Q3Url::parse( const QString& url ) if ( !tmp.isEmpty() ) { // if this part exists // look for the @ in this part - int at = tmp.find( QLatin1String("@") ); + int at = tmp.find( QLatin1Char('@') ); if ( at != -1 ) at += cs; // we have no @, which means host[:port], so directly @@ -793,7 +793,7 @@ bool Q3Url::parse( const QString& url ) // hack for windows if ( d->path.length() == 2 && d->path[ 1 ] == QLatin1Char(':') ) - d->path += QLatin1String("/"); + d->path += QLatin1Char('/'); // #### do some corrections, should be done nicer too if ( !d->pass.isEmpty() ) { @@ -808,7 +808,7 @@ bool Q3Url::parse( const QString& url ) if ( d->path[ 0 ] == QLatin1Char('@') || d->path[ 0 ] == QLatin1Char(':') ) d->path.remove( (uint)0, 1 ); if ( d->path[ 0 ] != QLatin1Char('/') && !relPath && d->path[ 1 ] != QLatin1Char(':') ) - d->path.prepend( QLatin1String("/") ); + d->path.prepend( QLatin1Char('/') ); } if ( !d->refEncoded.isEmpty() && d->refEncoded[ 0 ] == QLatin1Char('#') ) d->refEncoded.remove( (uint)0, 1 ); @@ -820,9 +820,9 @@ bool Q3Url::parse( const QString& url ) #if defined(Q_OS_WIN32) // hack for windows file://machine/path syntax if ( d->protocol == QLatin1String("file") ) { - if ( url.left( 7 ) == QLatin1String("file://") && + if ( url.startsWith(QLatin1String("file://")) && d->path.length() > 1 && d->path[ 1 ] != QLatin1Char(':') ) - d->path.prepend( QLatin1String("/") ); + d->path.prepend( QLatin1Char('/') ); } #endif @@ -942,7 +942,7 @@ void Q3Url::setFileName( const QString& name ) p += fn; if ( !d->queryEncoded.isEmpty() ) - p += QLatin1String("?") + d->queryEncoded; + p += QLatin1Char('?') + d->queryEncoded; setEncodedPathAndQuery( p ); } @@ -961,7 +961,7 @@ QString Q3Url::encodedPathAndQuery() encode( p ); if ( !d->queryEncoded.isEmpty() ) { - p += QLatin1String("?"); + p += QLatin1Char('?'); p += d->queryEncoded; } @@ -1011,7 +1011,7 @@ QString Q3Url::path( bool correct ) const } else if ( isLocalFile() ) { #if defined(Q_OS_WIN32) // hack for stuff like \\machine\path and //machine/path on windows - if ( ( d->path.left( 1 ) == QLatin1String("/") || d->path.left( 1 ) == QLatin1String("\\") ) && + if ( ( d->path.startsWith(QLatin1Char('/')) || d->path.startsWith(QLatin1Char('\\')) ) && d->path.length() > 1 ) { d->cleanPath = d->path; bool share = (d->cleanPath[0] == QLatin1Char('\\') && d->cleanPath[1] == QLatin1Char('\\')) || @@ -1021,7 +1021,7 @@ QString Q3Url::path( bool correct ) const if ( share ) { check = false; while (d->cleanPath.at(0) != QLatin1Char('/') || d->cleanPath.at(1) != QLatin1Char('/')) - d->cleanPath.prepend(QLatin1String("/")); + d->cleanPath.prepend(QLatin1Char('/')); } } #endif @@ -1036,7 +1036,7 @@ QString Q3Url::path( bool correct ) const dir = QDir::cleanDirPath( canPath ); else dir = QDir::cleanDirPath( QDir( d->path ).absPath() ); - dir += QLatin1String("/"); + dir += QLatin1Char('/'); if ( dir == QLatin1String("//") ) d->cleanPath = QLatin1String("/"); else @@ -1046,14 +1046,13 @@ QString Q3Url::path( bool correct ) const QDir::cleanDirPath( (qt_resolve_symlinks ? fi.dir().canonicalPath() : fi.dir().absPath()) ); - d->cleanPath = p + QLatin1String("/") + fi.fileName(); + d->cleanPath = p + QLatin1Char('/') + fi.fileName(); } } } else { - if ( d->path != QLatin1String("/") && d->path[ (int)d->path.length() - 1 ] == QLatin1Char('/') ) - d->cleanPath = QDir::cleanDirPath( d->path ) + QLatin1String("/"); - else d->cleanPath = QDir::cleanDirPath( d->path ); + if ( d->path.length() > 1 && d->path.endsWith(QLatin1Char('/')) ) + d->cleanPath += QLatin1Char('/'); } if ( check ) @@ -1084,9 +1083,9 @@ bool Q3Url::isLocalFile() const QString Q3Url::fileName() const { - if ( d->path.isEmpty() || d->path.endsWith( QLatin1String("/") ) + if ( d->path.isEmpty() || d->path.endsWith( QLatin1Char('/') ) #ifdef Q_WS_WIN - || d->path.endsWith( QLatin1String("\\") ) + || d->path.endsWith( QLatin1Char('\\') ) #endif ) return QString(); @@ -1110,12 +1109,12 @@ void Q3Url::addPath( const QString& pa ) if ( path().isEmpty() ) { if ( p[ 0 ] != QLatin1Char( '/' ) ) - d->path = QLatin1String("/") + p; + d->path = QLatin1Char('/') + p; else d->path = p; } else { if ( p[ 0 ] != QLatin1Char( '/' ) && d->path[ (int)d->path.length() - 1 ] != QLatin1Char('/') ) - d->path += QLatin1String("/") + p; + d->path += QLatin1Char('/') + p; else d->path += p; } @@ -1250,11 +1249,11 @@ QString Q3Url::toString( bool encodedPath, bool forcePrependProtocol ) const if ( isLocalFile() ) { if ( forcePrependProtocol ) - res = d->protocol + QLatin1String(":") + p; + res = d->protocol + QLatin1Char(':') + p; else res = p; } else if ( d->protocol == QLatin1String("mailto") ) { - res = d->protocol + QLatin1String(":") + p; + res = d->protocol + QLatin1Char(':') + p; } else { res = d->protocol + QLatin1String("://"); if ( !d->user.isEmpty() || !d->pass.isEmpty() ) { @@ -1267,24 +1266,24 @@ QString Q3Url::toString( bool encodedPath, bool forcePrependProtocol ) const if ( !d->pass.isEmpty() ) { tmp = d->pass; encode( tmp ); - res += QLatin1String(":") + tmp; + res += QLatin1Char(':') + tmp; } - res += QLatin1String("@"); + res += QLatin1Char('@'); } res += d->host; if ( d->port != -1 ) - res += QLatin1String(":") + QString( QLatin1String("%1") ).arg( d->port ); + res += QLatin1Char(':') + QString::number( d->port ); if ( !p.isEmpty() ) { if ( !d->host.isEmpty() && p[0]!= QLatin1Char( '/' ) ) - res += QLatin1String("/"); + res += QLatin1Char('/'); res += p; } } if ( !d->refEncoded.isEmpty() ) - res += QLatin1String("#") + d->refEncoded; + res += QLatin1Char('#') + d->refEncoded; if ( !d->queryEncoded.isEmpty() ) - res += QLatin1String("?") + d->queryEncoded; + res += QLatin1Char('?') + d->queryEncoded; return res; } diff --git a/src/qt3support/network/q3urloperator.cpp b/src/qt3support/network/q3urloperator.cpp index 3f334a8..6afd8ab 100644 --- a/src/qt3support/network/q3urloperator.cpp +++ b/src/qt3support/network/q3urloperator.cpp @@ -543,7 +543,7 @@ const Q3NetworkOperation *Q3UrlOperator::rename( const QString &oldname, const Q in mind that the get() and put() operations emit this signal through the Q3UrlOperator. The number of transferred bytes and the total bytes that you receive as arguments in this signal do not - relate to the the whole copy operation; they relate first to the + relate to the whole copy operation; they relate first to the get() and then to the put() operation. Always check what type of operation the signal comes from; this is given in the signal's last argument. @@ -579,7 +579,7 @@ Q3PtrList<Q3NetworkOperation> Q3UrlOperator::copy( const QString &from, const QS if (frm == to + file) return ops; - file.prepend( QLatin1String("/") ); + file.prepend( QLatin1Char('/') ); // uFrom and uTo are deleted when the Q3NetworkProtocol deletes itself via // autodelete diff --git a/src/qt3support/other/q3dragobject.cpp b/src/qt3support/other/q3dragobject.cpp index fb57220..89ffe24 100644 --- a/src/qt3support/other/q3dragobject.cpp +++ b/src/qt3support/other/q3dragobject.cpp @@ -93,7 +93,7 @@ public: Q3TextDragPrivate() { setSubType(QLatin1String("plain")); } void setSubType(const QString & st) { subtype = st; - fmt = QString(QLatin1String("text/")).toLatin1() + subtype.toLatin1(); + fmt = "text/" + subtype.toLatin1(); } QString txt; @@ -208,11 +208,6 @@ void Q3DragObject::setPixmap(QPixmap pm, const QPoint& hotspot) Q_D(Q3DragObject); d->pixmap = pm; d->hot = hotspot; -#if 0 - QDragManager *manager = QDragManager::self(); - if (manager && manager->object == d->data) - manager->updatePixmap(); -#endif } /*! @@ -1302,7 +1297,7 @@ QByteArray Q3UriDrag::localFileToUri(const QString& filename) r.prepend(QString::fromLatin1(hostname)); } #endif - return unicodeUriToUri(QString(QLatin1String("file://") + r)); + return unicodeUriToUri(QLatin1String("file://") + r); } /*! @@ -1357,7 +1352,7 @@ QString Q3UriDrag::uriToLocalFile(const char* uri) return file; if (0==qstrnicmp(uri,"file:/",6)) // It is a local file uri uri += 6; - else if (QString(QLatin1String(uri)).indexOf(QLatin1String(":/")) != -1) // It is a different scheme uri + else if (QString::fromLatin1(uri).indexOf(QLatin1String(":/")) != -1) // It is a different scheme uri return file; bool local = uri[0] != '/' || (uri[0] != '\0' && uri[1] == '/'); diff --git a/src/qt3support/other/q3process.cpp b/src/qt3support/other/q3process.cpp index 6eac812..9689de9 100644 --- a/src/qt3support/other/q3process.cpp +++ b/src/qt3support/other/q3process.cpp @@ -483,7 +483,7 @@ QString Q3Process::readLineStdout() return QString(); if ( !buf->scanNewline( &a ) ) - return QString( QLatin1String(buf->readAll()) ); + return QLatin1String(buf->readAll()); } uint size = a.size(); diff --git a/src/qt3support/other/q3process_unix.cpp b/src/qt3support/other/q3process_unix.cpp index 098c581..2492bf2 100644 --- a/src/qt3support/other/q3process_unix.cpp +++ b/src/qt3support/other/q3process_unix.cpp @@ -828,7 +828,7 @@ bool Q3Process::start( QStringList *env ) #ifndef QT_NO_DIR QFileInfo fileInfo( dir, command ); #else - QFileInfo fileInfo( dir + "/" + command ); + QFileInfo fileInfo( dir + QLatin1Char('/') + command ); #endif if ( fileInfo.isExecutable() ) { #if defined(Q_OS_MACX) diff --git a/src/qt3support/other/q3process_win.cpp b/src/qt3support/other/q3process_win.cpp index 3c862ee..7dc28cb 100644 --- a/src/qt3support/other/q3process_win.cpp +++ b/src/qt3support/other/q3process_win.cpp @@ -285,7 +285,7 @@ bool Q3Process::start( QStringList *env ) for ( ; it != _arguments.end(); ++it ) { QString tmp = *it; // escape a single " because the arguments will be parsed - tmp.replace( QLatin1String("\""), QLatin1String("\\\"") ); + tmp.replace( QLatin1Char('\"'), QLatin1String("\\\"") ); if ( tmp.isEmpty() || tmp.contains( QLatin1Char(' ') ) || tmp.contains( QLatin1Char('\t') ) ) { // The argument must not end with a \ since this would be interpreted // as escaping the quote -- rather put the \ behind the quote: e.g. @@ -294,9 +294,9 @@ bool Q3Process::start( QStringList *env ) int i = tmp.length(); while ( i>0 && tmp.at( i-1 ) == QLatin1Char('\\') ) { --i; - endQuote += QLatin1String("\\"); + endQuote += QLatin1Char('\\'); } - args += QString( QLatin1String(" \"") ) + tmp.left( i ) + endQuote; + args += QLatin1String(" \"") + tmp.left( i ) + endQuote; } else { args += QLatin1Char(' ') + tmp; } @@ -330,7 +330,7 @@ bool Q3Process::start( QStringList *env ) // add PATH if necessary (for DLL loading) QByteArray path = qgetenv( "PATH" ); if ( env->grep( QRegExp(QLatin1String("^PATH="),FALSE) ).empty() && !path.isNull() ) { - QString tmp = QString( QLatin1String("PATH=%1") ).arg(QString::fromLatin1(path.constData())); + QString tmp = QString::fromLatin1("PATH=%1").arg(QLatin1String(path.constData())); uint tmpSize = sizeof(TCHAR) * (tmp.length()+1); envlist.resize( envlist.size() + tmpSize ); memcpy( envlist.data()+pos, tmp.ucs2(), tmpSize ); @@ -378,7 +378,7 @@ bool Q3Process::start( QStringList *env ) // add PATH if necessary (for DLL loading) QByteArray path = qgetenv( "PATH" ); if ( env->grep( QRegExp(QLatin1String("^PATH="),FALSE) ).empty() && !path.isNull() ) { - Q3CString tmp = QString( QLatin1String("PATH=%1") ).arg(QString::fromLatin1(path.constData())).local8Bit(); + Q3CString tmp = QString::fromLatin1("PATH=%1").arg(QString::fromLatin1(path.constData())).local8Bit(); uint tmpSize = tmp.length() + 1; envlist.resize( envlist.size() + tmpSize ); memcpy( envlist.data()+pos, tmp.data(), tmpSize ); diff --git a/src/qt3support/painting/q3paintengine_svg.cpp b/src/qt3support/painting/q3paintengine_svg.cpp index 95528e8..22e0d49 100644 --- a/src/qt3support/painting/q3paintengine_svg.cpp +++ b/src/qt3support/painting/q3paintengine_svg.cpp @@ -263,7 +263,7 @@ void Q3SVGPaintEngine::updateClipPath(const QPainterPath &path, Qt::ClipOperatio QDomElement e; d->currentClip++; e = d->doc.createElement(QLatin1String("clipPath")); - e.setAttribute(QLatin1String("id"), QString(QLatin1String("clip%1")).arg(d->currentClip)); + e.setAttribute(QLatin1String("id"), QString::fromLatin1("clip%1").arg(d->currentClip)); QDomElement path_element = d->doc.createElement(QLatin1String("path")); path_element.setAttribute(QLatin1String("d"), qt_svg_compose_path(path)); @@ -509,14 +509,14 @@ bool Q3SVGPaintEngine::save(const QString &fileName) int icount = 0; ImageList::Iterator iit = d->images.begin(); for (; iit != d->images.end(); ++iit) { - QString href = QString(QLatin1String("%1_%2.png")).arg(svgName).arg(icount); + QString href = QString::fromLatin1("%1_%2.png").arg(svgName).arg(icount); (*iit).image.save(href, "PNG"); (*iit).element.setAttribute(QLatin1String("xlink:href"), href); icount++; } PixmapList::Iterator pit = d->pixmaps.begin(); for (; pit != d->pixmaps.end(); ++pit) { - QString href = QString(QLatin1String("%1_%2.png")).arg(svgName).arg(icount); + QString href = QString::fromLatin1("%1_%2.png").arg(svgName).arg(icount); (*pit).pixmap.save(href, "PNG"); (*pit).element.setAttribute(QLatin1String("xlink:href"), href); icount++; @@ -592,7 +592,7 @@ void Q3SVGPaintEnginePrivate::appendChild(QDomElement &e, QPicturePrivate::Paint if (c == QPicturePrivate::PdcSetClipRegion || c == QPicturePrivate::PdcSetClipPath) { QDomElement ne; ne = doc.createElement(QLatin1String("g")); - ne.setAttribute(QLatin1String("style"), QString(QLatin1String("clip-path:url(#clip%1)")).arg(currentClip)); + ne.setAttribute(QLatin1String("style"), QString::fromLatin1("clip-path:url(#clip%1)").arg(currentClip)); if (dirtyTransform) { applyTransform(&ne); dirtyTransform = false; @@ -621,12 +621,12 @@ void Q3SVGPaintEnginePrivate::applyStyle(QDomElement *e, QPicturePrivate::PaintC if (c == QPicturePrivate::PdcDrawText2 || c == QPicturePrivate::PdcDrawText2Formatted) { // QPainter has a reversed understanding of pen/stroke vs. // brush/fill for text - s += QString(QLatin1String("fill:rgb(%1,%2,%3);")).arg(pcol.red()).arg(pcol.green()).arg(pcol.blue()); - s += QString(QLatin1String("stroke-width:0;")); + s += QString::fromLatin1("fill:rgb(%1,%2,%3);").arg(pcol.red()).arg(pcol.green()).arg(pcol.blue()); + s += QLatin1String("stroke-width:0;"); QFont f = cfont; QFontInfo fi(f); - s += QString(QLatin1String("font-size:%1;")).arg(fi.pointSize()); - s += QString(QLatin1String("font-style:%1;")).arg(f.italic() ? QLatin1String("italic") : QLatin1String("normal")); + s += QString::fromLatin1("font-size:%1;").arg(fi.pointSize()); + s += QString::fromLatin1("font-style:%1;").arg(f.italic() ? QLatin1String("italic") : QLatin1String("normal")); // not a very scientific distribution QString fw; if (f.weight() <= QFont::Light) @@ -641,32 +641,32 @@ void Q3SVGPaintEnginePrivate::applyStyle(QDomElement *e, QPicturePrivate::PaintC fw = QLatin1String("800"); else fw = QLatin1String("900"); - s += QString(QLatin1String("font-weight:%1;")).arg(fw); - s += QString(QLatin1String("font-family:%1;")).arg(f.family()); + s += QString::fromLatin1("font-weight:%1;").arg(fw); + s += QString::fromLatin1("font-family:%1;").arg(f.family()); } else { - s += QString(QLatin1String("stroke:rgb(%1,%2,%3);")).arg(pcol.red()).arg(pcol.green()).arg(pcol.blue()); + s += QString::fromLatin1("stroke:rgb(%1,%2,%3);").arg(pcol.red()).arg(pcol.green()).arg(pcol.blue()); if (pcol.alpha() != 255) - s += QString(QLatin1String("stroke-opacity:%1;")).arg(pcol.alpha()/255.0); + s += QString::fromLatin1("stroke-opacity:%1;").arg(pcol.alpha()/255.0); if (bcol.alpha() != 255) - s += QString(QLatin1String("fill-opacity:%1;")).arg(bcol.alpha()/255.0); + s += QString::fromLatin1("fill-opacity:%1;").arg(bcol.alpha()/255.0); double pw = cpen.width(); if (pw == 0 && cpen.style() != Qt::NoPen) pw = 0.9; if (c == QPicturePrivate::PdcDrawLine) pw /= (qAbs(worldMatrix.m11()) + qAbs(worldMatrix.m22())) / 2.0; - s += QString(QLatin1String("stroke-width:%1;")).arg(pw); + s += QString::fromLatin1("stroke-width:%1;").arg(pw); if (cpen.style() == Qt::DashLine) - s+= QString(QLatin1String("stroke-dasharray:18,6;")); + s+= QLatin1String("stroke-dasharray:18,6;"); else if (cpen.style() == Qt::DotLine) - s+= QString(QLatin1String("stroke-dasharray:3;")); + s+= QLatin1String("stroke-dasharray:3;"); else if (cpen.style() == Qt::DashDotLine) - s+= QString(QLatin1String("stroke-dasharray:9,6,3,6;")); + s+= QLatin1String("stroke-dasharray:9,6,3,6;"); else if (cpen.style() == Qt::DashDotDotLine) - s+= QString(QLatin1String("stroke-dasharray:9,3,3;")); + s+= QLatin1String("stroke-dasharray:9,3,3;"); if (cbrush.style() == Qt::NoBrush || c == QPicturePrivate::PdcDrawPolyline || c == QPicturePrivate::PdcDrawCubicBezier) s += QLatin1String("fill:none;"); // Qt polylines use no brush, neither do Beziers else - s += QString(QLatin1String("fill:rgb(%1,%2,%3);")).arg(bcol.red()).arg(bcol.green()).arg(bcol.blue()); + s += QString::fromLatin1("fill:rgb(%1,%2,%3);").arg(bcol.red()).arg(bcol.green()).arg(bcol.blue()); } e->setAttribute(QLatin1String("style"), s); } @@ -679,13 +679,13 @@ void Q3SVGPaintEnginePrivate::applyTransform(QDomElement *e) const bool rot = (m.m11() != 1.0 || m.m12() != 0.0 || m.m21() != 0.0 || m.m22() != 1.0); if (!rot && (m.dx() != 0.0 || m.dy() != 0.0)) { - s = QString(QLatin1String("translate(%1,%2)")).arg(m.dx()).arg(m.dy()); + s = QString::fromLatin1("translate(%1,%2)").arg(m.dx()).arg(m.dy()); } else if (rot) { if (m.m12() == 0.0 && m.m21() == 0.0 && m.dx() == 0.0 && m.dy() == 0.0) - s = QString(QLatin1String("scale(%1,%2)")).arg(m.m11()).arg(m.m22()); + s = QString::fromLatin1("scale(%1,%2)").arg(m.m11()).arg(m.m22()); else - s = QString(QLatin1String("matrix(%1,%2,%3,%4,%5,%6)")) + s = QString::fromLatin1("matrix(%1,%2,%3,%4,%5,%6)") .arg(m.m11()).arg(m.m12()) .arg(m.m21()).arg(m.m22()) .arg(m.dx()).arg(m.dy()); @@ -730,9 +730,9 @@ bool Q3SVGPaintEngine::play(QPainter *pt) d->brect.setX(x); d->brect.setY(y); QString wstr = attr.contains(QLatin1String("width")) - ? attr.namedItem(QLatin1String("width")).nodeValue() : QString(QLatin1String("100%")); + ? attr.namedItem(QLatin1String("width")).nodeValue() : QString::fromLatin1("100%"); QString hstr = attr.contains(QLatin1String("height")) - ? attr.namedItem(QLatin1String("height")).nodeValue() : QString(QLatin1String("100%")); + ? attr.namedItem(QLatin1String("height")).nodeValue() : QString::fromLatin1("100%"); double width = d->parseLen(wstr, 0, true); double height = d->parseLen(hstr, 0, false); // SVG doesn't respect x and y. But we want a proper bounding rect. diff --git a/src/qt3support/text/q3richtext.cpp b/src/qt3support/text/q3richtext.cpp index e508001..d02f961 100644 --- a/src/qt3support/text/q3richtext.cpp +++ b/src/qt3support/text/q3richtext.cpp @@ -1678,7 +1678,7 @@ void Q3TextDocument::setRichTextInternal(const QString &text, Q3TextCursor* curs if (curtag.style->displayMode() == Q3StyleSheetItem::DisplayListItem) { // we are in a li and a new block comes along - if (nstyle->name() == QString(QLatin1String("ul")) || nstyle->name() == QLatin1String("ol")) + if (nstyle->name() == QLatin1String("ul") || nstyle->name() == QLatin1String("ol")) hasNewPar = false; // we want an empty li (like most browsers) if (!hasNewPar) { /* do not add new blocks inside @@ -1857,7 +1857,7 @@ void Q3TextDocument::setRichTextInternal(const QString &text, Q3TextCursor* curs curtag.format = curtag.format.makeTextFormat(nstyle, attr, scaleFontsFactor); if (nstyle->isAnchor()) { if (!anchorName.isEmpty()) - anchorName += QLatin1String("#") + attr[QLatin1String("name")]; + anchorName += QLatin1Char('#') + attr[QLatin1String("name")]; else anchorName = attr[QLatin1String("name")]; curtag.anchorHref = attr[QLatin1String("href")]; @@ -2436,7 +2436,7 @@ QString Q3TextDocument::richText() const list_type = QLatin1String(" type=") + list_style_to_string(p->listStyle()); for (int i = pastListDepth; i < listDepth; i++) { s += list_is_ordered(p->listStyle()) ? QLatin1String("<ol") : QLatin1String("<ul"); - s += list_type + QLatin1String(">"); + s += list_type + QLatin1Char('>'); } } else { s += QLatin1Char('\n'); @@ -2463,7 +2463,7 @@ QString Q3TextDocument::richText() const s += margin_to_string(item_li, p->utm, p->ubm, p->ulm, p->urm, p->uflm); s += list_value_to_string(p->listValue()); s += direction_to_string(p->direction()); - s += QLatin1String(">"); + s += QLatin1Char('>'); s += ps; s += QLatin1String("</li>"); } else if (p->listDepth()) { @@ -2471,7 +2471,7 @@ QString Q3TextDocument::richText() const s += align_to_string(p->alignment()); s += margin_to_string(item_div, p->utm, p->ubm, p->ulm, p->urm, p->uflm); s += direction_to_string(p->direction()); - s += QLatin1String(">"); + s += QLatin1Char('>'); s += ps; s += QLatin1String("</div>"); } else { @@ -2480,7 +2480,7 @@ QString Q3TextDocument::richText() const s += align_to_string(p->alignment()); s += margin_to_string(item_p, p->utm, p->ubm, p->ulm, p->urm, p->uflm); s += direction_to_string(p->direction()); - s += QLatin1String(">"); + s += QLatin1Char('>'); s += ps; s += QLatin1String("</p>"); } @@ -6667,7 +6667,7 @@ Q3TextImage::Q3TextImage(Q3TextDocument *p, const QMap<QString, QString> &attr, imageName = attr[QLatin1String("source")]; if (!imageName.isEmpty()) { - imgId = QString(QLatin1String("%1,%2,%3,%4")).arg(imageName).arg(width).arg(height).arg((ulong)&factory); + imgId = QString::fromLatin1("%1,%2,%3,%4").arg(imageName).arg(width).arg(height).arg((ulong)&factory); if (!pixmap_map) pixmap_map = new QMap<QString, QPixmapInt>; if (pixmap_map->contains(imgId)) { @@ -6761,13 +6761,13 @@ QString Q3TextImage::richText() const s += QLatin1String("<img "); QMap<QString, QString>::ConstIterator it = attributes.begin(); for (; it != attributes.end(); ++it) { - s += it.key() + QLatin1String("="); + s += it.key() + QLatin1Char('='); if ((*it).contains(QLatin1Char(' '))) - s += QLatin1String("\"") + *it + QLatin1String("\" "); + s += QLatin1Char('\"') + *it + QLatin1String("\" "); else - s += *it + QLatin1String(" "); + s += *it + QLatin1Char(' '); } - s += QLatin1String(">"); + s += QLatin1Char('>'); return s; } @@ -7722,7 +7722,7 @@ QString Q3TextTable::richText() const s = QLatin1String("<table "); QMap<QString, QString>::ConstIterator it = attributes.begin(); for (; it != attributes.end(); ++it) - s += it.key() + QLatin1String("=") + *it + QLatin1String(" "); + s += it.key() + QLatin1Char('=') + *it + QLatin1Char(' '); s += QLatin1String(">\n"); int lastRow = -1; @@ -7739,8 +7739,8 @@ QString Q3TextTable::richText() const s += QLatin1String("<td"); it = cell->attributes.constBegin(); for (; it != cell->attributes.constEnd(); ++it) - s += QLatin1String(" ") + it.key() + QLatin1String("=") + *it; - s += QLatin1String(">"); + s += QLatin1Char(' ') + it.key() + QLatin1Char('=') + *it; + s += QLatin1Char('>'); s += cell->richText()->richText(); s += QLatin1String("</td>"); } diff --git a/src/qt3support/text/q3textedit.cpp b/src/qt3support/text/q3textedit.cpp index 7577dce..d1db1e4 100644 --- a/src/qt3support/text/q3textedit.cpp +++ b/src/qt3support/text/q3textedit.cpp @@ -77,7 +77,7 @@ #include <qkeysequence.h> #define ACCEL_KEY(k) QLatin1Char('\t') + QString(QKeySequence(Qt::CTRL | Qt::Key_ ## k)) #else -#define ACCEL_KEY(k) QLatin1Char('\t' )+ QString(QLatin1String("Ctrl+" #k)) +#define ACCEL_KEY(k) QLatin1Char('\t' )+ QString::fromLatin1("Ctrl+" #k) #endif #ifdef QT_TEXTEDIT_OPTIMIZATION @@ -6625,7 +6625,7 @@ void Q3TextEdit::optimSetTextFormat(Q3TextDocument * td, Q3TextCursor * cur, } if (tag) { QString col = tag->tag.simplified(); - if (col.left(10) == QLatin1String("font color")) { + if (col.startsWith(QLatin1String("font color"))) { int i = col.indexOf(QLatin1Char('='), 10); col = col.mid(i + 1).simplified(); if (col[0] == QLatin1Char('\"')) diff --git a/src/qt3support/widgets/q3action.cpp b/src/qt3support/widgets/q3action.cpp index 4e1a1bf..311212a 100644 --- a/src/qt3support/widgets/q3action.cpp +++ b/src/qt3support/widgets/q3action.cpp @@ -497,7 +497,7 @@ Q3Action::Q3Action(const QIcon& icon, const QString& menuText, QKeySequence acce } /*! - This constructor results in an icon-less action with the the menu + This constructor results in an icon-less action with the menu text \a menuText and keyboard accelerator \a accel. It is a child of \a parent and called \a name. diff --git a/src/qt3support/widgets/q3groupbox.cpp b/src/qt3support/widgets/q3groupbox.cpp index 1fa7e7c..e0b609a 100644 --- a/src/qt3support/widgets/q3groupbox.cpp +++ b/src/qt3support/widgets/q3groupbox.cpp @@ -382,7 +382,7 @@ int Q3GroupBox::insideSpacing() const } /*! - Sets the the width of the inside margin to \a m pixels. + Sets the width of the inside margin to \a m pixels. \sa insideMargin() */ @@ -954,7 +954,7 @@ int Q3GroupBox::frameWidth() const \fn int Q3GroupBox::margin() const \since 4.2 - Returns the width of the the margin around the contents of the widget. + Returns the width of the margin around the contents of the widget. This function uses QWidget::getContentsMargins() to get the margin. diff --git a/src/qt3support/widgets/q3mainwindow.cpp b/src/qt3support/widgets/q3mainwindow.cpp index 2ee3bdc..ae80321 100644 --- a/src/qt3support/widgets/q3mainwindow.cpp +++ b/src/qt3support/widgets/q3mainwindow.cpp @@ -2261,7 +2261,7 @@ static void saveDockArea(QTextStream &ts, Q3DockArea *a) for (int i = 0; i < l.size(); ++i) { Q3DockWindow *dw = l.at(i); ts << QString(dw->windowTitle()); - ts << ","; + ts << ','; } ts << endl; ts << *a; @@ -2287,7 +2287,7 @@ QTextStream &operator<<(QTextStream &ts, const Q3MainWindow &mainWindow) for (int i = 0; i < l.size(); ++i) { Q3DockWindow *dw = l.at(i); ts << dw->windowTitle(); - ts << ","; + ts << ','; } ts << endl; @@ -2295,17 +2295,17 @@ QTextStream &operator<<(QTextStream &ts, const Q3MainWindow &mainWindow) for (int i = 0; i < l.size(); ++i) { Q3DockWindow *dw = l.at(i); ts << dw->windowTitle(); - ts << ","; + ts << ','; } ts << endl; for (int i = 0; i < l.size(); ++i) { Q3DockWindow *dw = l.at(i); - ts << "[" << dw->windowTitle() << "," - << (int)dw->geometry().x() << "," - << (int)dw->geometry().y() << "," - << (int)dw->geometry().width() << "," - << (int)dw->geometry().height() << "," - << (int)dw->isVisible() << "]"; + ts << '[' << dw->windowTitle() << ',' + << (int)dw->geometry().x() << ',' + << (int)dw->geometry().y() << ',' + << (int)dw->geometry().width() << ',' + << (int)dw->geometry().height() << ',' + << (int)dw->isVisible() << ']'; } ts << endl; diff --git a/src/qt3support/widgets/q3popupmenu.cpp b/src/qt3support/widgets/q3popupmenu.cpp index 7f890b5..0b3a524 100644 --- a/src/qt3support/widgets/q3popupmenu.cpp +++ b/src/qt3support/widgets/q3popupmenu.cpp @@ -134,7 +134,7 @@ QT_BEGIN_NAMESPACE \fn int Q3PopupMenu::margin() const \since 4.2 - Returns the with of the the margin around the contents of the widget. + Returns the width of the margin around the contents of the widget. This function uses QWidget::getContentsMargins() to get the margin. \sa setMargin(), QWidget::getContentsMargins() diff --git a/src/qt3support/widgets/q3progressbar.cpp b/src/qt3support/widgets/q3progressbar.cpp index caae460..81f0dbf 100644 --- a/src/qt3support/widgets/q3progressbar.cpp +++ b/src/qt3support/widgets/q3progressbar.cpp @@ -455,7 +455,7 @@ void Q3ProgressBar::paintEvent(QPaintEvent *) \fn int Q3ProgressBar::margin() const \since 4.2 - Returns the with of the the margin around the contents of the widget. + Returns the width of the margin around the contents of the widget. This function uses QWidget::getContentsMargins() to get the margin. \sa setMargin(), QWidget::getContentsMargins() diff --git a/src/qt3support/widgets/q3scrollview.cpp b/src/qt3support/widgets/q3scrollview.cpp index 91a9203..5a91027 100644 --- a/src/qt3support/widgets/q3scrollview.cpp +++ b/src/qt3support/widgets/q3scrollview.cpp @@ -2038,7 +2038,7 @@ void Q3ScrollView::center(int x, int y) \list \i Margin 0.0 allows (x, y) to be on the edge of the visible area. \i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area. - \i Margin 1.0 ensures that (x, y) is in the center of the the visible area. + \i Margin 1.0 ensures that (x, y) is in the center of the visible area. \endlist */ void Q3ScrollView::center(int x, int y, float xmargin, float ymargin) diff --git a/src/script/qscriptcontext.cpp b/src/script/qscriptcontext.cpp index 020601b..ff519c7 100644 --- a/src/script/qscriptcontext.cpp +++ b/src/script/qscriptcontext.cpp @@ -469,7 +469,7 @@ QString QScriptContext::toString() const QScriptValue arg = argument(i); result.append(safeValueToString(arg)); } - result.append(QLatin1String(")")); + result.append(QLatin1Char(')')); QString fileName = info.fileName(); int lineNumber = info.lineNumber(); diff --git a/src/script/qscriptcontext_p.cpp b/src/script/qscriptcontext_p.cpp index 199c9d4..f19ba9c 100644 --- a/src/script/qscriptcontext_p.cpp +++ b/src/script/qscriptcontext_p.cpp @@ -841,7 +841,7 @@ Ltop: flags = iPtr->operand[1].m_int_value; #ifndef QT_NO_REGEXP if (flags != 0) { - literal += QLatin1String("/"); + literal += QLatin1Char('/'); literal += QString::number(flags); } #endif @@ -2396,10 +2396,10 @@ QStringList QScriptContextPrivate::backtrace() const s += QLatin1String("<global>"); } } - s += QLatin1String("("); + s += QLatin1Char('('); for (int i = 0; i < ctx->argc; ++i) { if (i > 0) - s += QLatin1String(","); + s += QLatin1Char(','); QScriptValueImpl arg = ctx->args[i]; if (arg.isObject()) s += QLatin1String("[object Object]"); // don't do a function call diff --git a/src/script/qscriptecmaerror.cpp b/src/script/qscriptecmaerror.cpp index fc39bf9..0dde68c 100644 --- a/src/script/qscriptecmaerror.cpp +++ b/src/script/qscriptecmaerror.cpp @@ -318,18 +318,18 @@ QStringList Error::backtrace(const QScriptValueImpl &error) } else { s += functionName; } - s += QLatin1String("("); + s += QLatin1Char('('); QScriptValueImpl arguments = frame.property(QLatin1String("arguments")); if (arguments.isObject()) { int argCount = arguments.property(QLatin1String("length")).toInt32(); for (int j = 0; j < argCount; ++j) { if (j > 0) - s += QLatin1String(","); + s += QLatin1Char(','); s += arguments.property(j).toString(); } } s += QLatin1String(")@") + o.property(QLatin1String("fileName")).toString() - + QLatin1String(":") + o.property(QLatin1String("lineNumber")).toString(); + + QLatin1Char(':') + o.property(QLatin1String("lineNumber")).toString(); result.append(s); } return result; diff --git a/src/script/qscriptecmafunction.cpp b/src/script/qscriptecmafunction.cpp index ec45ae4..a1e5b58 100644 --- a/src/script/qscriptecmafunction.cpp +++ b/src/script/qscriptecmafunction.cpp @@ -197,7 +197,7 @@ QString Function::buildFunction(QScriptContextPrivate *context) // the formals for (int i = 0; i < argc - 1; ++i) { if (i != 0) - code += QLatin1String(","); + code += QLatin1Char(','); code += context->argument(i).toString(); } diff --git a/src/script/qscriptecmaglobal.cpp b/src/script/qscriptecmaglobal.cpp index da7ab9e..b5cf675 100644 --- a/src/script/qscriptecmaglobal.cpp +++ b/src/script/qscriptecmaglobal.cpp @@ -296,7 +296,7 @@ public: QString result; for (int i = 0; i < context->argumentCount(); ++i) { if (i != 0) - result.append(QLatin1String(" ")); + result.append(QLatin1Char(' ')); QString s = context->argument(i).toString(); if (context->state() == QScriptContext::ExceptionState) diff --git a/src/script/qscriptecmaobject.cpp b/src/script/qscriptecmaobject.cpp index 694f479..c4a1b08 100644 --- a/src/script/qscriptecmaobject.cpp +++ b/src/script/qscriptecmaobject.cpp @@ -113,7 +113,7 @@ QScriptValueImpl Object::method_toString(QScriptContextPrivate *context, QScript QString s = QLatin1String("[object "); QScriptValueImpl self = context->thisObject(); s += self.classInfo()->name(); - s += QLatin1String("]"); + s += QLatin1Char(']'); return (QScriptValueImpl(eng, s)); } diff --git a/src/script/qscriptengine_p.cpp b/src/script/qscriptengine_p.cpp index a2e58de..84a420d 100644 --- a/src/script/qscriptengine_p.cpp +++ b/src/script/qscriptengine_p.cpp @@ -1662,6 +1662,11 @@ bool QScriptEnginePrivate::convert(const QScriptValueImpl &value, return false; } +QScriptEngine::DemarshalFunction QScriptEnginePrivate::demarshalFunction(int type) const +{ + return m_customTypes.value(type).demarshal; +} + QScriptValuePrivate *QScriptEnginePrivate::registerValue(const QScriptValueImpl &value) { if (value.isString()) { diff --git a/src/script/qscriptenginefwd_p.h b/src/script/qscriptenginefwd_p.h index 2ea66c5..855317c 100644 --- a/src/script/qscriptenginefwd_p.h +++ b/src/script/qscriptenginefwd_p.h @@ -350,6 +350,7 @@ public: QScriptValueImpl create(int type, const void *ptr); static bool convert(const QScriptValueImpl &value, int type, void *ptr, QScriptEnginePrivate *eng); + QScriptEngine::DemarshalFunction demarshalFunction(int type) const; QScriptValueImpl arrayFromStringList(const QStringList &lst); static QStringList stringListFromArray(const QScriptValueImpl &arr); diff --git a/src/script/qscriptextqobject.cpp b/src/script/qscriptextqobject.cpp index d18c3da..4522807 100644 --- a/src/script/qscriptextqobject.cpp +++ b/src/script/qscriptextqobject.cpp @@ -425,7 +425,7 @@ static void callQtMethod(QScriptContextPrivate *context, QMetaMethod::MethodType matchDistance += 10; } } - } else if (actual.isNumber()) { + } else if (actual.isNumber() || actual.isString()) { // see if it's an enum value QMetaEnum m; if (argType.isMetaEnum()) { @@ -436,11 +436,21 @@ static void callQtMethod(QScriptContextPrivate *context, QMetaMethod::MethodType m = meta->enumerator(mi); } if (m.isValid()) { - int ival = actual.toInt32(); - if (m.valueToKey(ival) != 0) { - qVariantSetValue(v, ival); - converted = true; - matchDistance += 10; + if (actual.isNumber()) { + int ival = actual.toInt32(); + if (m.valueToKey(ival) != 0) { + qVariantSetValue(v, ival); + converted = true; + matchDistance += 10; + } + } else { + QString sval = actual.toString(); + int ival = m.keyToValue(sval.toLatin1()); + if (ival != -1) { + qVariantSetValue(v, ival); + converted = true; + matchDistance += 10; + } } } } @@ -1809,7 +1819,16 @@ void QScript::QtPropertyFunction::execute(QScriptContextPrivate *context) } } else { // set - QVariant v = variantFromValue(eng_p, prop.userType(), context->argument(0)); + QScriptValueImpl arg = context->argument(0); + QVariant v; + if (prop.isEnumType() && arg.isString() + && !eng_p->demarshalFunction(prop.userType())) { + // give QMetaProperty::write() a chance to convert from + // string to enum value + v = arg.toString(); + } else { + v = variantFromValue(eng_p, prop.userType(), arg); + } QScriptable *scriptable = scriptableFromQObject(qobject); QScriptEngine *oldEngine = 0; diff --git a/src/script/qscriptparser.cpp b/src/script/qscriptparser.cpp index 0b04df1..7408ec5 100644 --- a/src/script/qscriptparser.cpp +++ b/src/script/qscriptparser.cpp @@ -1148,9 +1148,9 @@ case 266: { error_message += QLatin1String (", "); first = false; - error_message += QLatin1String("`"); + error_message += QLatin1Char('`'); error_message += QLatin1String (spell [expected_tokens [s]]); - error_message += QLatin1String("'"); + error_message += QLatin1Char('\''); } } diff --git a/src/script/qscriptprettypretty.cpp b/src/script/qscriptprettypretty.cpp index 6ee1e55..b221b0a 100644 --- a/src/script/qscriptprettypretty.cpp +++ b/src/script/qscriptprettypretty.cpp @@ -73,13 +73,13 @@ PrettyPretty::~PrettyPretty() void PrettyPretty::acceptAsBlock(AST::Node *node) { - out << "{"; + out << '{'; pushIndentLevel(); newlineAndIndent(); accept(node); popIndentLevel(); newlineAndIndent(); - out << "}"; + out << '}'; } int PrettyPretty::operatorPrecedenceLevel(int op) @@ -230,8 +230,8 @@ void PrettyPretty::endVisit(AST::FalseLiteral *node) bool PrettyPretty::visit(AST::StringLiteral *node) { QString lit = QScriptEnginePrivate::toString(node->value); - lit.replace(QLatin1String("\\"), QLatin1String("\\\\")); - out << "\"" << lit << "\""; + lit.replace(QLatin1Char('\\'), QLatin1String("\\\\")); + out << '\"' << lit << '\"'; return false; } @@ -253,7 +253,7 @@ void PrettyPretty::endVisit(AST::NumericLiteral *node) bool PrettyPretty::visit(AST::RegExpLiteral *node) { - out << "/" << QScriptEnginePrivate::toString(node->pattern) << "/"; + out << '/' << QScriptEnginePrivate::toString(node->pattern) << '/'; if (node->flags) out << QScript::Ecma::RegExp::flagsToString(node->flags); @@ -267,10 +267,10 @@ void PrettyPretty::endVisit(AST::RegExpLiteral *node) bool PrettyPretty::visit(AST::ArrayLiteral *node) { - out << "["; + out << '['; accept(node->elements); accept(node->elision); - out << "]"; + out << ']'; return false; } @@ -281,7 +281,7 @@ void PrettyPretty::endVisit(AST::ArrayLiteral *node) bool PrettyPretty::visit(AST::ObjectLiteral *node) { - out << "{"; + out << '{'; if (node->properties) { pushIndentLevel(); AST::PropertyNameAndValueList *prop; @@ -289,12 +289,12 @@ bool PrettyPretty::visit(AST::ObjectLiteral *node) newlineAndIndent(); accept(prop); if (prop->next) - out << ","; + out << ','; } popIndentLevel(); newlineAndIndent(); } - out << "}"; + out << '}'; return false; } @@ -384,9 +384,9 @@ void PrettyPretty::endVisit(AST::NumericLiteralPropertyName *node) bool PrettyPretty::visit(AST::ArrayMemberExpression *node) { accept(node->base); - out << "["; + out << '['; accept(node->expression); - out << "]"; + out << ']'; return false; } @@ -398,7 +398,7 @@ void PrettyPretty::endVisit(AST::ArrayMemberExpression *node) bool PrettyPretty::visit(AST::FieldMemberExpression *node) { accept(node->base); - out << "." << QScriptEnginePrivate::toString(node->name); + out << '.' << QScriptEnginePrivate::toString(node->name); return false; } @@ -411,9 +411,9 @@ bool PrettyPretty::visit(AST::NewMemberExpression *node) { out << "new "; accept(node->base); - out << "("; + out << '('; accept(node->arguments); - out << ")"; + out << ')'; return false; } @@ -437,9 +437,9 @@ void PrettyPretty::endVisit(AST::NewExpression *node) bool PrettyPretty::visit(AST::CallExpression *node) { accept(node->base); - out << "("; + out << '('; accept(node->arguments); - out << ")"; + out << ')'; return false; } @@ -549,13 +549,13 @@ void PrettyPretty::endVisit(AST::PreDecrementExpression *node) bool PrettyPretty::visit(AST::UnaryPlusExpression *node) { - out << "+"; + out << '+'; bool needParens = (node->expression->binaryExpressionCast() != 0); if (needParens) - out << "("; + out << '('; accept(node->expression); if (needParens) - out << ")"; + out << ')'; return false; } @@ -566,13 +566,13 @@ void PrettyPretty::endVisit(AST::UnaryPlusExpression *node) bool PrettyPretty::visit(AST::UnaryMinusExpression *node) { - out << "-"; + out << '-'; bool needParens = (node->expression->binaryExpressionCast() != 0); if (needParens) - out << "("; + out << '('; accept(node->expression); if (needParens) - out << ")"; + out << ')'; return false; } @@ -583,13 +583,13 @@ void PrettyPretty::endVisit(AST::UnaryMinusExpression *node) bool PrettyPretty::visit(AST::TildeExpression *node) { - out << "~"; + out << '~'; bool needParens = (node->expression->binaryExpressionCast() != 0); if (needParens) - out << "("; + out << '('; accept(node->expression); if (needParens) - out << ")"; + out << ')'; return false; } @@ -600,13 +600,13 @@ void PrettyPretty::endVisit(AST::TildeExpression *node) bool PrettyPretty::visit(AST::NotExpression *node) { - out << "!"; + out << '!'; bool needParens = (node->expression->binaryExpressionCast() != 0); if (needParens) - out << "("; + out << '('; accept(node->expression); if (needParens) - out << ")"; + out << ')'; return false; } @@ -620,10 +620,10 @@ bool PrettyPretty::visit(AST::BinaryExpression *node) bool needParens = node->left->binaryExpressionCast() && (compareOperatorPrecedence(node->left->binaryExpressionCast()->op, node->op) < 0); if (needParens) - out << "("; + out << '('; accept(node->left); if (needParens) - out << ")"; + out << ')'; QString s; switch (node->op) { case QSOperator::Add: @@ -699,14 +699,14 @@ bool PrettyPretty::visit(AST::BinaryExpression *node) default: Q_ASSERT (0); } - out << " " << s << " "; + out << ' ' << s << ' '; needParens = node->right->binaryExpressionCast() && (compareOperatorPrecedence(node->right->binaryExpressionCast()->op, node->op) <= 0); if (needParens) - out << "("; + out << '('; accept(node->right); if (needParens) - out << ")"; + out << ')'; return false; } @@ -798,7 +798,7 @@ bool PrettyPretty::visit(AST::VariableStatement *node) void PrettyPretty::endVisit(AST::VariableStatement *node) { Q_UNUSED(node); - out << ";"; + out << ';'; } bool PrettyPretty::visit(AST::VariableDeclaration *node) @@ -819,7 +819,7 @@ void PrettyPretty::endVisit(AST::VariableDeclaration *node) bool PrettyPretty::visit(AST::EmptyStatement *node) { Q_UNUSED(node); - out << ";"; + out << ';'; return true; } @@ -831,7 +831,7 @@ void PrettyPretty::endVisit(AST::EmptyStatement *node) bool PrettyPretty::visit(AST::ExpressionStatement *node) { accept(node->expression); - out << ";"; + out << ';'; return false; } @@ -959,9 +959,9 @@ bool PrettyPretty::visit(AST::ContinueStatement *node) { out << "continue"; if (node->label) { - out << " " << QScriptEnginePrivate::toString(node->label); + out << ' ' << QScriptEnginePrivate::toString(node->label); } - out << ";"; + out << ';'; return false; } @@ -974,9 +974,9 @@ bool PrettyPretty::visit(AST::BreakStatement *node) { out << "break"; if (node->label) { - out << " " << QScriptEnginePrivate::toString(node->label); + out << ' ' << QScriptEnginePrivate::toString(node->label); } - out << ";"; + out << ';'; return false; } @@ -989,10 +989,10 @@ bool PrettyPretty::visit(AST::ReturnStatement *node) { out << "return"; if (node->expression) { - out << " "; + out << ' '; accept(node->expression); } - out << ";"; + out << ';'; return false; } @@ -1067,7 +1067,7 @@ bool PrettyPretty::visit(AST::CaseClause *node) { out << "case "; accept(node->expression); - out << ":"; + out << ':'; if (node->statements) { newlineAndIndent(); accept(node->statements); @@ -1109,7 +1109,7 @@ bool PrettyPretty::visit(AST::ThrowStatement *node) Q_UNUSED(node); out << "throw "; accept(node->expression); - out << ";"; + out << ';'; return false; } @@ -1166,10 +1166,10 @@ bool PrettyPretty::visit(AST::FunctionDeclaration *node) out << "function"; if (node->name) - out << " " << QScriptEnginePrivate::toString(node->name); + out << ' ' << QScriptEnginePrivate::toString(node->name); // the arguments - out << "("; + out << '('; for (AST::FormalParameterList *it = node->formals; it; it = it->next) { if (it->name) out << QScriptEnginePrivate::toString(it->name); @@ -1177,7 +1177,7 @@ bool PrettyPretty::visit(AST::FunctionDeclaration *node) if (it->next) out << ", "; } - out << ")"; + out << ')'; // the function body out << " {"; @@ -1190,7 +1190,7 @@ bool PrettyPretty::visit(AST::FunctionDeclaration *node) newlineAndIndent(); } - out << "}"; + out << '}'; return false; } @@ -1205,10 +1205,10 @@ bool PrettyPretty::visit(AST::FunctionExpression *node) out << "function"; if (node->name) - out << " " << QScriptEnginePrivate::toString(node->name); + out << ' ' << QScriptEnginePrivate::toString(node->name); // the arguments - out << "("; + out << '('; for (AST::FormalParameterList *it = node->formals; it; it = it->next) { if (it->name) out << QScriptEnginePrivate::toString(it->name); @@ -1216,7 +1216,7 @@ bool PrettyPretty::visit(AST::FunctionExpression *node) if (it->next) out << ", "; } - out << ")"; + out << ')'; // the function body out << " {"; @@ -1229,7 +1229,7 @@ bool PrettyPretty::visit(AST::FunctionExpression *node) newlineAndIndent(); } - out << "}"; + out << '}'; return false; } @@ -1320,7 +1320,7 @@ bool PrettyPretty::visit(AST::DebuggerStatement *node) void PrettyPretty::endVisit(AST::DebuggerStatement *node) { Q_UNUSED(node); - out << ";"; + out << ';'; } bool PrettyPretty::preVisit(AST::Node *node) diff --git a/src/script/qscriptsyntaxchecker.cpp b/src/script/qscriptsyntaxchecker.cpp index 9653bc1..74ca00f 100644 --- a/src/script/qscriptsyntaxchecker.cpp +++ b/src/script/qscriptsyntaxchecker.cpp @@ -186,9 +186,9 @@ SyntaxChecker::Result SyntaxChecker::checkSyntax(const QString &code) error_message += QLatin1String (", "); first = false; - error_message += QLatin1String("`"); + error_message += QLatin1Char('`'); error_message += QLatin1String (spell [expected_tokens [s]]); - error_message += QLatin1String("'"); + error_message += QLatin1Char('\''); } } diff --git a/src/script/qscriptvalueimpl.cpp b/src/script/qscriptvalueimpl.cpp index 15d1b8a..a890839 100644 --- a/src/script/qscriptvalueimpl.cpp +++ b/src/script/qscriptvalueimpl.cpp @@ -395,7 +395,7 @@ QDebug &operator<<(QDebug &d, const QScriptValueImpl &object) QScriptObject *od = object.objectValue(); for (int i=0; i<od->memberCount(); ++i) { if (i != 0) - d << ","; + d << ','; QScript::Member m; od->member(i, &m); @@ -404,7 +404,7 @@ QDebug &operator<<(QDebug &d, const QScriptValueImpl &object) d << object.engine()->toString(m.nameId()); QScriptValueImpl o; od->get(m, &o); - d.nospace() << QLatin1String(":") + d.nospace() << QLatin1Char(':') << (o.classInfo() ? o.classInfo()->name() : QLatin1String("?")); @@ -415,14 +415,14 @@ QDebug &operator<<(QDebug &d, const QScriptValueImpl &object) QScriptValueImpl scope = object.scope(); while (scope.isValid()) { Q_ASSERT(scope.isObject()); - d.nospace() << " " << scope.objectValue(); + d.nospace() << ' ' << scope.objectValue(); scope = scope.scope(); } - d.nospace() << "}"; + d.nospace() << '}'; break; } - d << ")"; + d << ')'; return d; } diff --git a/src/script/qscriptvalueiterator.cpp b/src/script/qscriptvalueiterator.cpp index fe5ef9f..1a60632 100644 --- a/src/script/qscriptvalueiterator.cpp +++ b/src/script/qscriptvalueiterator.cpp @@ -106,6 +106,7 @@ QScriptValueIteratorPrivate::QScriptValueIteratorPrivate() */ QScriptValueIteratorPrivate::~QScriptValueIteratorPrivate() { + delete it; } /*! @@ -130,7 +131,6 @@ QScriptValueIterator::QScriptValueIterator(const QScriptValue &object) QScriptValueIterator::~QScriptValueIterator() { if (d_ptr) { - delete d_ptr->it; delete d_ptr; d_ptr = 0; } @@ -312,7 +312,7 @@ void QScriptValueIterator::remove() QScriptValueIterator& QScriptValueIterator::operator=(QScriptValue &object) { if (d_ptr) { - delete d_ptr->it; + delete d_ptr; d_ptr = 0; } QScriptValueImpl val = QScriptValuePrivate::valueOf(object); diff --git a/src/script/qscriptxmlgenerator.cpp b/src/script/qscriptxmlgenerator.cpp index 131882b..163b60c 100644 --- a/src/script/qscriptxmlgenerator.cpp +++ b/src/script/qscriptxmlgenerator.cpp @@ -121,10 +121,10 @@ QTextStream &XmlGenerator::startTag(const QString &name, AST::Node *locationNode { pushIndentLevel(); newlineAndIndent(); - out << QLatin1String("<") << name; + out << QLatin1Char('<') << name; if (locationNode) - out << QLatin1String(" line=\"") << locationNode->startLine << QLatin1String("\""); - out << QLatin1String(">"); + out << QLatin1String(" line=\"") << locationNode->startLine << QLatin1Char('\"'); + out << QLatin1Char('>'); return out; } @@ -132,7 +132,7 @@ QTextStream &XmlGenerator::endTag(const QString &name) { newlineAndIndent(); popIndentLevel(); - out << QLatin1String("</") << escape(name) << QLatin1String(">"); + out << QLatin1String("</") << escape(name) << QLatin1Char('>'); return out; } @@ -233,7 +233,7 @@ void XmlGenerator::endVisit(AST::NumericLiteral *) bool XmlGenerator::visit(AST::RegExpLiteral *node) { startTag(QLatin1String("regexp")); - out << QLatin1String("/") << escape(QScriptEnginePrivate::toString(node->pattern)) << QLatin1String("/"); + out << QLatin1Char('/') << escape(QScriptEnginePrivate::toString(node->pattern)) << QLatin1Char('/'); if (node->flags) out << QScript::Ecma::RegExp::flagsToString(node->flags); out << QLatin1String("</regexp>"); diff --git a/src/scripttools/debugging/qscriptcompletiontask.cpp b/src/scripttools/debugging/qscriptcompletiontask.cpp index 119b96a..2f3c2cf 100644 --- a/src/scripttools/debugging/qscriptcompletiontask.cpp +++ b/src/scripttools/debugging/qscriptcompletiontask.cpp @@ -158,7 +158,7 @@ void QScriptCompletionTaskPrivate::completeScriptExpression() if (path.size() > 1) { const QString &topLevelIdent = path.at(0); QScriptValue obj; - if (topLevelIdent == QString::fromLatin1("this")) { + if (topLevelIdent == QLatin1String("this")) { obj = ctx->thisObject(); } else { QScriptValueList scopeChain; @@ -256,9 +256,9 @@ void QScriptCompletionTask::start() } QString argType = cmd->argumentTypes().value(argNum); if (!argType.isEmpty()) { - if (argType == QString::fromLatin1("command-or-group-name")) { + if (argType == QLatin1String("command-or-group-name")) { d->results = d->console->commandManager()->completions(arg); - } else if (argType == QString::fromLatin1("script-filename")) { + } else if (argType == QLatin1String("script-filename")) { // ### super-cheating for now; have to use the async API QScriptEngineDebuggerFrontend *edf = static_cast<QScriptEngineDebuggerFrontend*>(d->frontend); QScriptDebuggerBackend *backend = edf->backend(); @@ -269,13 +269,13 @@ void QScriptCompletionTask::start() if (isPrefixOf(arg, fileName)) d->results.append(fileName); } - } else if (argType == QString::fromLatin1("subcommand-name")) { + } else if (argType == QLatin1String("subcommand-name")) { for (int i = 0; i < cmd->subCommands().size(); ++i) { QString name = cmd->subCommands().at(i); if (isPrefixOf(arg, name)) d->results.append(name); } - } else if (argType == QString::fromLatin1("script")) { + } else if (argType == QLatin1String("script")) { d->completeScriptExpression(); } if ((d->type == NoCompletion) && !d->results.isEmpty()) { diff --git a/src/scripttools/debugging/qscriptdebuggerbackend.cpp b/src/scripttools/debugging/qscriptdebuggerbackend.cpp index 3c29130..0771d0b 100644 --- a/src/scripttools/debugging/qscriptdebuggerbackend.cpp +++ b/src/scripttools/debugging/qscriptdebuggerbackend.cpp @@ -292,7 +292,7 @@ QScriptValue QScriptDebuggerBackendPrivate::trace(QScriptContext *context, QString str; for (int i = 0; i < context->argumentCount(); ++i) { if (i > 0) - str.append(QLatin1String(" ")); + str.append(QLatin1Char(' ')); str.append(context->argument(i).toString()); } QScriptDebuggerEvent e(QScriptDebuggerEvent::Trace); diff --git a/src/scripttools/debugging/qscriptdebuggerconsole.cpp b/src/scripttools/debugging/qscriptdebuggerconsole.cpp index 70bb8b1..546ec63 100644 --- a/src/scripttools/debugging/qscriptdebuggerconsole.cpp +++ b/src/scripttools/debugging/qscriptdebuggerconsole.cpp @@ -163,10 +163,10 @@ QScriptDebuggerConsoleCommandJob *QScriptDebuggerConsolePrivate::createJob( .arg(name)); for (int j = 0; j < completions.size(); ++j) { if (j > 0) - msg.append(QString::fromLatin1(", ")); + msg.append(QLatin1String(", ")); msg.append(completions.at(j)); } - msg.append(QString::fromLatin1(".")); + msg.append(QLatin1Char('.')); messageHandler->message(QtWarningMsg, msg); return 0; } diff --git a/src/scripttools/debugging/qscriptdebuggerlocalsmodel.cpp b/src/scripttools/debugging/qscriptdebuggerlocalsmodel.cpp index caeb971..e096ba8 100644 --- a/src/scripttools/debugging/qscriptdebuggerlocalsmodel.cpp +++ b/src/scripttools/debugging/qscriptdebuggerlocalsmodel.cpp @@ -807,7 +807,7 @@ QVariant QScriptDebuggerLocalsModel::data(const QModelIndex &index, int role) co QString str = node->property.valueAsString(); if (node->property.value().type() == QScriptDebuggerValue::StringValue) { // escape - str.replace(QLatin1String("\""), QLatin1String("\\\"")); + str.replace(QLatin1Char('\"'), QLatin1String("\\\"")); str.prepend(QLatin1Char('\"')); str.append(QLatin1Char('\"')); } diff --git a/src/scripttools/debugging/qscriptenginedebugger.cpp b/src/scripttools/debugging/qscriptenginedebugger.cpp index e35bd1d..0f8b600 100644 --- a/src/scripttools/debugging/qscriptenginedebugger.cpp +++ b/src/scripttools/debugging/qscriptenginedebugger.cpp @@ -63,16 +63,23 @@ #include <QtGui/qtoolbar.h> #include <QtGui/qboxlayout.h> +// this has to be outside the namespace +static void initScriptEngineDebuggerResources() +{ + Q_INIT_RESOURCE(scripttools_debugging); +} + +QT_BEGIN_NAMESPACE + class QtScriptDebuggerResourceInitializer { public: QtScriptDebuggerResourceInitializer() { - Q_INIT_RESOURCE(scripttools_debugging); + // call outside-the-namespace function + initScriptEngineDebuggerResources(); } }; -QT_BEGIN_NAMESPACE - /*! \since 4.5 \class QScriptEngineDebugger diff --git a/src/sql/drivers/db2/qsql_db2.cpp b/src/sql/drivers/db2/qsql_db2.cpp index 11d0041..c7cbc9b 100644 --- a/src/sql/drivers/db2/qsql_db2.cpp +++ b/src/sql/drivers/db2/qsql_db2.cpp @@ -1666,7 +1666,7 @@ QVariant QDB2Driver::handle() const QString QDB2Driver::escapeIdentifier(const QString &identifier, IdentifierType) const { QString res = identifier; - if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) { + if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) { res.replace(QLatin1Char('"'), QLatin1String("\"\"")); res.prepend(QLatin1Char('"')).append(QLatin1Char('"')); res.replace(QLatin1Char('.'), QLatin1String("\".\"")); diff --git a/src/sql/drivers/ibase/qsql_ibase.cpp b/src/sql/drivers/ibase/qsql_ibase.cpp index 9eeb41d..199ad8e 100644 --- a/src/sql/drivers/ibase/qsql_ibase.cpp +++ b/src/sql/drivers/ibase/qsql_ibase.cpp @@ -55,6 +55,7 @@ #include <limits.h> #include <math.h> #include <qdebug.h> +#include <QVarLengthArray> QT_BEGIN_NAMESPACE @@ -66,8 +67,11 @@ QT_BEGIN_NAMESPACE enum { QIBaseChunkSize = SHRT_MAX / 2 }; -static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, - QTextCodec *tc) +#if defined(FB_API_VER) && FB_API_VER >= 20 +static bool getIBaseError(QString& msg, const ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc) +#else +static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc) +#endif { if (status[0] != 1 || status[1] <= 0) return false; @@ -75,7 +79,11 @@ static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, msg.clear(); sqlcode = isc_sqlcode(status); char buf[512]; +#if defined(FB_API_VER) && FB_API_VER >= 20 + while(fb_interpret(buf, 512, &status)) { +#else while(isc_interprete(buf, &status)) { +#endif if(!msg.isEmpty()) msg += QLatin1String(" - "); if (tc) @@ -576,7 +584,7 @@ QVariant QIBaseResultPrivate::fetchArray(int pos, ISC_QUAD *arr) int arraySize = 1, subArraySize; short dimensions = desc.array_desc_dimensions; - short *numElements = new short[dimensions]; + QVarLengthArray<short> numElements(dimensions); for(int i = 0; i < dimensions; ++i) { subArraySize = (desc.array_desc_bounds[i].array_bound_upper - @@ -605,9 +613,7 @@ QVariant QIBaseResultPrivate::fetchArray(int pos, ISC_QUAD *arr) QSqlError::StatementError)) return list; - readArrayBuffer(list, ba.data(), 0, numElements, &desc, tc); - - delete[] numElements; + readArrayBuffer(list, ba.data(), 0, numElements.data(), &desc, tc); return QVariant(list); } @@ -871,7 +877,7 @@ QIBaseResult::~QIBaseResult() bool QIBaseResult::prepare(const QString& query) { - //qDebug("prepare: %s\n", qPrintable(query)); +// qDebug("prepare: %s", qPrintable(query)); if (!driver() || !driver()->isOpen() || driver()->isOpenError()) return false; d->cleanup(); @@ -1025,7 +1031,7 @@ bool QIBaseResult::exec() } if (ok) { - if (colCount()) { + if (colCount() && d->queryType != isc_info_sql_stmt_exec_procedure) { isc_dsql_free_statement(d->status, &d->stmt, DSQL_close); if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to close statement"))) return false; @@ -1039,7 +1045,7 @@ bool QIBaseResult::exec() return false; // Not all stored procedures necessarily return values. - if (d->queryType == isc_info_sql_stmt_exec_procedure && d->sqlda->sqld == 0) + if (d->queryType == isc_info_sql_stmt_exec_procedure && d->sqlda && d->sqlda->sqld == 0) delDA(d->sqlda); if (d->sqlda) @@ -1726,7 +1732,7 @@ bool QIBaseDriver::subscribeToNotificationImplementation(const QString &name) eBuffer->resultBuffer); if (status[0] == 1 && status[1]) { - setLastError(QSqlError(QString(QLatin1String("Could not subscribe to event notifications for %1.")).arg(name))); + setLastError(QSqlError(QString::fromLatin1("Could not subscribe to event notifications for %1.").arg(name))); d->eventBuffers.remove(name); qFreeEventBuffer(eBuffer); return false; @@ -1754,7 +1760,7 @@ bool QIBaseDriver::unsubscribeFromNotificationImplementation(const QString &name isc_cancel_events(status, &d->ibase, &eBuffer->eventId); if (status[0] == 1 && status[1]) { - setLastError(QSqlError(QString(QLatin1String("Could not unsubscribe from event notifications for %1.")).arg(name))); + setLastError(QSqlError(QString::fromLatin1("Could not unsubscribe from event notifications for %1.").arg(name))); return false; } @@ -1812,7 +1818,7 @@ void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer) QString QIBaseDriver::escapeIdentifier(const QString &identifier, IdentifierType) const { QString res = identifier; - if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) { + if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) { res.replace(QLatin1Char('"'), QLatin1String("\"\"")); res.prepend(QLatin1Char('"')).append(QLatin1Char('"')); res.replace(QLatin1Char('.'), QLatin1String("\".\"")); diff --git a/src/sql/drivers/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp index a84e840..82ed124 100644 --- a/src/sql/drivers/mysql/qsql_mysql.cpp +++ b/src/sql/drivers/mysql/qsql_mysql.cpp @@ -163,18 +163,21 @@ static inline QVariant qDateTimeFromString(QString &val) #endif } -class QMYSQLResultPrivate +class QMYSQLResultPrivate : public QObject { + Q_OBJECT public: - QMYSQLResultPrivate(QMYSQLDriverPrivate* dp) : d(dp), result(0), + QMYSQLResultPrivate(const QMYSQLDriver* dp) : driver(dp), result(0), rowsAffected(0), hasBlobs(false) #if MYSQL_VERSION_ID >= 40108 , stmt(0), meta(0), inBinds(0), outBinds(0) #endif , precisionPolicy(QSql::HighPrecision) - {} + { + connect(dp, SIGNAL(destroyed()), this, SLOT(driverDestroyed())); + } - QMYSQLDriverPrivate* d; + const QMYSQLDriver* driver; MYSQL_RES *result; MYSQL_ROW row; @@ -207,6 +210,8 @@ public: MYSQL_BIND *outBinds; #endif QSql::NumericalPrecisionPolicy precisionPolicy; +private Q_SLOTS: + void driverDestroyed() { driver = NULL; } }; #ifndef QT_NO_TEXTCODEC @@ -224,7 +229,7 @@ static QTextCodec* codec(MYSQL* mysql) static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, const QMYSQLDriverPrivate* p) { - const char *cerr = mysql_error(p->mysql); + const char *cerr = p->mysql ? mysql_error(p->mysql) : 0; return QSqlError(QLatin1String("QMYSQL: ") + err, p->tc ? toUnicode(p->tc, cerr) : QString::fromLatin1(cerr), type, mysql_errno(p->mysql)); @@ -379,7 +384,7 @@ bool QMYSQLResultPrivate::bindInValues() QMYSQLResult::QMYSQLResult(const QMYSQLDriver* db) : QSqlResult(db) { - d = new QMYSQLResultPrivate(db->d); + d = new QMYSQLResultPrivate(db); } QMYSQLResult::~QMYSQLResult() @@ -391,7 +396,7 @@ QMYSQLResult::~QMYSQLResult() QVariant QMYSQLResult::handle() const { #if MYSQL_VERSION_ID >= 40108 - if(d->d->preparedQuerys) + if(d->driver && d->driver->d->preparedQuerys) return d->meta ? qVariantFromValue(d->meta) : qVariantFromValue(d->stmt); else #endif @@ -406,8 +411,8 @@ void QMYSQLResult::cleanup() // must iterate trough leftover result sets from multi-selects or stored procedures // if this isn't done subsequent queries will fail with "Commands out of sync" #if MYSQL_VERSION_ID >= 40100 - while (d->d->mysql && mysql_next_result(d->d->mysql) == 0) { - MYSQL_RES *res = mysql_store_result(d->d->mysql); + while (d->driver && d->driver->d->mysql && mysql_next_result(d->driver->d->mysql) == 0) { + MYSQL_RES *res = mysql_store_result(d->driver->d->mysql); if (res) mysql_free_result(res); } @@ -447,11 +452,14 @@ void QMYSQLResult::cleanup() setAt(-1); setActive(false); - d->d->preparedQuerys = d->d->preparedQuerysEnabled; + if(d->driver) + d->driver->d->preparedQuerys = d->driver->d->preparedQuerysEnabled; } bool QMYSQLResult::fetch(int i) { + if(!d->driver) + return false; if (isForwardOnly()) { // fake a forward seek if (at() < i) { int x = i - at(); @@ -463,7 +471,7 @@ bool QMYSQLResult::fetch(int i) } if (at() == i) return true; - if (d->d->preparedQuerys) { + if (d->driver->d->preparedQuerys) { #if MYSQL_VERSION_ID >= 40108 mysql_stmt_data_seek(d->stmt, i); @@ -494,7 +502,9 @@ bool QMYSQLResult::fetch(int i) bool QMYSQLResult::fetchNext() { - if (d->d->preparedQuerys) { + if(!d->driver) + return false; + if (d->driver->d->preparedQuerys) { #if MYSQL_VERSION_ID >= 40108 if (mysql_stmt_fetch(d->stmt)) return false; @@ -512,6 +522,8 @@ bool QMYSQLResult::fetchNext() bool QMYSQLResult::fetchLast() { + if(!d->driver) + return false; if (isForwardOnly()) { // fake this since MySQL can't seek on forward only queries bool success = fetchNext(); // did we move at all? while (fetchNext()) {}; @@ -519,7 +531,7 @@ bool QMYSQLResult::fetchLast() } my_ulonglong numRows; - if (d->d->preparedQuerys) { + if (d->driver->d->preparedQuerys) { #if MYSQL_VERSION_ID >= 40108 numRows = mysql_stmt_num_rows(d->stmt); #else @@ -553,15 +565,18 @@ QVariant QMYSQLResult::data(int field) return QVariant(); } + if (!d->driver) + return QVariant(); + int fieldLength = 0; const QMYSQLResultPrivate::QMyField &f = d->fields.at(field); QString val; - if (d->d->preparedQuerys) { + if (d->driver->d->preparedQuerys) { if (f.nullIndicator) return QVariant(f.type); if (f.type != QVariant::ByteArray) - val = toUnicode(d->d->tc, f.outField, f.bufLength); + val = toUnicode(d->driver->d->tc, f.outField, f.bufLength); } else { if (d->row[field] == NULL) { // NULL value @@ -569,7 +584,7 @@ QVariant QMYSQLResult::data(int field) } fieldLength = mysql_fetch_lengths(d->result)[field]; if (f.type != QVariant::ByteArray) - val = toUnicode(d->d->tc, d->row[field], fieldLength); + val = toUnicode(d->driver->d->tc, d->row[field], fieldLength); } switch(f.type) { @@ -614,7 +629,7 @@ QVariant QMYSQLResult::data(int field) case QVariant::ByteArray: { QByteArray ba; - if (d->d->preparedQuerys) { + if (d->driver->d->preparedQuerys) { ba = QByteArray(f.outField, f.bufLength); } else { ba = QByteArray(d->row[field], fieldLength); @@ -631,7 +646,7 @@ QVariant QMYSQLResult::data(int field) bool QMYSQLResult::isNull(int field) { - if (d->d->preparedQuerys) + if (d->driver->d->preparedQuerys) return d->fields.at(field).nullIndicator; else return d->row[field] == NULL; @@ -639,31 +654,31 @@ bool QMYSQLResult::isNull(int field) bool QMYSQLResult::reset (const QString& query) { - if (!driver() || !driver()->isOpen() || driver()->isOpenError()) + if (!driver() || !driver()->isOpen() || driver()->isOpenError() || !d->driver) return false; - if(d->d->preparedQuerysEnabled && prepare(query)) { - d->d->preparedQuerys = true; + if(d->driver->d->preparedQuerysEnabled && prepare(query)) { + d->driver->d->preparedQuerys = true; return exec(); } - d->d->preparedQuerys = false; + d->driver->d->preparedQuerys = false; - const QByteArray encQuery(fromUnicode(d->d->tc, query)); - if (mysql_real_query(d->d->mysql, encQuery.data(), encQuery.length())) { + const QByteArray encQuery(fromUnicode(d->driver->d->tc, query)); + if (mysql_real_query(d->driver->d->mysql, encQuery.data(), encQuery.length())) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute query"), - QSqlError::StatementError, d->d)); + QSqlError::StatementError, d->driver->d)); return false; } - d->result = mysql_store_result(d->d->mysql); - if (!d->result && mysql_field_count(d->d->mysql) > 0) { + d->result = mysql_store_result(d->driver->d->mysql); + if (!d->result && mysql_field_count(d->driver->d->mysql) > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store result"), - QSqlError::StatementError, d->d)); + QSqlError::StatementError, d->driver->d)); return false; } - int numFields = mysql_field_count(d->d->mysql); + int numFields = mysql_field_count(d->driver->d->mysql); setSelect(numFields != 0); d->fields.resize(numFields); - d->rowsAffected = mysql_affected_rows(d->d->mysql); + d->rowsAffected = mysql_affected_rows(d->driver->d->mysql); if (isSelect()) { for(int i = 0; i < numFields; i++) { MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i); @@ -677,8 +692,8 @@ bool QMYSQLResult::reset (const QString& query) int QMYSQLResult::size() { - if (isSelect()) - if (d->d->preparedQuerys) + if (d->driver && isSelect()) + if (d->driver->d->preparedQuerys) #if MYSQL_VERSION_ID >= 40108 return mysql_stmt_num_rows(d->stmt); #else @@ -697,17 +712,17 @@ int QMYSQLResult::numRowsAffected() QVariant QMYSQLResult::lastInsertId() const { - if (!isActive()) + if (!isActive() || !d->driver) return QVariant(); - if (d->d->preparedQuerys) { + if (d->driver->d->preparedQuerys) { #if MYSQL_VERSION_ID >= 40108 quint64 id = mysql_stmt_insert_id(d->stmt); if (id) return QVariant(id); #endif } else { - quint64 id = mysql_insert_id(d->d->mysql); + quint64 id = mysql_insert_id(d->driver->d->mysql); if (id) return QVariant(id); } @@ -718,20 +733,20 @@ QSqlRecord QMYSQLResult::record() const { QSqlRecord info; MYSQL_RES *res; - if (!isActive() || !isSelect()) + if (!isActive() || !isSelect() || !d->driver) return info; #if MYSQL_VERSION_ID >= 40108 - res = d->d->preparedQuerys ? d->meta : d->result; + res = d->driver->d->preparedQuerys ? d->meta : d->result; #else res = d->result; #endif - if (!mysql_errno(d->d->mysql)) { + if (!mysql_errno(d->driver->d->mysql)) { mysql_field_seek(res, 0); MYSQL_FIELD* field = mysql_fetch_field(res); while(field) { - info.append(qToField(field, d->d->tc)); + info.append(qToField(field, d->driver->d->tc)); field = mysql_fetch_field(res); } } @@ -741,6 +756,8 @@ QSqlRecord QMYSQLResult::record() const bool QMYSQLResult::nextResult() { + if(!d->driver) + return false; #if MYSQL_VERSION_ID >= 40100 setAt(-1); setActive(false); @@ -754,26 +771,26 @@ bool QMYSQLResult::nextResult() delete[] d->fields[i].outField; d->fields.clear(); - int status = mysql_next_result(d->d->mysql); + int status = mysql_next_result(d->driver->d->mysql); if (status > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute next query"), - QSqlError::StatementError, d->d)); + QSqlError::StatementError, d->driver->d)); return false; } else if (status == -1) { return false; // No more result sets } - d->result = mysql_store_result(d->d->mysql); - int numFields = mysql_field_count(d->d->mysql); + d->result = mysql_store_result(d->driver->d->mysql); + int numFields = mysql_field_count(d->driver->d->mysql); if (!d->result && numFields > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store next result"), - QSqlError::StatementError, d->d)); + QSqlError::StatementError, d->driver->d)); return false; } setSelect(numFields > 0); d->fields.resize(numFields); - d->rowsAffected = mysql_affected_rows(d->d->mysql); + d->rowsAffected = mysql_affected_rows(d->driver->d->mysql); if (isSelect()) { for (int i = 0; i < numFields; i++) { @@ -833,9 +850,11 @@ static MYSQL_TIME *toMySqlDate(QDate date, QTime time, QVariant::Type type) bool QMYSQLResult::prepare(const QString& query) { + if(!d->driver) + return false; #if MYSQL_VERSION_ID >= 40108 cleanup(); - if (!d->d->preparedQuerys) + if (!d->driver->d->preparedQuerys) return QSqlResult::prepare(query); int r; @@ -844,14 +863,14 @@ bool QMYSQLResult::prepare(const QString& query) return false; if (!d->stmt) - d->stmt = mysql_stmt_init(d->d->mysql); + d->stmt = mysql_stmt_init(d->driver->d->mysql); if (!d->stmt) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to prepare statement"), - QSqlError::StatementError, d->d)); + QSqlError::StatementError, d->driver->d)); return false; } - const QByteArray encQuery(fromUnicode(d->d->tc, query)); + const QByteArray encQuery(fromUnicode(d->driver->d->tc, query)); r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.length()); if (r != 0) { setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", @@ -873,7 +892,9 @@ bool QMYSQLResult::prepare(const QString& query) bool QMYSQLResult::exec() { - if (!d->d->preparedQuerys) + if (!d->driver) + return false; + if (!d->driver->d->preparedQuerys) return QSqlResult::exec(); if (!d->stmt) return false; @@ -906,6 +927,7 @@ bool QMYSQLResult::exec() nullVector[i] = static_cast<my_bool>(val.isNull()); currBind->is_null = &nullVector[i]; currBind->length = 0; + currBind->is_unsigned = 0; switch (val.type()) { case QVariant::ByteArray: @@ -952,7 +974,6 @@ bool QMYSQLResult::exec() currBind->buffer_type = MYSQL_TYPE_DOUBLE; currBind->buffer = data; currBind->buffer_length = sizeof(double); - currBind->is_unsigned = 0; break; case QVariant::LongLong: case QVariant::ULongLong: @@ -963,12 +984,11 @@ bool QMYSQLResult::exec() break; case QVariant::String: default: { - QByteArray ba = fromUnicode(d->d->tc, val.toString()); + QByteArray ba = fromUnicode(d->driver->d->tc, val.toString()); stringVector.append(ba); currBind->buffer_type = MYSQL_TYPE_STRING; currBind->buffer = const_cast<char *>(ba.constData()); currBind->buffer_length = ba.length(); - currBind->is_unsigned = 0; break; } } } @@ -1258,6 +1278,11 @@ bool QMYSQLDriver::open(const QString& db, d->preparedQuerysEnabled = false; #endif +#ifndef QT_NO_THREAD + mysql_thread_init(); +#endif + + setOpen(true); setOpenError(false); return true; @@ -1266,6 +1291,9 @@ bool QMYSQLDriver::open(const QString& db, void QMYSQLDriver::close() { if (isOpen()) { +#ifndef QT_NO_THREAD + mysql_thread_end(); +#endif mysql_close(d->mysql); d->mysql = NULL; setOpen(false); @@ -1440,7 +1468,7 @@ QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) cons QString QMYSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const { QString res = identifier; - if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('`')) && identifier.right(1) != QString(QLatin1Char('`')) ) { + if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('`')) && !identifier.endsWith(QLatin1Char('`')) ) { res.prepend(QLatin1Char('`')).append(QLatin1Char('`')); res.replace(QLatin1Char('.'), QLatin1String("`.`")); } @@ -1450,12 +1478,11 @@ QString QMYSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType bool QMYSQLDriver::isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const { Q_UNUSED(type); - bool isLeftDelimited = (identifier.left(1) == QString(QLatin1Char('`'))); - bool isRightDelimited = (identifier.right(1) == QString(QLatin1Char('`'))); - if( identifier.size() > 2 && isLeftDelimited && isRightDelimited ) - return true; - else - return false; + return identifier.size() > 2 + && identifier.startsWith(QLatin1Char('`')) //left delimited + && identifier.endsWith(QLatin1Char('`')); //right delimited } QT_END_NAMESPACE + +#include "qsql_mysql.moc"
\ No newline at end of file diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp index d63c482..e6ee63d 100644 --- a/src/sql/drivers/oci/qsql_oci.cpp +++ b/src/sql/drivers/oci/qsql_oci.cpp @@ -1789,7 +1789,7 @@ bool QOCIResult::prepare(const QString& query) bool QOCIResult::exec() { int r = 0; - ub2 stmtType; + ub2 stmtType=0; ub4 iters; ub4 mode; QList<QByteArray> tmpStorage; @@ -1803,6 +1803,16 @@ bool QOCIResult::exec() OCI_ATTR_STMT_TYPE, d->err); + if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) { + qOraWarning("QOCIResult::exec: Unable to get statement type:", d->err); + setLastError(qMakeError(QCoreApplication::translate("QOCIResult", + "Unable to get statement type"), QSqlError::StatementError, d->err)); +#ifdef QOCI_DEBUG + qDebug() << "lastQuery()" << lastQuery(); +#endif + return false; + } + if (stmtType == OCI_STMT_SELECT) { iters = 0; mode = OCI_DEFAULT; @@ -2030,8 +2040,8 @@ bool QOCIDriver::open(const QString & db, QString connectionString = db; if (!hostname.isEmpty()) connectionString = - QString(QLatin1String("(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=%1)(Port=%2))" - "(CONNECT_DATA=(SID=%3)))")).arg(hostname).arg((port > -1 ? port : 1521)).arg(db); + QString::fromLatin1("(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=%1)(Port=%2))" + "(CONNECT_DATA=(SID=%3)))").arg(hostname).arg((port > -1 ? port : 1521)).arg(db); r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->srvhp), OCI_HTYPE_SERVER, 0, 0); if (r == OCI_SUCCESS) @@ -2209,7 +2219,7 @@ QStringList QOCIDriver::tables(QSql::TableType type) const while (t.next()) { if (t.value(0).toString().toUpper() != user.toUpper()) - tl.append(t.value(0).toString() + QLatin1String(".") + t.value(1).toString()); + tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString()); else tl.append(t.value(1).toString()); } @@ -2225,7 +2235,7 @@ QStringList QOCIDriver::tables(QSql::TableType type) const "and owner != 'WMSYS'")); while (t.next()) { if (t.value(0).toString().toUpper() != d->user.toUpper()) - tl.append(t.value(0).toString() + QLatin1String(".") + t.value(1).toString()); + tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString()); else tl.append(t.value(1).toString()); } @@ -2287,7 +2297,7 @@ QSqlRecord QOCIDriver::record(const QString& tablename) const else owner = owner.toUpper(); - tmpStmt += QLatin1String(" and owner='") + owner + QLatin1String("'"); + tmpStmt += QLatin1String(" and owner='") + owner + QLatin1Char('\''); t.setForwardOnly(true); t.exec(tmpStmt); if (!t.next()) { // try and see if the tablename is a synonym @@ -2342,7 +2352,7 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const else table = table.toUpper(); - tmpStmt = stmt + QLatin1String(" and a.table_name='") + table + QLatin1String("'"); + tmpStmt = stmt + QLatin1String(" and a.table_name='") + table + QLatin1Char('\''); if (owner.isEmpty()) { owner = d->user; } @@ -2352,7 +2362,7 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const else owner = owner.toUpper(); - tmpStmt += QLatin1String(" and a.owner='") + owner + QLatin1String("'"); + tmpStmt += QLatin1String(" and a.owner='") + owner + QLatin1Char('\''); t.setForwardOnly(true); t.exec(tmpStmt); @@ -2376,7 +2386,7 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const tt.exec(QLatin1String("select data_type from all_tab_columns where table_name='") + t.value(2).toString() + QLatin1String("' and column_name='") + t.value(0).toString() + QLatin1String("' and owner='") + - owner +QLatin1String("'")); + owner + QLatin1Char('\'')); if (!tt.next()) { return QSqlIndex(); } diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp index 9932463..8eaa8bf 100644 --- a/src/sql/drivers/odbc/qsql_odbc.cpp +++ b/src/sql/drivers/odbc/qsql_odbc.cpp @@ -213,14 +213,14 @@ static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode static QString qODBCWarn(const QODBCPrivate* odbc, int *nativeCode = 0) { - return (qWarnODBCHandle(SQL_HANDLE_ENV, odbc->hEnv) + QLatin1String(" ") - + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->hDbc) + QLatin1String(" ") + return (qWarnODBCHandle(SQL_HANDLE_ENV, odbc->hEnv) + QLatin1Char(' ') + + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->hDbc) + QLatin1Char(' ') + qWarnODBCHandle(SQL_HANDLE_STMT, odbc->hStmt, nativeCode)); } static QString qODBCWarn(const QODBCDriverPrivate* odbc, int *nativeCode = 0) { - return (qWarnODBCHandle(SQL_HANDLE_ENV, odbc->hEnv) + QLatin1String(" ") + return (qWarnODBCHandle(SQL_HANDLE_ENV, odbc->hEnv) + QLatin1Char(' ') + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->hDbc, nativeCode)); } @@ -563,7 +563,6 @@ QChar QODBCDriverPrivate::quoteChar() const static QChar quote = QChar::fromLatin1('"'); if (!isQuoteInitialized) { char driverResponse[4]; - SQLUSMALLINT casing; SQLSMALLINT length; int r = SQLGetInfo(hDbc, SQL_IDENTIFIER_QUOTE_CHAR, @@ -2415,12 +2414,12 @@ QString QODBCDriver::escapeIdentifier(const QString &identifier, IdentifierType) { QString res = identifier; if (d->isMySqlServer) { - if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('`')) && identifier.right(1) != QString(QLatin1Char('`')) ) { + if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('`')) && !identifier.endsWith(QLatin1Char('`')) ) { res.prepend(QLatin1Char('`')).append(QLatin1Char('`')); res.replace(QLatin1Char('.'), QLatin1String("`.`")); } } else { - if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) { + if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) { res.replace(QLatin1Char('"'), QLatin1String("\"\"")); res.prepend(QLatin1Char('"')).append(QLatin1Char('"')); res.replace(QLatin1Char('.'), QLatin1String("\".\"")); @@ -2431,13 +2430,10 @@ QString QODBCDriver::escapeIdentifier(const QString &identifier, IdentifierType) bool QODBCDriver::isIdentifierEscapedImplementation(const QString &identifier, IdentifierType) const { - QString quote = d->quoteChar(); - bool isLeftDelimited = identifier.left(1) == quote; - bool isRightDelimited = identifier.right(1) == quote; - if( identifier.size() > 2 && isLeftDelimited && isRightDelimited ) - return true; - else - return false; + QChar quote = d->quoteChar(); + return identifier.size() > 2 + && identifier.startsWith(quote) //left delimited + && identifier.endsWith(quote); //right delimited } QT_END_NAMESPACE diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp index 16d19f1..ce0b8c5 100644 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ b/src/sql/drivers/psql/qsql_psql.cpp @@ -541,7 +541,7 @@ bool QPSQLResult::prepare(const QString &query) qDeallocatePreparedStmt(d); const QString stmtId = qMakePreparedStmtId(); - const QString stmt = QString(QLatin1String("PREPARE %1 AS ")).arg(stmtId).append(qReplacePlaceholderMarkers(query)); + const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(qReplacePlaceholderMarkers(query)); PGresult *result = PQexec(d->driver->connection, d->driver->isUtf8 ? stmt.toUtf8().constData() @@ -570,9 +570,9 @@ bool QPSQLResult::exec() QString stmt; const QString params = qCreateParamString(boundValues(), d->q->driver()); if (params.isEmpty()) - stmt = QString(QLatin1String("EXECUTE %1")).arg(d->preparedStmtId); + stmt = QString::fromLatin1("EXECUTE %1").arg(d->preparedStmtId); else - stmt = QString(QLatin1String("EXECUTE %1 (%2)")).arg(d->preparedStmtId).arg(params); + stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId).arg(params); d->result = PQexec(d->driver->connection, d->driver->isUtf8 ? stmt.toUtf8().constData() @@ -1102,12 +1102,12 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const QTime tm = field.value().toDateTime().time(); // msecs need to be right aligned otherwise psql // interpretes them wrong - r = QLatin1String("'") + QString::number(dt.year()) + QLatin1String("-") - + QString::number(dt.month()) + QLatin1String("-") - + QString::number(dt.day()) + QLatin1String(" ") - + tm.toString() + QLatin1String(".") + r = QLatin1Char('\'') + QString::number(dt.year()) + QLatin1Char('-') + + QString::number(dt.month()) + QLatin1Char('-') + + QString::number(dt.day()) + QLatin1Char(' ') + + tm.toString() + QLatin1Char('.') + QString::number(tm.msec()).rightJustified(3, QLatin1Char('0')) - + QLatin1String("'"); + + QLatin1Char('\''); } else { r = QLatin1String("NULL"); } @@ -1162,7 +1162,7 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const QString QPSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const { QString res = identifier; - if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) { + if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) { res.replace(QLatin1Char('"'), QLatin1String("\"\"")); res.prepend(QLatin1Char('"')).append(QLatin1Char('"')); res.replace(QLatin1Char('.'), QLatin1String("\".\"")); @@ -1195,7 +1195,7 @@ bool QPSQLDriver::subscribeToNotificationImplementation(const QString &name) int socket = PQsocket(d->connection); if (socket) { - QString query = QString(QLatin1String("LISTEN %1")).arg(escapeIdentifier(name, QSqlDriver::TableName)); + QString query = QLatin1String("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); if (PQresultStatus(PQexec(d->connection, d->isUtf8 ? query.toUtf8().constData() : query.toLocal8Bit().constData()) @@ -1227,7 +1227,7 @@ bool QPSQLDriver::unsubscribeFromNotificationImplementation(const QString &name) return false; } - QString query = QString(QLatin1String("UNLISTEN %1")).arg(escapeIdentifier(name, QSqlDriver::TableName)); + QString query = QLatin1String("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); if (PQresultStatus(PQexec(d->connection, d->isUtf8 ? query.toUtf8().constData() : query.toLocal8Bit().constData()) diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp index f732077..05d63ca 100644 --- a/src/sql/drivers/sqlite/qsql_sqlite.cpp +++ b/src/sql/drivers/sqlite/qsql_sqlite.cpp @@ -631,9 +631,9 @@ static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool only { QString schema; QString table(tableName); - int indexOfSeparator = tableName.indexOf(QLatin1String(".")); + int indexOfSeparator = tableName.indexOf(QLatin1Char('.')); if (indexOfSeparator > -1) { - schema = tableName.left(indexOfSeparator).append(QLatin1String(".")); + schema = tableName.left(indexOfSeparator).append(QLatin1Char('.')); table = tableName.mid(indexOfSeparator + 1); } q.exec(QLatin1String("PRAGMA ") + schema + QLatin1String("table_info ('") + table + QLatin1String("')")); diff --git a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp index d0c6e18..cb72ff0 100644 --- a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp +++ b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp @@ -170,8 +170,8 @@ void QSQLite2ResultPrivate::init(const char **cnames, int numCols) //remove quotations around the field name if any QString fieldStr = QString::fromAscii(fieldName); - QString quote = QString::fromLatin1("\""); - if ( fieldStr.length() > 2 && fieldStr.left(1) == quote && fieldStr.right(1) == quote) { + QLatin1Char quote('\"'); + if ( fieldStr.length() > 2 && fieldStr.startsWith(quote) && fieldStr.endsWith(quote)) { fieldStr = fieldStr.mid(1); fieldStr.chop(1); } @@ -561,7 +561,7 @@ QVariant QSQLite2Driver::handle() const QString QSQLite2Driver::escapeIdentifier(const QString &identifier, IdentifierType /*type*/) const { QString res = identifier; - if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) { + if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) { res.replace(QLatin1Char('"'), QLatin1String("\"\"")); res.prepend(QLatin1Char('"')).append(QLatin1Char('"')); res.replace(QLatin1Char('.'), QLatin1String("\".\"")); diff --git a/src/sql/drivers/tds/qsql_tds.cpp b/src/sql/drivers/tds/qsql_tds.cpp index 515f0de..298b008 100644 --- a/src/sql/drivers/tds/qsql_tds.cpp +++ b/src/sql/drivers/tds/qsql_tds.cpp @@ -181,7 +181,7 @@ static int CS_PUBLIC qTdsMsgHandler (DBPROCESS* dbproc, } if (severity > 0) { - QString errMsg = QString(QLatin1String("%1 (%2)")).arg(QString::fromAscii(msgtext)).arg( + QString errMsg = QString::fromLatin1("%1 (%2)").arg(QString::fromAscii(msgtext)).arg( msgstate); p->addErrorMsg(errMsg); } @@ -211,8 +211,8 @@ static int CS_PUBLIC qTdsErrHandler(DBPROCESS* dbproc, } - QString errMsg = QString(QLatin1String("%1 %2\n")).arg(QString::fromAscii(dberrstr)).arg( - QString::fromAscii(oserrstr)); + QString errMsg = QString::fromLatin1("%1 %2\n").arg(QLatin1String(dberrstr)).arg( + QLatin1String(oserrstr)); errMsg += p->getErrorMsgs(); p->lastError = qMakeError(errMsg, QSqlError::UnknownError, dberr); p->clearErrorMsgs(); diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp index 6232452..a270c0e 100644 --- a/src/sql/kernel/qsqldatabase.cpp +++ b/src/sql/kernel/qsqldatabase.cpp @@ -378,7 +378,7 @@ void QSqlDatabasePrivate::disable() the connection name argument, if you don't pass the connection name argument, the default connection is assumed. The following snippet shows how to create and open a default connection to a - MySQL database: + PostgreSQL database: \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 0 diff --git a/src/sql/kernel/qsqldriver.cpp b/src/sql/kernel/qsqldriver.cpp index 40bc0df..477d531 100644 --- a/src/sql/kernel/qsqldriver.cpp +++ b/src/sql/kernel/qsqldriver.cpp @@ -520,7 +520,7 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName, continue; s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this)).append(QLatin1String(", ")); if (preparedStatement) - vals.append(QLatin1String("?")); + vals.append(QLatin1Char('?')); else vals.append(formatValue(rec.field(i))); vals.append(QLatin1String(", ")); @@ -530,7 +530,7 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName, } else { vals.chop(2); // remove trailing comma s[s.length() - 2] = QLatin1Char(')'); - s.append(QLatin1String("VALUES (")).append(vals).append(QLatin1String(")")); + s.append(QLatin1String("VALUES (")).append(vals).append(QLatin1Char(')')); } break; } } @@ -625,10 +625,7 @@ QString QSqlDriver::formatValue(const QSqlField &field, bool trimStrings) const break; } case QVariant::Bool: - if (field.value().toBool()) - r = QLatin1String("1"); - else - r = QLatin1String("0"); + r = QString::number(field.value().toBool()); break; case QVariant::ByteArray : { if (hasFeature(BLOB)) { @@ -884,12 +881,9 @@ QStringList QSqlDriver::subscribedToNotificationsImplementation() const bool QSqlDriver::isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const { Q_UNUSED(type); - bool isLeftDelimited = identifier.left(1) == QString(QLatin1Char('"')); - bool isRightDelimited = identifier.right(1) == QString(QLatin1Char('"')); - if( identifier.size() > 2 && isLeftDelimited && isRightDelimited ) - return true; - else - return false; + return identifier.size() > 2 + && identifier.startsWith(QLatin1Char('"')) //left delimited + && identifier.endsWith(QLatin1Char('"')); //right delimited } /*! diff --git a/src/sql/kernel/qsqlerror.cpp b/src/sql/kernel/qsqlerror.cpp index 14fc050..b1fa6e2 100644 --- a/src/sql/kernel/qsqlerror.cpp +++ b/src/sql/kernel/qsqlerror.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QDebug operator<<(QDebug dbg, const QSqlError &s) { dbg.nospace() << "QSqlError(" << s.number() << ", " << s.driverText() << - ", " << s.databaseText() << ")"; + ", " << s.databaseText() << ')'; return dbg.space(); } #endif diff --git a/src/sql/kernel/qsqlfield.cpp b/src/sql/kernel/qsqlfield.cpp index 8a808b6..46a5135 100644 --- a/src/sql/kernel/qsqlfield.cpp +++ b/src/sql/kernel/qsqlfield.cpp @@ -514,8 +514,8 @@ QDebug operator<<(QDebug dbg, const QSqlField &f) if (f.typeID() >= 0) dbg.nospace() << ", typeID: " << f.typeID(); if (!f.defaultValue().isNull()) - dbg.nospace() << ", auto-value: \"" << f.defaultValue() << "\""; - dbg.nospace() << ")"; + dbg.nospace() << ", auto-value: \"" << f.defaultValue() << '\"'; + dbg.nospace() << ')'; return dbg.space(); #else qWarning("This compiler doesn't support streaming QSqlField to QDebug"); diff --git a/src/sql/kernel/qsqlquery.cpp b/src/sql/kernel/qsqlquery.cpp index e6729a5..2a07e28 100644 --- a/src/sql/kernel/qsqlquery.cpp +++ b/src/sql/kernel/qsqlquery.cpp @@ -1195,7 +1195,7 @@ void QSqlQuery::finish() The query will be repositioned on an \e invalid record in the new result set and must be navigated to a valid record before data values can be retrieved. If a new result set isn't available the - function returns false and the the query is set to inactive. In any + function returns false and the query is set to inactive. In any case the old result set will be discarded. When one of the statements is a non-select statement a count of diff --git a/src/sql/kernel/qsqlrecord.cpp b/src/sql/kernel/qsqlrecord.cpp index 0162664..95f6020 100644 --- a/src/sql/kernel/qsqlrecord.cpp +++ b/src/sql/kernel/qsqlrecord.cpp @@ -589,7 +589,7 @@ void QSqlRecord::detach() #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug dbg, const QSqlRecord &r) { - dbg << "QSqlRecord(" << r.count() << ")"; + dbg << "QSqlRecord(" << r.count() << ')'; for (int i = 0; i < r.count(); ++i) dbg << '\n' << QString::fromLatin1("%1:").arg(i, 2) << r.field(i) << r.value(i).toString(); return dbg; diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp index 12eae84..1b8fb4c 100644 --- a/src/sql/models/qsqlrelationaltablemodel.cpp +++ b/src/sql/models/qsqlrelationaltablemodel.cpp @@ -573,7 +573,7 @@ QString QSqlRelationalTableModel::selectStatement() const } // this needs fixing!! the below if is borken. - tables.append(relation.tableName().append(QLatin1String(" ")).append(relTableAlias)); + tables.append(relation.tableName().append(QLatin1Char(' ')).append(relTableAlias)); if(!where.isEmpty()) where.append(QLatin1String(" AND ")); where.append(d->relationField(tableName(), d->db.driver()->escapeIdentifier(rec.fieldName(i), QSqlDriver::FieldName))); diff --git a/src/svg/qsvggenerator.cpp b/src/svg/qsvggenerator.cpp index 2b5fbd5..d51636f 100644 --- a/src/svg/qsvggenerator.cpp +++ b/src/svg/qsvggenerator.cpp @@ -261,7 +261,7 @@ public: constantAlpha &= (stops.at(i).second.alpha() == alpha); if (!constantAlpha) { - const qreal spacing = 0.02; + const qreal spacing = qreal(0.02); QGradientStops newStops; QRgb fromColor = PREMUL(stops.at(0).second.rgba()); QRgb toColor; @@ -362,7 +362,7 @@ public: translate_dashPattern(spen.dashPattern(), penWidth, &dashPattern); // SVG uses absolute offset - dashOffset = QString::fromLatin1("%1").arg(spen.dashOffset() * penWidth); + dashOffset = QString::number(spen.dashOffset() * penWidth); d_func()->attributes.stroke = color; d_func()->attributes.strokeOpacity = colorOpacity; @@ -403,8 +403,8 @@ public: } switch (spen.joinStyle()) { case Qt::MiterJoin: - stream() << "stroke-linejoin=\"miter\" "; - stream() << "stroke-miterlimit=\""<<spen.miterLimit()<<"\" "; + stream() << "stroke-linejoin=\"miter\" " + "stroke-miterlimit=\""<<spen.miterLimit()<<"\" "; break; case Qt::BevelJoin: stream() << "stroke-linejoin=\"bevel\" "; @@ -413,8 +413,8 @@ public: stream() << "stroke-linejoin=\"round\" "; break; case Qt::SvgMiterJoin: - stream() << "stroke-linejoin=\"miter\" "; - stream() << "stroke-miterlimit=\""<<spen.miterLimit()<<"\" "; + stream() << "stroke-linejoin=\"miter\" " + "stroke-miterlimit=\""<<spen.miterLimit()<<"\" "; break; default: qWarning("Unhandled join style"); @@ -427,8 +427,8 @@ public: case Qt::SolidPattern: { QString color, colorOpacity; translate_color(sbrush.color(), &color, &colorOpacity); - stream() << "fill=\"" << color << "\" "; - stream() << "fill-opacity=\"" + stream() << "fill=\"" << color << "\" " + "fill-opacity=\"" << colorOpacity << "\" "; d_func()->attributes.fill = color; d_func()->attributes.fillOpacity = colorOpacity; @@ -493,9 +493,9 @@ public: d->attributes.font_style = d->font.italic() ? QLatin1String("italic") : QLatin1String("normal"); *d->stream << "font-family=\"" << d->attributes.font_family << "\" " - << "font-size=\"" << d->attributes.font_size << "\" " - << "font-weight=\"" << d->attributes.font_weight << "\" " - << "font-style=\"" << d->attributes.font_style << "\" " + "font-size=\"" << d->attributes.font_size << "\" " + "font-weight=\"" << d->attributes.font_weight << "\" " + "font-style=\"" << d->attributes.font_style << "\" " << endl; } }; @@ -849,13 +849,13 @@ bool QSvgPaintEngine::begin(QPaintDevice *) } if (d->viewBox.isValid()) { - *d->stream << " viewBox=\"" << d->viewBox.left() << " " << d->viewBox.top(); - *d->stream << " " << d->viewBox.width() << " " << d->viewBox.height() << "\"" << endl; + *d->stream << " viewBox=\"" << d->viewBox.left() << ' ' << d->viewBox.top(); + *d->stream << ' ' << d->viewBox.width() << ' ' << d->viewBox.height() << '\"' << endl; } *d->stream << " xmlns=\"http://www.w3.org/2000/svg\"" - << " xmlns:xlink=\"http://www.w3.org/1999/xlink\" " - << " version=\"1.2\" baseProfile=\"tiny\">" << endl; + " xmlns:xlink=\"http://www.w3.org/1999/xlink\" " + " version=\"1.2\" baseProfile=\"tiny\">" << endl; if (!d->attributes.document_title.isEmpty()) { *d->stream << "<title>" << d->attributes.document_title << "</title>" << endl; @@ -918,10 +918,10 @@ void QSvgPaintEngine::drawImage(const QRectF &r, const QImage &image, Q_UNUSED(sr); Q_UNUSED(flags); stream() << "<image "; - stream() << "x=\""<<r.x()<<"\" "; - stream() << "y=\""<<r.y()<<"\" "; - stream() << "width=\""<<r.width()<<"\" "; - stream() << "height=\""<<r.height()<<"\" "; + stream() << "x=\""<<r.x()<<"\" " + "y=\""<<r.y()<<"\" " + "width=\""<<r.width()<<"\" " + "height=\""<<r.height()<<"\" "; QByteArray data; QBuffer buffer(&data); @@ -930,8 +930,7 @@ void QSvgPaintEngine::drawImage(const QRectF &r, const QImage &image, buffer.close(); stream() << "xlink:href=\"data:image/png;base64," << data.toBase64() - <<"\" "; - stream() << "/>\n"; + <<"\" />\n"; } void QSvgPaintEngine::updateState(const QPaintEngineState &state) @@ -958,10 +957,10 @@ void QSvgPaintEngine::updateState(const QPaintEngineState &state) if (flags & QPaintEngine::DirtyTransform) { d->matrix = state.matrix(); - *d->stream << "transform=\"matrix(" << d->matrix.m11() << "," - << d->matrix.m12() << "," - << d->matrix.m21() << "," << d->matrix.m22() << "," - << d->matrix.dx() << "," << d->matrix.dy() + *d->stream << "transform=\"matrix(" << d->matrix.m11() << ',' + << d->matrix.m12() << ',' + << d->matrix.m21() << ',' << d->matrix.m22() << ',' + << d->matrix.dx() << ',' << d->matrix.dy() << ")\"" << endl; } @@ -975,7 +974,7 @@ void QSvgPaintEngine::updateState(const QPaintEngineState &state) stream() << "opacity=\""<<state.opacity()<<"\" "; } - *d->stream << ">" << endl; + *d->stream << '>' << endl; d->afterFirstUpdate = true; } @@ -984,10 +983,8 @@ void QSvgPaintEngine::drawPath(const QPainterPath &p) { Q_D(QSvgPaintEngine); - *d->stream << "<path "; - - - *d->stream << "fill-rule="; + *d->stream << "<path " + "fill-rule="; if (p.fillRule() == Qt::OddEvenFill) *d->stream << "\"evenodd\" "; else @@ -999,13 +996,13 @@ void QSvgPaintEngine::drawPath(const QPainterPath &p) const QPainterPath::Element &e = p.elementAt(i); switch (e.type) { case QPainterPath::MoveToElement: - *d->stream << "M" << e.x << "," << e.y; + *d->stream << 'M' << e.x << ',' << e.y; break; case QPainterPath::LineToElement: - *d->stream << "L" << e.x << "," << e.y; + *d->stream << 'L' << e.x << ',' << e.y; break; case QPainterPath::CurveToElement: - *d->stream << "C" << e.x << "," << e.y; + *d->stream << 'C' << e.x << ',' << e.y; ++i; while (i < p.elementCount()) { const QPainterPath::Element &e = p.elementAt(i); @@ -1013,8 +1010,8 @@ void QSvgPaintEngine::drawPath(const QPainterPath &p) --i; break; } else - *d->stream << " "; - *d->stream << e.x << "," << e.y; + *d->stream << ' '; + *d->stream << e.x << ',' << e.y; ++i; } break; @@ -1022,7 +1019,7 @@ void QSvgPaintEngine::drawPath(const QPainterPath &p) break; } if (i != p.elementCount() - 1) { - *d->stream << " "; + *d->stream << ' '; } } @@ -1044,7 +1041,7 @@ void QSvgPaintEngine::drawPolygon(const QPointF *points, int pointCount, stream() << "<polyline fill=\"none\" points=\""; for (int i = 0; i < pointCount; ++i) { const QPointF &pt = points[i]; - stream() << pt.x() << "," << pt.y() << " "; + stream() << pt.x() << ',' << pt.y() << ' '; } stream() << "\" />" <<endl; } else { @@ -1063,10 +1060,10 @@ void QSvgPaintEngine::drawTextItem(const QPointF &pt, const QTextItem &textItem) QString s = QString::fromRawData(ti.chars, ti.num_chars); *d->stream << "<text " - << "fill=\"" << d->attributes.stroke << "\" " - << "fill-opacity=\"" << d->attributes.strokeOpacity << "\" " - << "stroke=\"none\" " - << "x=\"" << pt.x() << "\" y=\"" << pt.y() << "\" "; + "fill=\"" << d->attributes.stroke << "\" " + "fill-opacity=\"" << d->attributes.strokeOpacity << "\" " + "stroke=\"none\" " + "x=\"" << pt.x() << "\" y=\"" << pt.y() << "\" "; qfontToSvg(textItem.font()); *d->stream << " >" << Qt::escape(s) diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index cb07c53..c5026b8 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -1673,10 +1673,19 @@ static void parseCSStoXMLAttrs(const QVector<QCss::Declaration> &declarations, const QCss::Declaration &decl = declarations.at(i); if (decl.d->property.isEmpty()) continue; - if (decl.d->values.count() != 1) - continue; QCss::Value val = decl.d->values.first(); - QString valueStr = val.toString(); + QString valueStr; + if (decl.d->values.count() != 1) { + for (int i=0; i<decl.d->values.count(); ++i) { + const QString &value = decl.d->values[i].toString(); + if (value.isEmpty()) + valueStr += QLatin1Char(','); + else + valueStr += value; + } + } else { + valueStr = val.toString(); + } if (val.type == QCss::Value::Uri) { valueStr.prepend(QLatin1String("url(")); valueStr.append(QLatin1Char(')')); diff --git a/src/testlib/qabstracttestlogger_p.h b/src/testlib/qabstracttestlogger_p.h index a550b3c..298fbad 100644 --- a/src/testlib/qabstracttestlogger_p.h +++ b/src/testlib/qabstracttestlogger_p.h @@ -1,4 +1,4 @@ - /**************************************************************************** +/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) diff --git a/src/testlib/qbenchmark.cpp b/src/testlib/qbenchmark.cpp index 7687fec..894296d 100644 --- a/src/testlib/qbenchmark.cpp +++ b/src/testlib/qbenchmark.cpp @@ -1,4 +1,3 @@ - /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). diff --git a/src/testlib/qbenchmark_p.h b/src/testlib/qbenchmark_p.h index 8bb6e84..b6340f8 100644 --- a/src/testlib/qbenchmark_p.h +++ b/src/testlib/qbenchmark_p.h @@ -81,7 +81,7 @@ struct QBenchmarkContext QString toString() const { - QString s = QString(QLatin1String("%1,%2,%3")).arg(slotName).arg(tag).arg(checkpointIndex); + QString s = QString::fromLatin1("%1,%2,%3").arg(slotName).arg(tag).arg(checkpointIndex); return s; } diff --git a/src/testlib/qbenchmarkvalgrind.cpp b/src/testlib/qbenchmarkvalgrind.cpp index bcce147..c61460d 100644 --- a/src/testlib/qbenchmarkvalgrind.cpp +++ b/src/testlib/qbenchmarkvalgrind.cpp @@ -133,12 +133,12 @@ QString QBenchmarkValgrindUtils::getNewestFileName() QString base = QBenchmarkGlobalData::current->callgrindOutFileBase; Q_ASSERT(!base.isEmpty()); - nameFilters << QString(QLatin1String("%1.*")).arg(base); + nameFilters << QString::fromLatin1("%1.*").arg(base); QFileInfoList fiList = QDir().entryInfoList(nameFilters, QDir::Files | QDir::Readable); Q_ASSERT(!fiList.empty()); int hiSuffix = -1; QFileInfo lastFileInfo; - const QString pattern = QString(QLatin1String("%1.(\\d+)")).arg(base); + const QString pattern = QString::fromLatin1("%1.(\\d+)").arg(base); const QRegExp rx(pattern); foreach (QFileInfo fileInfo, fiList) { const int index = rx.indexIn(fileInfo.fileName()); @@ -168,8 +168,8 @@ void QBenchmarkValgrindUtils::cleanup() QString base = QBenchmarkGlobalData::current->callgrindOutFileBase; Q_ASSERT(!base.isEmpty()); nameFilters - << QString(QLatin1String("%1")).arg(base) // overall summary - << QString(QLatin1String("%1.*")).arg(base); // individual dumps + << base // overall summary + << QString::fromLatin1("%1.*").arg(base); // individual dumps QFileInfoList fiList = QDir().entryInfoList(nameFilters, QDir::Files | QDir::Readable); foreach (QFileInfo fileInfo, fiList) { const bool removeOk = QFile::remove(fileInfo.fileName()); @@ -180,7 +180,7 @@ void QBenchmarkValgrindUtils::cleanup() QString QBenchmarkValgrindUtils::outFileBase(qint64 pid) { - return QString(QLatin1String("callgrind.out.%1")).arg( + return QString::fromLatin1("callgrind.out.%1").arg( pid != -1 ? pid : QCoreApplication::applicationPid()); } diff --git a/src/testlib/qplaintestlogger.cpp b/src/testlib/qplaintestlogger.cpp index 6f10d72..8ffdca2 100644 --- a/src/testlib/qplaintestlogger.cpp +++ b/src/testlib/qplaintestlogger.cpp @@ -216,9 +216,9 @@ namespace QTest { template <typename T> QString formatResult(T number, int significantDigits) { if (number < T(0)) - return QString(QLatin1String("NAN")); + return QLatin1String("NAN"); if (number == T(0)) - return QString(QLatin1String("0")); + return QLatin1String("0"); QString beforeDecimalPoint = QString::number(qint64(number), 'f', 0); QString afterDecimalPoint = QString::number(number, 'f', 20); diff --git a/src/testlib/qsignaldumper.cpp b/src/testlib/qsignaldumper.cpp index 0a32a6d..3a9d75e 100644 --- a/src/testlib/qsignaldumper.cpp +++ b/src/testlib/qsignaldumper.cpp @@ -87,7 +87,7 @@ static void qSignalDumperCallback(QObject *caller, int method_index, void **argv str.fill(' ', QTest::iLevel++ * QTest::IndentSpacesCount); str += "Signal: "; str += mo->className(); - str += "("; + str += '('; QString objname = caller->objectName(); str += objname.toLocal8Bit(); @@ -114,15 +114,15 @@ static void qSignalDumperCallback(QObject *caller, int method_index, void **argv str.append(QByteArray::number(addr, 16)); } else if (typeId != QMetaType::Void) { str.append(arg) - .append("(") + .append('(') .append(QVariant(typeId, argv[i + 1]).toString().toLocal8Bit()) - .append(")"); + .append(')'); } str.append(", "); } if (str.endsWith(", ")) str.chop(2); - str.append(")"); + str.append(')'); qPrintMessage(str); } @@ -143,7 +143,7 @@ static void qSignalDumperCallbackSlot(QObject *caller, int method_index, void ** str.fill(' ', QTest::iLevel * QTest::IndentSpacesCount); str += "Slot: "; str += mo->className(); - str += "("; + str += '('; QString objname = caller->objectName(); str += objname.toLocal8Bit(); diff --git a/src/testlib/qtestbasicstreamer.cpp b/src/testlib/qtestbasicstreamer.cpp index b133aae..f22b3d2 100644 --- a/src/testlib/qtestbasicstreamer.cpp +++ b/src/testlib/qtestbasicstreamer.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include "qtestbasicstreamer.h" #include "qtestlogger_p.h" #include "qtestelement.h" @@ -55,7 +96,7 @@ void QTestBasicStreamer::formatAfterAttributes(const QTestElement *element, char QTest::qt_snprintf(formatted, 10, ""); } -void QTestBasicStreamer::formatAttributes(const QTestElementAttribute *attribute, char *formatted) const +void QTestBasicStreamer::formatAttributes(const QTestElement *, const QTestElementAttribute *attribute, char *formatted) const { if(!attribute || !formatted ) return; @@ -90,7 +131,7 @@ void QTestBasicStreamer::outputElements(QTestElement *element, bool) const formatBeforeAttributes(element, buf); outputString(buf); - outputElementAttributes(element->attributes()); + outputElementAttributes(element, element->attributes()); formatAfterAttributes(element, buf); outputString(buf); @@ -105,11 +146,11 @@ void QTestBasicStreamer::outputElements(QTestElement *element, bool) const } } -void QTestBasicStreamer::outputElementAttributes(QTestElementAttribute *attribute) const +void QTestBasicStreamer::outputElementAttributes(const QTestElement* element, QTestElementAttribute *attribute) const { char buf[1024]; while(attribute){ - formatAttributes(attribute, buf); + formatAttributes(element, attribute, buf); outputString(buf); attribute = attribute->nextElement(); } diff --git a/src/testlib/qtestbasicstreamer.h b/src/testlib/qtestbasicstreamer.h index cfd6b94..527b1d4 100644 --- a/src/testlib/qtestbasicstreamer.h +++ b/src/testlib/qtestbasicstreamer.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QTESTBASICSTREAMER_H #define QTESTBASICSTREAMER_H @@ -30,9 +71,9 @@ class QTestBasicStreamer virtual void formatEnd(const QTestElement *element = 0, char *formatted = 0) const; virtual void formatBeforeAttributes(const QTestElement *element = 0, char *formatted = 0) const; virtual void formatAfterAttributes(const QTestElement *element = 0, char *formatted = 0) const; - virtual void formatAttributes(const QTestElementAttribute *attribute = 0, char *formatted = 0) const; + virtual void formatAttributes(const QTestElement *element = 0, const QTestElementAttribute *attribute = 0, char *formatted = 0) const; virtual void outputElements(QTestElement *element, bool isChildElement = false) const; - virtual void outputElementAttributes(QTestElementAttribute *attribute) const; + virtual void outputElementAttributes(const QTestElement *element, QTestElementAttribute *attribute) const; private: const QTestLogger *testLogger; diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 936b936..041f2db 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -54,6 +54,7 @@ #include <QtCore/qdir.h> #include <QtCore/qprocess.h> #include <QtCore/qdebug.h> +#include <QtCore/qlibraryinfo.h> #include "QtTest/private/qtestlog_p.h" #include "QtTest/private/qtesttable_p.h" @@ -846,9 +847,8 @@ static void qParseArgs(int argc, char *argv[]) " -iterations n : Sets the number of accumulation iterations.\n" " -median n : Sets the number of median iterations.\n" " -vb : Print out verbose benchmarking information.\n" -#ifndef QT_NO_PROCESS -// Will be enabled when tools are integrated. -// " -chart : Runs the chart generator after the test. No output is printed to the console\n" +#if !defined(QT_NO_PROCESS) || !defined(QT_NO_SETTINGS) + " -chart : Create chart based on the benchmark result.\n" #endif "\n" " -help : This help\n"; @@ -963,7 +963,7 @@ static void qParseArgs(int argc, char *argv[]) } else if (strcmp(argv[i], "-vb") == 0) { QBenchmarkGlobalData::current->verboseOutput = true; -#ifndef QT_NO_PROCESS +#if !defined(QT_NO_PROCESS) || !defined(QT_NO_SETTINGS) } else if (strcmp(argv[i], "-chart") == 0) { QBenchmarkGlobalData::current->createChart = true; QTestLog::setLogMode(QTestLog::XML); @@ -1463,26 +1463,21 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) #endif -#ifndef QT_NO_PROCESS +#if !defined(QT_NO_PROCESS) || !defined(QT_NO_SETTINGS) if (QBenchmarkGlobalData::current->createChart) { - -#define XSTR(s) STR(s) -#define STR(s) #s + QString chartLocation = QLibraryInfo::location(QLibraryInfo::BinariesPath); #ifdef Q_OS_WIN - const char * path = XSTR(QBENCHLIB_BASE) "/tools/generatereport/generatereport.exe"; + chartLocation += QLatin1String("/../tools/qtestlib/chart/release/chart.exe"); #else - const char * path = XSTR(QBENCHLIB_BASE) "/tools/generatereport/generatereport"; + chartLocation += QLatin1String("/../tools/qtestlib/chart/chart"); #endif -#undef XSTR -#undef STR - - if (QFile::exists(QLatin1String(path))) { + if (QFile::exists(chartLocation)) { QProcess p; p.setProcessChannelMode(QProcess::ForwardedChannels); - p.start(QLatin1String(path), QStringList() << QLatin1String("results.xml")); + p.start(chartLocation, QStringList() << QLatin1String("results.xml")); p.waitForFinished(-1); } else { - qWarning("Could not find %s, please make sure it is compiled.", path); + qDebug() << QLatin1String("Could not find the chart tool in ") + chartLocation + QLatin1String(", please make sure it is compiled."); } } #endif diff --git a/src/testlib/qtestcoreelement.h b/src/testlib/qtestcoreelement.h index ea05c19..4cf8fcb 100644 --- a/src/testlib/qtestcoreelement.h +++ b/src/testlib/qtestcoreelement.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QTESTCOREELEMENT_H #define QTESTCOREELEMENT_H @@ -90,7 +131,8 @@ const char *QTestCoreElement<ElementType>::elementName() const "error", "testcase", "testsuite", - "benchmark" + "benchmark", + "system-err" }; if(type != QTest::LET_Undefined) diff --git a/src/testlib/qtestcorelist.h b/src/testlib/qtestcorelist.h index 8e008a4..686e157 100644 --- a/src/testlib/qtestcorelist.h +++ b/src/testlib/qtestcorelist.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QTESTCORELIST_H #define QTESTCORELIST_H diff --git a/src/testlib/qtestelement.cpp b/src/testlib/qtestelement.cpp index 55341d4..a417360 100644 --- a/src/testlib/qtestelement.cpp +++ b/src/testlib/qtestelement.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include "qtestelement.h" QT_BEGIN_NAMESPACE diff --git a/src/testlib/qtestelement.h b/src/testlib/qtestelement.h index f5d7466..c1932da 100644 --- a/src/testlib/qtestelement.h +++ b/src/testlib/qtestelement.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QTESTELEMENT_H #define QTESTELEMENT_H diff --git a/src/testlib/qtestelementattribute.cpp b/src/testlib/qtestelementattribute.cpp index 64f9da5..540389b 100644 --- a/src/testlib/qtestelementattribute.cpp +++ b/src/testlib/qtestelementattribute.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include "qtestelementattribute.h" #include <QtCore/qbytearray.h> #include <string.h> diff --git a/src/testlib/qtestelementattribute.h b/src/testlib/qtestelementattribute.h index 2e23cd9..261f3f7 100644 --- a/src/testlib/qtestelementattribute.h +++ b/src/testlib/qtestelementattribute.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QTESTELEMENTATTRIBUTE_H #define QTESTELEMENTATTRIBUTE_H @@ -37,7 +78,8 @@ namespace QTest { LET_Error = 3, LET_TestCase = 4, LET_TestSuite = 5, - LET_Benchmark = 6 + LET_Benchmark = 6, + LET_SystemError = 7 }; } diff --git a/src/testlib/qtestfilelogger.cpp b/src/testlib/qtestfilelogger.cpp index f753b83..50741de 100644 --- a/src/testlib/qtestfilelogger.cpp +++ b/src/testlib/qtestfilelogger.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include "qtestfilelogger.h" #include "qtestassert.h" #include "QtTest/private/qtestlog_p.h" diff --git a/src/testlib/qtestfilelogger.h b/src/testlib/qtestfilelogger.h index 4dca090..892657d 100644 --- a/src/testlib/qtestfilelogger.h +++ b/src/testlib/qtestfilelogger.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QTESTFILELOGGER_H #define QTESTFILELOGGER_H diff --git a/src/testlib/qtestlightxmlstreamer.cpp b/src/testlib/qtestlightxmlstreamer.cpp index 73b33ef..75fec40 100644 --- a/src/testlib/qtestlightxmlstreamer.cpp +++ b/src/testlib/qtestlightxmlstreamer.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include "qtestlightxmlstreamer.h" #include "qtestelement.h" #include "qtestelementattribute.h" diff --git a/src/testlib/qtestlightxmlstreamer.h b/src/testlib/qtestlightxmlstreamer.h index 872eed2..382a14a 100644 --- a/src/testlib/qtestlightxmlstreamer.h +++ b/src/testlib/qtestlightxmlstreamer.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QTESTLIGHTXMLSTREAMER_H #define QTESTLIGHTXMLSTREAMER_H diff --git a/src/testlib/qtestlogger.cpp b/src/testlib/qtestlogger.cpp index c053c30..46af232 100644 --- a/src/testlib/qtestlogger.cpp +++ b/src/testlib/qtestlogger.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include "qtestlogger_p.h" #include "qtestelement.h" #include "qtestxunitstreamer.h" @@ -14,7 +55,7 @@ QT_BEGIN_NAMESPACE QTestLogger::QTestLogger(int fm) - :listOfTestcases(0), currentLogElement(0), + :listOfTestcases(0), currentLogElement(0), errorLogElement(0), logFormatter(0), format( (TestLoggerFormat)fm ), filelogger(new QTestFileLogger), testCounter(0), passCounter(0), failureCounter(0), errorCounter(0), @@ -49,6 +90,8 @@ void QTestLogger::startLogging() break; }case TLF_XunitXml:{ logFormatter = new QTestXunitStreamer; + delete errorLogElement; + errorLogElement = new QTestElement(QTest::LET_SystemError); filelogger->init(); break; } @@ -101,6 +144,8 @@ void QTestLogger::stopLogging() testcase = testcase->nextElement(); } + currentLogElement->addLogElement(errorLogElement); + QTestElement *it = currentLogElement; logFormatter->output(it); }else{ @@ -135,7 +180,7 @@ void QTestLogger::addIncident(IncidentTypes type, const char *description, switch (type) { case QAbstractTestLogger::XPass: - ++passCounter; + ++failureCounter; typeBuf = "xpass"; break; case QAbstractTestLogger::Pass: @@ -143,7 +188,7 @@ void QTestLogger::addIncident(IncidentTypes type, const char *description, typeBuf = "pass"; break; case QAbstractTestLogger::XFail: - ++failureCounter; + ++passCounter; typeBuf = "xfail"; break; case QAbstractTestLogger::Fail: @@ -155,10 +200,14 @@ void QTestLogger::addIncident(IncidentTypes type, const char *description, break; } - if (type == QAbstractTestLogger::Fail || type == QAbstractTestLogger::XFail) { + if (type == QAbstractTestLogger::Fail || type == QAbstractTestLogger::XPass + || ((format != TLF_XunitXml) && (type == QAbstractTestLogger::XFail))) { QTestElement *failureElement = new QTestElement(QTest::LET_Failure); failureElement->addAttribute(QTest::AI_Result, typeBuf); - failureElement->addAttribute(QTest::AI_File, file); + if(file) + failureElement->addAttribute(QTest::AI_File, file); + else + failureElement->addAttribute(QTest::AI_File, ""); QTest::qt_snprintf(buf, sizeof(buf), "%i", line); failureElement->addAttribute(QTest::AI_Line, buf); failureElement->addAttribute(QTest::AI_Description, description); @@ -182,10 +231,10 @@ void QTestLogger::addIncident(IncidentTypes type, const char *description, if (!strcmp(oldResult, "pass")) { overwrite = true; } - else if (!strcmp(oldResult, "xpass")) { - overwrite = (type == QAbstractTestLogger::XFail || type == QAbstractTestLogger::Fail); - } else if (!strcmp(oldResult, "xfail")) { + overwrite = (type == QAbstractTestLogger::XPass || type == QAbstractTestLogger::Fail); + } + else if (!strcmp(oldResult, "xpass")) { overwrite = (type == QAbstractTestLogger::Fail); } if (overwrite) { @@ -203,6 +252,14 @@ void QTestLogger::addIncident(IncidentTypes type, const char *description, QTest::qt_snprintf(buf, sizeof(buf), "%i", line); currentLogElement->addAttribute(QTest::AI_Line, buf); + + /* + Since XFAIL does not add a failure to the testlog in xunitxml, add a message, so we still + have some information about the expected failure. + */ + if (format == TLF_XunitXml && type == QAbstractTestLogger::XFail) { + QTestLogger::addMessage(QAbstractTestLogger::Info, description, file, line); + } } void QTestLogger::addBenchmarkResult(const QBenchmarkResult &result) @@ -273,6 +330,13 @@ void QTestLogger::addMessage(MessageTypes type, const char *message, const char currentLogElement->addLogElement(errorElement); ++errorCounter; + + // Also add the message to the system error log (i.e. stderr), if one exists + if (errorLogElement) { + QTestElement *systemErrorElement = new QTestElement(QTest::LET_Error); + systemErrorElement->addAttribute(QTest::AI_Description, message); + errorLogElement->addLogElement(systemErrorElement); + } } void QTestLogger::setLogFormat(TestLoggerFormat fm) diff --git a/src/testlib/qtestlogger_p.h b/src/testlib/qtestlogger_p.h index 3badb1d..9807fd2 100644 --- a/src/testlib/qtestlogger_p.h +++ b/src/testlib/qtestlogger_p.h @@ -1,6 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QTESTLOGGER_P_H #define QTESTLOGGER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtTest/private/qabstracttestlogger_p.h> QT_BEGIN_NAMESPACE @@ -52,6 +104,7 @@ class QTestLogger : public QAbstractTestLogger private: QTestElement *listOfTestcases; QTestElement *currentLogElement; + QTestElement *errorLogElement; QTestBasicStreamer *logFormatter; TestLoggerFormat format; QTestFileLogger *filelogger; diff --git a/src/testlib/qtestxmlstreamer.cpp b/src/testlib/qtestxmlstreamer.cpp index cf99b96..5d57bab 100644 --- a/src/testlib/qtestxmlstreamer.cpp +++ b/src/testlib/qtestxmlstreamer.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include "qtestxmlstreamer.h" #include "qtestelement.h" #include "qtestelementattribute.h" @@ -54,7 +95,7 @@ void QTestXmlStreamer::formatStart(const QTestElement *element, char *formatted) QXmlTestLogger::xmlCdata(cdataTag, element->attributeValue(QTest::AI_Tag), sizeof(cdataTag)); QTest::qt_snprintf(formatted, 1024, "<Incident type=\"%s\" %s>\n" - " <DataTag><![CDATA[%s]]></Description>\n" + " <DataTag><![CDATA[%s]]></DataTag>\n" " <Description><![CDATA[%s]]></Description>\n" "</Incident>\n", element->attributeValue(QTest::AI_Result), location, cdataTag, cdataDesc); diff --git a/src/testlib/qtestxmlstreamer.h b/src/testlib/qtestxmlstreamer.h index e6858c6..58544a4 100644 --- a/src/testlib/qtestxmlstreamer.h +++ b/src/testlib/qtestxmlstreamer.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QTESTXMLSTREAMER_H #define QTESXMLSTREAMER_H diff --git a/src/testlib/qtestxunitstreamer.cpp b/src/testlib/qtestxunitstreamer.cpp index 2d8b7c4..a34791c 100644 --- a/src/testlib/qtestxunitstreamer.cpp +++ b/src/testlib/qtestxunitstreamer.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include "qtestxunitstreamer.h" #include "qtestelement.h" @@ -40,6 +81,17 @@ void QTestXunitStreamer::formatStart(const QTestElement *element, char *formatte char indent[20]; indentForElement(element, indent, sizeof(indent)); + // Errors are written as CDATA within system-err, comments elsewhere + if (element->elementType() == QTest::LET_Error) { + if (element->parentElement()->elementType() == QTest::LET_SystemError) { + QTest::qt_snprintf(formatted, 1024, "<![CDATA["); + } + else { + QTest::qt_snprintf(formatted, 1024, "%s<!--", indent); + } + return; + } + QTest::qt_snprintf(formatted, 1024, "%s<%s", indent, element->elementName()); } @@ -59,13 +111,23 @@ void QTestXunitStreamer::formatEnd(const QTestElement *element, char *formatted) QTest::qt_snprintf(formatted, 1024, "%s</%s>\n", indent, element->elementName()); } -void QTestXunitStreamer::formatAttributes(const QTestElementAttribute *attribute, char *formatted) const +void QTestXunitStreamer::formatAttributes(const QTestElement* element, const QTestElementAttribute *attribute, char *formatted) const { if(!attribute || !formatted ) return; QTest::AttributeIndex attrindex = attribute->index(); + // For errors within system-err, we only want to output `message' + if (element && element->elementType() == QTest::LET_Error + && element->parentElement()->elementType() == QTest::LET_SystemError) { + + if (attrindex != QTest::AI_Description) return; + + QXmlTestLogger::xmlCdata(formatted, attribute->value(), 1024); + return; + } + char const* key = 0; if (attrindex == QTest::AI_Description) key = "message"; @@ -87,10 +149,21 @@ void QTestXunitStreamer::formatAfterAttributes(const QTestElement *element, char if(!element || !formatted ) return; - if(!element->childElements()) - QTest::qt_snprintf(formatted, 10, "/>\n"); - else - QTest::qt_snprintf(formatted, 10, ">\n"); + // Errors are written as CDATA within system-err, comments elsewhere + if (element->elementType() == QTest::LET_Error) { + if (element->parentElement()->elementType() == QTest::LET_SystemError) { + QTest::qt_snprintf(formatted, 1024, "]]>\n"); + } + else { + QTest::qt_snprintf(formatted, 1024, " -->\n"); + } + return; + } + + if(!element->childElements()) + QTest::qt_snprintf(formatted, 10, "/>\n"); + else + QTest::qt_snprintf(formatted, 10, ">\n"); } void QTestXunitStreamer::output(QTestElement *element) const @@ -122,7 +195,7 @@ void QTestXunitStreamer::outputElements(QTestElement *element, bool) const formatBeforeAttributes(element, buf); outputString(buf); - outputElementAttributes(element->attributes()); + outputElementAttributes(element, element->attributes()); formatAfterAttributes(element, buf); outputString(buf); diff --git a/src/testlib/qtestxunitstreamer.h b/src/testlib/qtestxunitstreamer.h index 1ce9576..b4b82f0 100644 --- a/src/testlib/qtestxunitstreamer.h +++ b/src/testlib/qtestxunitstreamer.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtTest 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QTESTXUNITSTREAMER_H #define QTESTXUNITSTREAMER_H @@ -16,7 +57,7 @@ class QTestXunitStreamer: public QTestBasicStreamer void formatStart(const QTestElement *element = 0, char *formatted = 0) const; void formatEnd(const QTestElement *element = 0, char *formatted = 0) const; void formatAfterAttributes(const QTestElement *element = 0, char *formatted = 0) const; - void formatAttributes(const QTestElementAttribute *attribute = 0, char *formatted = 0) const; + void formatAttributes(const QTestElement *element = 0, const QTestElementAttribute *attribute = 0, char *formatted = 0) const; void output(QTestElement *element) const; void outputElements(QTestElement *element, bool isChildElement = false) const; diff --git a/src/testlib/qxmltestlogger.cpp b/src/testlib/qxmltestlogger.cpp index ec9a5d2..0606ced 100644 --- a/src/testlib/qxmltestlogger.cpp +++ b/src/testlib/qxmltestlogger.cpp @@ -325,6 +325,10 @@ void QXmlTestLogger::xmlQuote(char* dest, char const* src, size_t n) MAP_ENTITY('"', """); MAP_ENTITY('&', "&"); + // not strictly necessary, but allows handling of comments without + // having to explicitly look for `--' + MAP_ENTITY('-', "-"); + #undef MAP_ENTITY case 0: diff --git a/src/tools/idc/main.cpp b/src/tools/idc/main.cpp index eb04114..8d2f0cc 100644 --- a/src/tools/idc/main.cpp +++ b/src/tools/idc/main.cpp @@ -50,8 +50,8 @@ QT_BEGIN_NAMESPACE static QString quotePath(const QString &s) { - if (!s.startsWith(QLatin1String("\"")) && s.contains(QLatin1Char(' '))) - return QLatin1String("\"") + s + QLatin1String("\""); + if (!s.startsWith(QLatin1Char('\"')) && s.contains(QLatin1Char(' '))) + return QLatin1Char('\"') + s + QLatin1Char('\"'); return s; } @@ -282,7 +282,7 @@ int runIdc(int argc, char **argv) fprintf(stderr, "Server unregistered successfully!\n"); return 0; } else if (p[0] == QLatin1Char('/') || p[0] == QLatin1Char('-')) { - error = QLatin1String("Unknown option \"") + p + QLatin1String("\""); + error = QLatin1String("Unknown option \"") + p + QLatin1Char('\"'); break; } else { input = QLatin1String(argv[i]); diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index ae8a76e..e94bb77 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -1161,8 +1161,8 @@ void Generator::_generateFunctions(QList<FunctionDef> &list, int type) for (int j = 0; j < f.arguments.count(); ++j) { const ArgumentDef &a = f.arguments.at(j); if (j) { - sig += ","; - arguments += ","; + sig += ','; + arguments += ','; } sig += a.normalizedType; arguments += a.name; diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index a6a0ba1..8ca2823 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -752,14 +752,14 @@ void Moc::generate(FILE *out) if (!noInclude) { - if (includePath.size() && includePath.right(1) != "/") - includePath += "/"; + if (includePath.size() && !includePath.endsWith('/')) + includePath += '/'; for (int i = 0; i < includeFiles.size(); ++i) { QByteArray inc = includeFiles.at(i); if (inc[0] != '<' && inc[0] != '"') { if (includePath.size() && includePath != "./") inc.prepend(includePath); - inc = "\"" + inc + "\""; + inc = '\"' + inc + '\"'; } fprintf(out, "#include %s\n", inc.constData()); } diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp index 45cbbfd..3260ca2 100644 --- a/src/tools/moc/preprocessor.cpp +++ b/src/tools/moc/preprocessor.cpp @@ -807,7 +807,7 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed) continue; QByteArray frameworkCandidate = include.left(slashPos); frameworkCandidate.append(".framework/Headers/"); - fi.setFile(QString::fromLocal8Bit(p.path + "/" + frameworkCandidate), QString::fromLocal8Bit(include.mid(slashPos + 1))); + fi.setFile(QString::fromLocal8Bit(p.path + '/' + frameworkCandidate), QString::fromLocal8Bit(include.mid(slashPos + 1))); } else { fi.setFile(QString::fromLocal8Bit(p.path), QString::fromLocal8Bit(include)); } diff --git a/src/tools/uic/cpp/cppwriteicondata.cpp b/src/tools/uic/cpp/cppwriteicondata.cpp index 53b108f..08d552d 100644 --- a/src/tools/uic/cpp/cppwriteicondata.cpp +++ b/src/tools/uic/cpp/cppwriteicondata.cpp @@ -161,9 +161,9 @@ void WriteIconData::writeImage(QTextStream &output, const QString &indent, DomIm for (a = 0; a < (int) (data.length()/2)-1; a++) { output << "0x" << QString(data[2*a]) << QString(data[2*a+1]) << ','; if (a % 12 == 11) - output << "\n" << indent; + output << '\n' << indent; else - output << " "; + output << ' '; } output << "0x" << QString(data[2*a]) << QString(data[2*a+1]) << '\n'; output << "};\n\n"; diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp index 47566ad..5a2f487 100644 --- a/src/tools/uic/cpp/cppwriteinitialization.cpp +++ b/src/tools/uic/cpp/cppwriteinitialization.cpp @@ -2813,7 +2813,7 @@ QString WriteInitialization::Item::writeSetupUi(const QString &parent, Item::Emp bool generateMultiDirective = false; if (emptyItemPolicy == Item::ConstructItemOnly && m_children.size() == 0) { if (m_setupUiData.policy == ItemData::DontGenerate) { - m_setupUiStream << m_indent << "new " << m_itemClassName << "(" << parent << ");\n"; + m_setupUiStream << m_indent << "new " << m_itemClassName << '(' << parent << ");\n"; return QString(); } else if (m_setupUiData.policy == ItemData::GenerateWithMultiDirective) { generateMultiDirective = true; @@ -2824,11 +2824,11 @@ QString WriteInitialization::Item::writeSetupUi(const QString &parent, Item::Emp generateMultiDirectiveBegin(m_setupUiStream, m_setupUiData.directives); const QString uniqueName = m_driver->unique(QLatin1String("__") + m_itemClassName.toLower()); - m_setupUiStream << m_indent << m_itemClassName << " *" << uniqueName << " = new " << m_itemClassName << "(" << parent << ");\n"; + m_setupUiStream << m_indent << m_itemClassName << " *" << uniqueName << " = new " << m_itemClassName << '(' << parent << ");\n"; if (generateMultiDirective) { m_setupUiStream << "#else\n"; - m_setupUiStream << m_indent << "new " << m_itemClassName << "(" << parent << ");\n"; + m_setupUiStream << m_indent << "new " << m_itemClassName << '(' << parent << ");\n"; generateMultiDirectiveEnd(m_setupUiStream, m_setupUiData.directives); } diff --git a/src/tools/uic3/embed.cpp b/src/tools/uic3/embed.cpp index 882328a..b406c1f 100644 --- a/src/tools/uic3/embed.cpp +++ b/src/tools/uic3/embed.cpp @@ -238,7 +238,7 @@ void Ui3Reader::embed(const char *project, const QStringList &images) out << "true, "; else out << "false, "; - out << "\"" << e->name << "\" },\n"; + out << '\"' << e->name << "\" },\n"; delete e; } #ifndef QT_NO_IMAGE_COLLECTION_COMPRESSION diff --git a/src/tools/uic3/form.cpp b/src/tools/uic3/form.cpp index d9e968b..b484210 100644 --- a/src/tools/uic3/form.cpp +++ b/src/tools/uic3/form.cpp @@ -185,14 +185,14 @@ void Ui3Reader::createFormDecl(const QDomElement &e, bool implicitIncludes) for (it = globalIncludes.constBegin(); it != globalIncludes.constEnd(); ++it) { if (!(*it).isEmpty()) { QString header = fixHeaderName(*it); - out << "#include <" << header << ">" << endl; + out << "#include <" << header << '>' << endl; } } localIncludes = unique(localIncludes); for (it = localIncludes.constBegin(); it != localIncludes.constEnd(); ++it) { if (!(*it).isEmpty()) { QString header = fixHeaderName(*it); - out << "#include \"" << header << "\"" << endl; + out << "#include \"" << header << '\"' << endl; } } out << endl; @@ -216,7 +216,7 @@ void Ui3Reader::createFormDecl(const QDomElement &e, bool implicitIncludes) typeDefs = unique(typeDefs); for (it = typeDefs.constBegin(); it != typeDefs.constEnd(); ++it) { if (!(*it).isEmpty()) - out << "typedef " << *it << ";" << endl; + out << "typedef " << *it << ';' << endl; } nl = e.parentNode().toElement().elementsByTagName(QLatin1String("forward")); @@ -236,17 +236,17 @@ void Ui3Reader::createFormDecl(const QDomElement &e, bool implicitIncludes) out << "namespace " << *ns << " {" << endl; ++ns; } - out << "class " << forwardName << ";" << endl; + out << "class " << forwardName << ';' << endl; for (int i = 0; i < (int) forwardNamespaces.count(); i++) - out << "}" << endl; + out << '}' << endl; } } for (it = forwardDecl2.constBegin(); it != forwardDecl2.constEnd(); ++it) { QString fd = *it; fd = fd.trimmed(); - if (!fd.endsWith(QLatin1String(";"))) - fd += QLatin1String(";"); + if (!fd.endsWith(QLatin1Char(';'))) + fd += QLatin1Char(';'); out << fd << endl; } @@ -279,7 +279,7 @@ void Ui3Reader::createWrapperDecl(const QDomElement &e, const QString &converted out << "#ifndef " << protector << endl; out << "#define " << protector << endl; out << endl; - out << "#include \"" << convertedUiFile << "\"" << endl; + out << "#include \"" << convertedUiFile << '\"' << endl; createWrapperDeclContents(e); out << endl; @@ -309,8 +309,8 @@ void Ui3Reader::createWrapperDeclContents(const QDomElement &e) out << "class "; if (!exportMacro.isEmpty()) - out << exportMacro << " "; - out << bareNameOfClass << " : public " << objClass << ", public Ui::" << bareNameOfClass << endl << "{" << endl; + out << exportMacro << ' '; + out << bareNameOfClass << " : public " << objClass << ", public Ui::" << bareNameOfClass << endl << '{' << endl; /* qmake ignore Q_OBJECT */ out << " Q_OBJECT" << endl; @@ -362,8 +362,8 @@ void Ui3Reader::createWrapperDeclContents(const QDomElement &e) continue; QString returnType = n.attribute(QLatin1String("returnType"), QLatin1String("void")); QString functionName = n.firstChild().toText().data().trimmed(); - if (functionName.endsWith(QLatin1String(";"))) - functionName = functionName.left(functionName.length() - 1); + if (functionName.endsWith(QLatin1Char(';'))) + functionName.chop(1); QString specifier = n.attribute(QLatin1String("specifier")); QString access = n.attribute(QLatin1String("access")); if (access == QLatin1String(QLatin1String("protected"))) { @@ -394,8 +394,8 @@ void Ui3Reader::createWrapperDeclContents(const QDomElement &e) continue; QString returnType = n.attribute(QLatin1String("returnType"), QLatin1String("void")); QString functionName = n.firstChild().toText().data().trimmed(); - if (functionName.endsWith(QLatin1String(";"))) - functionName = functionName.left(functionName.length() - 1); + if (functionName.endsWith(QLatin1Char(';'))) + functionName.chop(1); QString specifier = n.attribute(QLatin1String("specifier")); QString access = n.attribute(QLatin1String("access")); if (access == QLatin1String("protected")) { @@ -423,8 +423,8 @@ void Ui3Reader::createWrapperDeclContents(const QDomElement &e) // continue; QString access = n.attribute(QLatin1String("access"), QLatin1String("protected")); QString var = fixDeclaration(n.firstChild().toText().data().trimmed()); - if (!var.endsWith(QLatin1String(";"))) - var += QLatin1String(";"); + if (!var.endsWith(QLatin1Char(';'))) + var += QLatin1Char(';'); if (access == QLatin1String("public")) publicVars += var; else if (access == QLatin1String("private")) @@ -458,7 +458,7 @@ void Ui3Reader::createWrapperDeclContents(const QDomElement &e) if (n.attribute(QLatin1String("language"), QLatin1String("C++")) != QLatin1String("C++")) continue; QString sigName = n.firstChild().toText().data().trimmed(); - if (sigName.endsWith(QLatin1String(";"))) + if (sigName.endsWith(QLatin1Char(';'))) sigName = sigName.left(sigName.length() - 1); extraSignals += fixDeclaration(sigName); } @@ -467,7 +467,7 @@ void Ui3Reader::createWrapperDeclContents(const QDomElement &e) if (!extraSignals.isEmpty()) { out << "signals:" << endl; for (it = extraSignals.constBegin(); it != extraSignals.constEnd(); ++it) - out << " void " << (*it) << ";" << endl; + out << " void " << (*it) << ';' << endl; out << endl; } @@ -513,7 +513,7 @@ void Ui3Reader::createWrapperDeclContents(const QDomElement &e) out << "};" << endl; for (i = 0; i < (int) namespaces.count(); i++) - out << "}" << endl; + out << '}' << endl; out << endl; } @@ -543,7 +543,7 @@ void Ui3Reader::writeFunctionsDecl(const QStringList &fuLst, const QStringList & signature = fixDeclaration(signature); type = fixType(type); - out << " " << specifier << type << " " << signature << pure << ";" << endl; + out << " " << specifier << type << ' ' << signature << pure << ';' << endl; } out << endl; } @@ -583,8 +583,8 @@ void Ui3Reader::createFormImpl(const QDomElement &e) if (n.attribute(QLatin1String("language"), QLatin1String("C++")) != QLatin1String("C++")) continue; QString functionName = n.firstChild().toText().data().trimmed(); - if (functionName.endsWith(QLatin1String(";"))) - functionName = functionName.left(functionName.length() - 1); + if (functionName.endsWith(QLatin1Char(';'))) + functionName.chop(1); extraFuncts += functionName; extraFunctTyp += n.attribute(QLatin1String("returnType"), QLatin1String("void")); extraFunctSpecifier += n.attribute(QLatin1String("specifier"), QLatin1String("virtual")); @@ -598,8 +598,8 @@ void Ui3Reader::createFormImpl(const QDomElement &e) if (n.attribute(QLatin1String("language"), QLatin1String("C++")) != QLatin1String("C++")) continue; QString functionName = n.firstChild().toText().data().trimmed(); - if (functionName.endsWith(QLatin1String(";"))) - functionName = functionName.left(functionName.length() - 1); + if (functionName.endsWith(QLatin1Char(';'))) + functionName.chop(1); extraFuncts += functionName; extraFunctTyp += n.attribute(QLatin1String("returnType"), QLatin1String("void")); extraFunctSpecifier += n.attribute(QLatin1String("specifier"), QLatin1String("virtual")); @@ -663,7 +663,7 @@ void Ui3Reader::createFormImpl(const QDomElement &e) globalIncludes = unique(globalIncludes); for (it = globalIncludes.begin(); it != globalIncludes.end(); ++it) { if (!(*it).isEmpty()) - out << "#include <" << fixHeaderName(*it) << ">" << endl; + out << "#include <" << fixHeaderName(*it) << '>' << endl; } if (externPixmaps) { @@ -677,14 +677,14 @@ void Ui3Reader::createFormImpl(const QDomElement &e) localIncludes = unique(localIncludes); for (it = localIncludes.begin(); it != localIncludes.end(); ++it) { if (!(*it).isEmpty() && *it != QFileInfo(fileName + QLatin1String(".h")).fileName()) - out << "#include \"" << fixHeaderName(*it) << "\"" << endl; + out << "#include \"" << fixHeaderName(*it) << '\"' << endl; } QString uiDotH = fileName + QLatin1String(".h"); if (QFile::exists(uiDotH)) { if (!outputFileName.isEmpty()) uiDotH = QString::fromUtf8(combinePath(uiDotH.ascii(), outputFileName.ascii())); - out << "#include \"" << uiDotH << "\"" << endl; + out << "#include \"" << uiDotH << '\"' << endl; writeFunctImpl = false; } @@ -702,7 +702,7 @@ void Ui3Reader::createFormImpl(const QDomElement &e) out << " * name 'name' and widget flags set to 'f'." << endl; out << " *" << endl; out << " * The " << objClass.mid(1).toLower() << " will by default be modeless, unless you set 'modal' to" << endl; - out << " * true to construct a modal " << objClass.mid(1).toLower() << "." << endl; + out << " * true to construct a modal " << objClass.mid(1).toLower() << '.' << endl; out << " */" << endl; out << nameOfClass << "::" << bareNameOfClass << "(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl)" << endl; out << " : " << objClass << "(parent, name, modal, fl)"; @@ -733,7 +733,7 @@ void Ui3Reader::createFormImpl(const QDomElement &e) out << endl; - out << "{" << endl; + out << '{' << endl; // // setup the gui @@ -775,7 +775,7 @@ void Ui3Reader::createFormImpl(const QDomElement &e) out << indent << "init();" << endl; // end of constructor - out << "}" << endl; + out << '}' << endl; out << endl; // destructor @@ -783,11 +783,11 @@ void Ui3Reader::createFormImpl(const QDomElement &e) out << " * Destroys the object and frees any allocated resources" << endl; out << " */" << endl; out << nameOfClass << "::~" << bareNameOfClass << "()" << endl; - out << "{" << endl; + out << '{' << endl; if (extraFuncts.contains(QLatin1String("destroy()"))) out << indent << "destroy();" << endl; out << indent << "// no need to delete child widgets, Qt does it all for us" << endl; - out << "}" << endl; + out << '}' << endl; out << endl; // handle application events if required @@ -816,9 +816,9 @@ void Ui3Reader::createFormImpl(const QDomElement &e) out << " * language." << endl; out << " */" << endl; out << "void " << nameOfClass << "::languageChange()" << endl; - out << "{" << endl; + out << '{' << endl; out << " retranslateUi(this);" << endl; - out << "}" << endl; + out << '}' << endl; out << endl; // create stubs for additional slots if necessary @@ -833,8 +833,8 @@ void Ui3Reader::createFormImpl(const QDomElement &e) type = type.simplified(); QString fname = fixDeclaration(Parser::cleanArgs(*it)); if (!(*it3).startsWith(QLatin1String("pure"))) { // "pure virtual" or "pureVirtual" - out << type << " " << nameOfClass << "::" << fname << endl; - out << "{" << endl; + out << type << ' ' << nameOfClass << "::" << fname << endl; + out << '{' << endl; if (*it != QLatin1String("init()") && *it != QLatin1String("destroy()")) { QRegExp numeric(QLatin1String("^(?:signed|unsigned|u?char|u?short|u?int" "|u?long|Q_U?INT(?:8|16|32)|Q_U?LONG|float" @@ -868,14 +868,14 @@ void Ui3Reader::createFormImpl(const QDomElement &e) if (type == QLatin1String("bool")) { retVal = QLatin1String("false"); - } else if (isBasicNumericType || type.endsWith(QLatin1String("*"))) { + } else if (isBasicNumericType || type.endsWith(QLatin1Char('*'))) { retVal = QLatin1String("0"); - } else if (type.endsWith(QLatin1String("&"))) { + } else if (type.endsWith(QLatin1Char('&'))) { do { type.chop(1); - } while (type.endsWith(QLatin1String(" "))); + } while (type.endsWith(QLatin1Char(' '))); retVal = QLatin1String("uic_temp_var"); - out << indent << "static " << type << " " << retVal << ";" << endl; + out << indent << "static " << type << ' ' << retVal << ';' << endl; } else { retVal = type + QLatin1String("()"); } @@ -883,9 +883,9 @@ void Ui3Reader::createFormImpl(const QDomElement &e) out << indent << "qWarning(\"" << nameOfClass << "::" << fname << ": Not implemented yet\");" << endl; if (!retVal.isEmpty()) - out << indent << "return " << retVal << ";" << endl; + out << indent << "return " << retVal << ';' << endl; } - out << "}" << endl; + out << '}' << endl; out << endl; } ++it; diff --git a/src/tools/uic3/main.cpp b/src/tools/uic3/main.cpp index d581016..9535b91 100644 --- a/src/tools/uic3/main.cpp +++ b/src/tools/uic3/main.cpp @@ -367,7 +367,7 @@ int runUic3(int argc, char * argv[]) } if (headerFile) { - out << "#include \"" << headerFile << "\"" << endl << endl; + out << "#include \"" << headerFile << '\"' << endl << endl; } QString convertedUi; diff --git a/src/tools/uic3/parser.cpp b/src/tools/uic3/parser.cpp index 744dd30..395cc4d 100644 --- a/src/tools/uic3/parser.cpp +++ b/src/tools/uic3/parser.cpp @@ -48,14 +48,14 @@ QT_BEGIN_NAMESPACE QString Parser::cleanArgs(const QString &func) { QString slot(func); - int begin = slot.indexOf(QLatin1String("(")) + 1; + int begin = slot.indexOf(QLatin1Char('(')) + 1; QString args = slot.mid(begin); - args = args.left(args.indexOf(QLatin1String(")"))); + args = args.left(args.indexOf(QLatin1Char(')'))); QStringList lst = args.split(QLatin1Char(',')); QString res = slot.left(begin); for (QStringList::Iterator it = lst.begin(); it != lst.end(); ++it) { if (it != lst.begin()) - res += QLatin1String(","); + res += QLatin1Char(','); QString arg = *it; int pos = 0; if ((pos = arg.indexOf(QLatin1Char('&'))) != -1) { @@ -65,7 +65,7 @@ QString Parser::cleanArgs(const QString &func) } else { arg = arg.simplified(); if ((pos = arg.indexOf(QLatin1Char(':'))) != -1) - arg = arg.left(pos).simplified() + QLatin1String(":") + arg.mid(pos + 1).simplified(); + arg = arg.left(pos).simplified() + QLatin1Char(':') + arg.mid(pos + 1).simplified(); QStringList l = arg.split(QLatin1Char(' ')); if (l.count() == 2) { if (l[0] != QLatin1String("const") @@ -73,12 +73,12 @@ QString Parser::cleanArgs(const QString &func) && l[0] != QLatin1String("var")) arg = l[0]; } else if (l.count() == 3) { - arg = l[0] + QLatin1String(" ") + l[1]; + arg = l[0] + QLatin1Char(' ') + l[1]; } } res += arg; } - res += QLatin1String(")"); + res += QLatin1Char(')'); return res; } diff --git a/src/tools/uic3/qt3to4.cpp b/src/tools/uic3/qt3to4.cpp index 9e5b64b..2862727 100644 --- a/src/tools/uic3/qt3to4.cpp +++ b/src/tools/uic3/qt3to4.cpp @@ -149,7 +149,7 @@ void Porting::readXML(RuleList *renamedHeaders, RuleList *renamedClasses, RuleLi QString fileName = QLatin1String("q3porting.xml"); QString filePath; //check QLibraryInfo::DataPath/filename - filePath = QDir::cleanPath(QLibraryInfo::location(QLibraryInfo::DataPath) + QLatin1String("/") + fileName) ; + filePath = QDir::cleanPath(QLibraryInfo::location(QLibraryInfo::DataPath) + QLatin1Char('/') + fileName) ; //check QLibraryInfo::PrefixPath/tools/porting/src/filename if (!QFile::exists(filePath)) diff --git a/src/tools/uic3/subclassing.cpp b/src/tools/uic3/subclassing.cpp index e590ab7..85c2218 100644 --- a/src/tools/uic3/subclassing.cpp +++ b/src/tools/uic3/subclassing.cpp @@ -69,7 +69,7 @@ void Ui3Reader::createSubDecl( const QDomElement &e, const QString& subClass ) return; out << "class " << subClass << " : public " << nameOfClass << endl; - out << "{" << endl; + out << '{' << endl; /* tmake ignore Q_OBJECT */ out << " Q_OBJECT" << endl; @@ -105,8 +105,8 @@ void Ui3Reader::createSubDecl( const QDomElement &e, const QString& subClass ) continue; QString returnType = n.attribute(QLatin1String("returnType"), QLatin1String("void")); QString functionName = n.firstChild().toText().data().trimmed(); - if ( functionName.endsWith(QLatin1String(";"))) - functionName = functionName.left( functionName.length() - 1 ); + if ( functionName.endsWith(QLatin1Char(';'))) + functionName.chop(1); QString specifier = n.attribute(QLatin1String("specifier")); QString access = n.attribute(QLatin1String("access")); if ( access == QLatin1String("protected") ) { @@ -133,8 +133,8 @@ void Ui3Reader::createSubDecl( const QDomElement &e, const QString& subClass ) continue; QString returnType = n.attribute(QLatin1String("returnType"), QLatin1String("void")); QString functionName = n.firstChild().toText().data().trimmed(); - if ( functionName.endsWith(QLatin1String(";")) ) - functionName = functionName.left( functionName.length() - 1 ); + if ( functionName.endsWith(QLatin1Char(';')) ) + functionName.chop(1); QString specifier = n.attribute(QLatin1String("specifier")); QString access = n.attribute(QLatin1String("access")); if ( access == QLatin1String("protected") ) { @@ -195,7 +195,7 @@ void Ui3Reader::writeFunctionsSubDecl( const QStringList &fuLst, const QStringLi type = QLatin1String("void"); if ( *it3 == QLatin1String("non virtual") ) continue; - out << " " << type << " " << fixDeclaration(*it) << ";" << endl; + out << " " << type << ' ' << fixDeclaration(*it) << ';' << endl; } out << endl; } @@ -223,7 +223,7 @@ void Ui3Reader::createSubImpl( const QDomElement &e, const QString& subClass ) out << " * name 'name' and widget flags set to 'f' " << endl; out << " *" << endl; out << " * The " << objClass.mid(1).toLower() << " will by default be modeless, unless you set 'modal' to" << endl; - out << " * true to construct a modal " << objClass.mid(1).toLower() << "." << endl; + out << " * true to construct a modal " << objClass.mid(1).toLower() << '.' << endl; out << " */" << endl; out << subClass << "::" << subClass << "( QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl )" << endl; out << " : " << nameOfClass << "( parent, name, modal, fl )" << endl; @@ -235,8 +235,8 @@ void Ui3Reader::createSubImpl( const QDomElement &e, const QString& subClass ) out << subClass << "::" << subClass << "( QWidget* parent, const char* name, Qt::WindowFlags fl )" << endl; out << " : " << nameOfClass << "( parent, name, fl )" << endl; } - out << "{" << endl; - out << "}" << endl; + out << '{' << endl; + out << '}' << endl; out << endl; // destructor @@ -244,9 +244,9 @@ void Ui3Reader::createSubImpl( const QDomElement &e, const QString& subClass ) out << " * Destroys the object and frees any allocated resources" << endl; out << " */" << endl; out << subClass << "::~" << subClass << "()" << endl; - out << "{" << endl; + out << '{' << endl; out << " // no need to delete child widgets, Qt does it all for us" << endl; - out << "}" << endl; + out << '}' << endl; out << endl; @@ -268,8 +268,8 @@ void Ui3Reader::createSubImpl( const QDomElement &e, const QString& subClass ) continue; QString returnType = n.attribute(QLatin1String("returnType"), QLatin1String("void")); QString functionName = n.firstChild().toText().data().trimmed(); - if ( functionName.endsWith(QLatin1String(";")) ) - functionName = functionName.left( functionName.length() - 1 ); + if ( functionName.endsWith(QLatin1Char(';')) ) + functionName.chop(1); QString specifier = n.attribute(QLatin1String("specifier")); QString access = n.attribute(QLatin1String("access")); if ( access == QLatin1String("protected") ) { @@ -296,8 +296,8 @@ void Ui3Reader::createSubImpl( const QDomElement &e, const QString& subClass ) continue; QString returnType = n.attribute(QLatin1String("returnType"), QLatin1String("void")); QString functionName = n.firstChild().toText().data().trimmed(); - if ( functionName.endsWith(QLatin1String(";")) ) - functionName = functionName.left( functionName.length() - 1 ); + if ( functionName.endsWith(QLatin1Char(';')) ) + functionName.chop(1); QString specifier = n.attribute(QLatin1String("specifier")); QString access = n.attribute(QLatin1String("access")); if ( access == QLatin1String("protected") ) { @@ -351,10 +351,10 @@ void Ui3Reader::writeFunctionsSubImpl( const QStringList &fuLst, const QStringLi out << "/*" << endl; out << " * " << descr << endl; out << " */" << endl; - out << type << " " << subClass << "::" << fixDeclaration(*it) << endl; - out << "{" << endl; + out << type << ' ' << subClass << "::" << fixDeclaration(*it) << endl; + out << '{' << endl; out << " qWarning( \"" << subClass << "::" << fixDeclaration(*it) << " not yet implemented!\" );" << endl; - out << "}" << endl << endl; + out << '}' << endl << endl; } out << endl; } diff --git a/src/tools/uic3/ui3reader.cpp b/src/tools/uic3/ui3reader.cpp index 1ba4b2f..539565c 100644 --- a/src/tools/uic3/ui3reader.cpp +++ b/src/tools/uic3/ui3reader.cpp @@ -125,10 +125,10 @@ QString Ui3Reader::fixString(const QString &str, bool encode) QString s; if (!encode) { s = str; - s.replace(QLatin1String("\\"), QLatin1String("\\\\")); - s.replace(QLatin1String("\""), QLatin1String("\\\"")); - s.replace(QLatin1String("\r"), QLatin1String("")); - s.replace(QLatin1String("\n"), QLatin1String("\\n\"\n\"")); + s.replace(QLatin1Char('\\'), QLatin1String("\\\\")); + s.replace(QLatin1Char('\"'), QLatin1String("\\\"")); + s.remove(QLatin1Char('\r')); + s.replace(QLatin1Char('\n'), QLatin1String("\\n\"\n\"")); } else { QByteArray utf8 = str.utf8(); const int l = utf8.length(); @@ -136,7 +136,7 @@ QString Ui3Reader::fixString(const QString &str, bool encode) s += QLatin1String("\\x") + QString::number((uchar)utf8[i], 16); } - return QLatin1String("\"") + s + QLatin1String("\""); + return QLatin1Char('\"') + s + QLatin1Char('\"'); } QString Ui3Reader::trcall(const QString& sourceText, const QString& comment) @@ -158,12 +158,12 @@ QString Ui3Reader::trcall(const QString& sourceText, const QString& comment) } if (comment.isEmpty()) { - return t + QLatin1String("(") + fixString(sourceText, encode) + QLatin1String(")"); + return t + QLatin1Char('(') + fixString(sourceText, encode) + QLatin1Char(')'); } else { - return t + QLatin1String("(") + return t + QLatin1Char('(') + fixString(sourceText, encode) + QLatin1String(", ") - + fixString(comment, encode) + QLatin1String(")"); + + fixString(comment, encode) + QLatin1Char(')'); } } @@ -480,10 +480,10 @@ void Ui3Reader::createColorGroupImpl(const QString& name, const QDomElement& e) QString pixmap = n.firstChild().toText().data(); if (!pixmapLoaderFunction.isEmpty()) { pixmap.prepend(pixmapLoaderFunction - + QLatin1String("(") + + QLatin1Char('(') + QLatin1String(externPixmaps ? "\"" : "")); - pixmap.append(QLatin1String(externPixmaps ? "\"" : "") + QLatin1String(")")); + pixmap.append(QLatin1String(externPixmaps ? "\"" : "") + QLatin1Char(')')); } out << indent << name << ".setBrush(QColorGroup::" << ColorRole[r] << ", QBrush(" << color << ", " << pixmap << "));" << endl; @@ -578,9 +578,9 @@ QString Ui3Reader::registerObject(const QString& name) if (objectNames.contains(result)) { int i = 2; - while (objectNames.contains(result + QLatin1String("_") + QString::number(i))) + while (objectNames.contains(result + QLatin1Char('_') + QString::number(i))) i++; - result += QLatin1String("_"); + result += QLatin1Char('_'); result += QString::number(i); } objectNames += result; diff --git a/src/winmain/qtmain_win.cpp b/src/winmain/qtmain_win.cpp index a3bc0e0..e5b3259 100644 --- a/src/winmain/qtmain_win.cpp +++ b/src/winmain/qtmain_win.cpp @@ -100,7 +100,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR /*cmdPara #if defined(Q_OS_WINCE) TCHAR appName[256]; GetModuleFileName(0, appName, 255); - cmdParam = QString(QLatin1String("\"%1\" ")).arg(QString::fromUtf16((const unsigned short *)appName)).toLocal8Bit() + cmdParam; + cmdParam.prepend(QString::fromLatin1("\"%1\" ").arg(QString::fromUtf16((const unsigned short *)appName)).toLocal8Bit()); #endif int argc = 0; @@ -110,7 +110,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR /*cmdPara #if defined(Q_OS_WINCE) TCHAR uniqueAppID[256]; GetModuleFileName(0, uniqueAppID, 255); - QString uid = QString::fromUtf16((const unsigned short *)uniqueAppID).toLower().replace(QString(QLatin1String("\\")), QString(QLatin1String("_"))); + QString uid = QString::fromUtf16((const unsigned short *)uniqueAppID).toLower().replace(QLatin1Char('\\'), QLatin1Char('_')); // If there exists an other instance of this application // it will be the owner of a mutex with the unique ID. diff --git a/src/xml/dom/qdom.cpp b/src/xml/dom/qdom.cpp index 550abc9..da0e31b 100644 --- a/src/xml/dom/qdom.cpp +++ b/src/xml/dom/qdom.cpp @@ -2694,7 +2694,7 @@ void QDomNode::save(QTextStream& str, int indent) const If the document contains invalid XML characters or characters that cannot be encoded in the given encoding, the result and behavior is undefined. - \since 4.2 + \since 4.2 */ void QDomNode::save(QTextStream& str, int indent, EncodingPolicy encodingPolicy) const { @@ -4589,7 +4589,7 @@ void QDomElementPrivate::save(QTextStream& s, int depth, int indent) const qName = prefix + QLatin1Char(':') + name; nsDecl = QLatin1String(" xmlns:") + prefix; } - nsDecl += QLatin1String("=\"") + encodeText(namespaceURI, s) + QLatin1String("\""); + nsDecl += QLatin1String("=\"") + encodeText(namespaceURI, s) + QLatin1Char('\"'); } s << '<' << qName << nsDecl; @@ -4597,9 +4597,9 @@ void QDomElementPrivate::save(QTextStream& s, int depth, int indent) const /* Write out attributes. */ if (!m_attr->map.isEmpty()) { - s << ' '; QHash<QString, QDomNodePrivate *>::const_iterator it = m_attr->map.constBegin(); for (; it != m_attr->map.constEnd(); ++it) { + s << ' '; if (it.value()->namespaceURI.isNull()) { s << it.value()->name << "=\"" << encodeText(it.value()->value, s, true, true) << '\"'; } else { @@ -4622,7 +4622,6 @@ void QDomElementPrivate::save(QTextStream& s, int depth, int indent) const outputtedPrefixes.insert(it.value()->prefix); } } - s << ' '; } } diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp index c78d4ba..db50f01 100644 --- a/src/xml/sax/qxml.cpp +++ b/src/xml/sax/qxml.cpp @@ -2107,7 +2107,7 @@ events are reported. You can set the lexical handler with QXmlReader::setLexicalHandler(). - This interface's design is based on the the SAX2 extension + This interface's design is based on the SAX2 extension LexicalHandler. The interface provides the startDTD(), endDTD(), startEntity(), @@ -5464,7 +5464,7 @@ bool QXmlSimpleReaderPrivate::parsePEReference() if (skipIt) { if (contentHnd) { - if (!contentHnd->skippedEntity(QString::fromLatin1("%") + ref())) { + if (!contentHnd->skippedEntity(QLatin1Char('%') + ref())) { reportParseError(contentHnd->errorString()); return false; } @@ -5476,7 +5476,7 @@ bool QXmlSimpleReaderPrivate::parsePEReference() return false; } else if (parsePEReference_context == InDTD) { // Included as PE - if (!insertXmlRef(QString::fromLatin1(" ")+xmlRefString+QString::fromLatin1(" "), ref(), false)) + if (!insertXmlRef(QLatin1Char(' ') + xmlRefString + QLatin1Char(' '), ref(), false)) return false; } } @@ -6728,7 +6728,7 @@ bool QXmlSimpleReaderPrivate::parseEntityDecl() if ( !entityExist(name())) { parameterEntities.insert(name(), string()); if (declHnd) { - if (!declHnd->internalEntityDecl(QString::fromLatin1("%")+name(), string())) { + if (!declHnd->internalEntityDecl(QLatin1Char('%') + name(), string())) { reportParseError(declHnd->errorString()); return false; } @@ -6740,7 +6740,7 @@ bool QXmlSimpleReaderPrivate::parseEntityDecl() if ( !entityExist(name())) { externParameterEntities.insert(name(), QXmlSimpleReaderPrivate::ExternParameterEntity(publicId, systemId)); if (declHnd) { - if (!declHnd->externalEntityDecl(QString::fromLatin1("%")+name(), publicId, systemId)) { + if (!declHnd->externalEntityDecl(QLatin1Char('%') + name(), publicId, systemId)) { reportParseError(declHnd->errorString()); return false; } @@ -7864,8 +7864,8 @@ bool QXmlSimpleReaderPrivate::insertXmlRef(const QString &data, const QString &n { if (inLiteral) { QString tmp = data; - xmlRefStack.push(XmlRef(name, tmp.replace(QLatin1String("\""), - QLatin1String(""")).replace(QLatin1String("'"), QLatin1String("'")))); + xmlRefStack.push(XmlRef(name, tmp.replace(QLatin1Char('\"'), + QLatin1String(""")).replace(QLatin1Char('\''), QLatin1String("'")))); } else { xmlRefStack.push(XmlRef(name, data)); } diff --git a/src/xmlpatterns/acceltree/qacceltree.cpp b/src/xmlpatterns/acceltree/qacceltree.cpp index 60e6e27..6bc1794 100644 --- a/src/xmlpatterns/acceltree/qacceltree.cpp +++ b/src/xmlpatterns/acceltree/qacceltree.cpp @@ -71,7 +71,7 @@ void AccelTree::printStats(const NamePool::Ptr &np) const for(int i = 0; i < len; ++i) { const BasicNodeData &v = basicData.at(i); - pDebug() << "|" << i + pDebug() << '|' << i << "\t\t|" << v.depth() << "\t|" << v.size() << "\t|" << postNumber(i) @@ -81,12 +81,12 @@ void AccelTree::printStats(const NamePool::Ptr &np) const : data.value(i)) << "\t|"; /* - pDebug() << "|" << QString().arg(i, 14) - << "|" << QString().arg(v.depth(), 6) - << "|" << QString().arg(v.size(), 6) - << "|" << QString().arg(postNumber(i), 14) - << "|" << QString().arg(v.kind(), 6) - << "|"; + pDebug() << '|' << QString().arg(i, 14) + << '|' << QString().arg(v.depth(), 6) + << '|' << QString().arg(v.size(), 6) + << '|' << QString().arg(postNumber(i), 14) + << '|' << QString().arg(v.kind(), 6) + << '|'; */ } pDebug() << "+---------------+-------+-------+---------------+-------+--------------+"; diff --git a/src/xmlpatterns/api/qsourcelocation.cpp b/src/xmlpatterns/api/qsourcelocation.cpp index 4eee39c..1dd8ffd 100644 --- a/src/xmlpatterns/api/qsourcelocation.cpp +++ b/src/xmlpatterns/api/qsourcelocation.cpp @@ -206,7 +206,7 @@ QDebug operator<<(QDebug debug, const QSourceLocation &sourceLocation) << sourceLocation.line() << ", column:" << sourceLocation.column() - << ")"; + << ')'; return debug; } #endif diff --git a/src/xmlpatterns/data/qabstractfloat.cpp b/src/xmlpatterns/data/qabstractfloat.cpp index b6226b5..a45b0fd 100644 --- a/src/xmlpatterns/data/qabstractfloat.cpp +++ b/src/xmlpatterns/data/qabstractfloat.cpp @@ -186,7 +186,7 @@ QString AbstractFloat<isDouble>::stringValue() const if(sign) valueAsString += QLatin1Char('-'); - valueAsString += qret.left(1); + valueAsString += qret.at(0); valueAsString += QLatin1Char('.'); if(1 == qret.size()) diff --git a/src/xmlpatterns/data/qcommonvalues.cpp b/src/xmlpatterns/data/qcommonvalues.cpp index 07a273d..99a8086 100644 --- a/src/xmlpatterns/data/qcommonvalues.cpp +++ b/src/xmlpatterns/data/qcommonvalues.cpp @@ -57,7 +57,7 @@ using namespace QPatternist; // STATIC DATA const AtomicString::Ptr CommonValues::EmptyString - (new AtomicString(QString(QLatin1String("")))); + (new AtomicString(QLatin1String(""))); const AtomicString::Ptr CommonValues::TrueString (new AtomicString(QLatin1String("true"))); const AtomicString::Ptr CommonValues::FalseString diff --git a/src/xmlpatterns/expr/qapplytemplate.cpp b/src/xmlpatterns/expr/qapplytemplate.cpp index 95f4fdf..b91c2f0 100644 --- a/src/xmlpatterns/expr/qapplytemplate.cpp +++ b/src/xmlpatterns/expr/qapplytemplate.cpp @@ -160,8 +160,7 @@ Item::Iterator::Ptr ApplyTemplate::evaluateSequence(const DynamicContext::Ptr &c focus->setFocusIterator(focusIterator); return makeSequenceMappingIterator<Item>(ConstPtr(this), focusIterator, focus); } - else - return CommonValues::emptyIterator; + return CommonValues::emptyIterator; } } diff --git a/src/xmlpatterns/expr/qexpression_p.h b/src/xmlpatterns/expr/qexpression_p.h index 5eb63de..65918e6 100644 --- a/src/xmlpatterns/expr/qexpression_p.h +++ b/src/xmlpatterns/expr/qexpression_p.h @@ -884,7 +884,7 @@ namespace QPatternist { pDebug() << "AST REWRITE:" << old.data() << "to" << New.data() << '(' << old->actualReflection() << "to" << New->actualReflection() << ", " - << old->description() << "to" << New->description() << ")"; + << old->description() << "to" << New->description() << ')'; /* The order of these two lines is significant.. */ context->addLocation(New.data(), context->locationFor(old->actualReflection())); diff --git a/src/xmlpatterns/expr/qpath.cpp b/src/xmlpatterns/expr/qpath.cpp index 33bfa0f..a60f622 100644 --- a/src/xmlpatterns/expr/qpath.cpp +++ b/src/xmlpatterns/expr/qpath.cpp @@ -170,7 +170,7 @@ Expression::Ptr Path::compress(const StaticContext::Ptr &context) /* We do this as late as we can, such that we pick up the most recent type * from the operand. */ - if(m_isLast && !m_kind == XSLTForEach && m_operand2->staticType()->itemType() == BuiltinTypes::item) + if(m_isLast && m_kind != XSLTForEach && m_operand2->staticType()->itemType() == BuiltinTypes::item) m_checkXPTY0018 = true; return me; diff --git a/src/xmlpatterns/expr/qxsltsimplecontentconstructor.cpp b/src/xmlpatterns/expr/qxsltsimplecontentconstructor.cpp index ef77c76..104c5cc 100644 --- a/src/xmlpatterns/expr/qxsltsimplecontentconstructor.cpp +++ b/src/xmlpatterns/expr/qxsltsimplecontentconstructor.cpp @@ -105,7 +105,7 @@ Item XSLTSimpleContentConstructor::evaluateSingleton(const DynamicContext::Ptr & QString result; bool previousIsText = false; - bool discard; + bool discard = false; if(next) { diff --git a/src/xmlpatterns/functions/qsequencefns.cpp b/src/xmlpatterns/functions/qsequencefns.cpp index f6d5391..faa787e 100644 --- a/src/xmlpatterns/functions/qsequencefns.cpp +++ b/src/xmlpatterns/functions/qsequencefns.cpp @@ -246,8 +246,7 @@ Item::Iterator::Ptr SubsequenceFN::evaluateSequence(const DynamicContext::Ptr &c if(length < 1 && length != -1) return CommonValues::emptyIterator; - else - return Item::Iterator::Ptr(new SubsequenceIterator(it, startingLoc, length)); + return Item::Iterator::Ptr(new SubsequenceIterator(it, startingLoc, length)); } Item SubsequenceFN::evaluateSingleton(const DynamicContext::Ptr &context) const |