From 76bcd00f74b0977b5f6ce12295aae987ea9ad4c1 Mon Sep 17 00:00:00 2001 From: aavit Date: Fri, 5 Feb 2010 12:04:38 +0100 Subject: Performance: Use QImage's smoothscaling instead of old private code For historical reasons, QJpegHandler had its own smoothscaling code. QImage's scaling has since evolved to become both faster and better, so avoid code duplication and just use QImage for scaling. Reviewed-by: Trond --- src/plugins/imageformats/jpeg/qjpeghandler.cpp | 574 +++---------------------- 1 file changed, 67 insertions(+), 507 deletions(-) diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index 6cb93ad..4b4712c 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -52,8 +52,6 @@ #undef FAR #endif -// hw: optimize smoothscaler for returning 24-bit images - // including jpeglib.h seems to be a little messy extern "C" { // mingw includes rpcndr.h but does not define boolean @@ -76,433 +74,6 @@ extern "C" { QT_BEGIN_NAMESPACE -//#define QT_NO_IMAGE_SMOOTHSCALE -#ifndef QT_NO_IMAGE_SMOOTHSCALE -class QImageSmoothScalerPrivate; -class QImageSmoothScaler -{ -public: - QImageSmoothScaler(const int w, const int h, const QImage &src); - QImageSmoothScaler(const int srcWidth, const int srcHeight, - const int dstWidth, const int dstHeight); - - virtual ~QImageSmoothScaler(void); - - QImage scale(); - -private: - QImageSmoothScalerPrivate *d; - virtual QRgb *scanLine(const int line = 0, const QImage *src = 0); -}; - -class QImageSmoothScalerPrivate -{ -public: - int cols; - int newcols; - int rows; - int newrows; - bool hasAlpha; - - const QImage *src; - - void setup(const int srcWidth, const int srcHeight, const int dstWidth, - const int dstHeight, bool hasAlphaChannel); -}; - -QImageSmoothScaler::QImageSmoothScaler(const int w, const int h, - const QImage &src) -{ - d = new QImageSmoothScalerPrivate; - - d->setup(src.width(), src.height(), w, h, src.hasAlphaChannel() ); - this->d->src = &src; -} - -QImageSmoothScaler::QImageSmoothScaler(const int srcWidth, const int srcHeight, - const int dstWidth, const int dstHeight) -{ - d = new QImageSmoothScalerPrivate; - d->setup(srcWidth, srcHeight, dstWidth, dstHeight, 0); -} - -void QImageSmoothScalerPrivate::setup(const int srcWidth, const int srcHeight, - const int dstWidth, const int dstHeight, - bool hasAlphaChannel) -{ - cols = srcWidth; - rows = srcHeight; - newcols = dstWidth; - newrows = dstHeight; - hasAlpha = hasAlphaChannel; -} - -QImageSmoothScaler::~QImageSmoothScaler() -{ - delete d; -} - -inline QRgb *QImageSmoothScaler::scanLine(const int line, const QImage *src) -{ - return (QRgb*)src->scanLine(line); -} - -/* - This function uses code based on pnmscale.c by Jef Poskanzer. - - pnmscale.c - read a portable anymap and scale it - - Copyright (C) 1989, 1991 by Jef Poskanzer. - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose and without fee is hereby granted, provided - that the above copyright notice appear in all copies and that both that - copyright notice and this permission notice appear in supporting - documentation. This software is provided "as is" without express or - implied warranty. -*/ - -QImage QImageSmoothScaler::scale() -{ - long SCALE; - long HALFSCALE; - QRgb *xelrow = 0; - QRgb *tempxelrow = 0; - QRgb *xP; - QRgb *nxP; - int row, rowsread; - int col, needtoreadrow; - uchar maxval = 255; - qreal xscale, yscale; - long sxscale, syscale; - long fracrowtofill, fracrowleft; - long *as; - long *rs; - long *gs; - long *bs; - int rowswritten = 0; - QImage dst; - - if (d->cols > 4096) { - SCALE = 4096; - HALFSCALE = 2048; - } else { - int fac = 4096; - while (d->cols * fac > 4096) - fac /= 2; - - SCALE = fac * d->cols; - HALFSCALE = fac * d->cols / 2; - } - - xscale = (qreal)d->newcols / (qreal)d->cols; - yscale = (qreal)d->newrows / (qreal)d->rows; - sxscale = (long)(xscale * SCALE); - syscale = (long)(yscale * SCALE); - - // shortcut Y scaling if possible - if (d->newrows != d->rows) - tempxelrow = new QRgb[d->cols]; - - if (d->hasAlpha) { - as = new long[d->cols]; - for (col = 0; col < d->cols; ++col) - as[col] = HALFSCALE; - } else { - as = 0; - } - rs = new long[d->cols]; - gs = new long[d->cols]; - bs = new long[d->cols]; - rowsread = 0; - fracrowleft = syscale; - needtoreadrow = 1; - for (col = 0; col < d->cols; ++col) - rs[col] = gs[col] = bs[col] = HALFSCALE; - fracrowtofill = SCALE; - - dst = QImage(d->newcols, d->newrows, d->hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32); - - for (row = 0; row < d->newrows; ++row) { - // First scale Y from xelrow into tempxelrow. - if (d->newrows == d->rows) { - // shortcut Y scaling if possible - tempxelrow = xelrow = scanLine(rowsread++, d->src); - } else { - while (fracrowleft < fracrowtofill) { - if (needtoreadrow && rowsread < d->rows) - xelrow = scanLine(rowsread++, d->src); - for (col = 0, xP = xelrow; col < d->cols; ++col, ++xP) { - if (as) { - as[col] += fracrowleft * qAlpha(*xP); - rs[col] += fracrowleft * qRed(*xP) * qAlpha(*xP) / 255; - gs[col] += fracrowleft * qGreen(*xP) * qAlpha(*xP) / 255; - bs[col] += fracrowleft * qBlue(*xP) * qAlpha(*xP) / 255; - } else { - rs[col] += fracrowleft * qRed(*xP); - gs[col] += fracrowleft * qGreen(*xP); - bs[col] += fracrowleft * qBlue(*xP); - } - } - fracrowtofill -= fracrowleft; - fracrowleft = syscale; - needtoreadrow = 1; - } - // Now fracrowleft is >= fracrowtofill, so we can produce a row. - if (needtoreadrow && rowsread < d->rows) { - xelrow = scanLine(rowsread++, d->src); - needtoreadrow = 0; - } - for (col = 0, xP = xelrow, nxP = tempxelrow; col < d->cols; ++col, ++xP, ++nxP) { - register long a, r, g, b; - - if (as) { - r = rs[col] + fracrowtofill * qRed(*xP) * qAlpha(*xP) / 255; - g = gs[col] + fracrowtofill * qGreen(*xP) * qAlpha(*xP) / 255; - b = bs[col] + fracrowtofill * qBlue(*xP) * qAlpha(*xP) / 255; - a = as[col] + fracrowtofill * qAlpha(*xP); - if (a) { - r = r * 255 / a * SCALE; - g = g * 255 / a * SCALE; - b = b * 255 / a * SCALE; - } - } else { - r = rs[col] + fracrowtofill * qRed(*xP); - g = gs[col] + fracrowtofill * qGreen(*xP); - b = bs[col] + fracrowtofill * qBlue(*xP); - a = 0; // unwarn - } - r /= SCALE; - if (r > maxval) - r = maxval; - g /= SCALE; - if (g > maxval) - g = maxval; - b /= SCALE; - if (b > maxval) - b = maxval; - if (as) { - a /= SCALE; - if (a > maxval) - a = maxval; - *nxP = qRgba((int)r, (int)g, (int)b, (int)a); - as[col] = HALFSCALE; - } else { - *nxP = qRgb((int)r, (int)g, (int)b); - } - rs[col] = gs[col] = bs[col] = HALFSCALE; - } - fracrowleft -= fracrowtofill; - if (fracrowleft == 0) { - fracrowleft = syscale; - needtoreadrow = 1; - } - fracrowtofill = SCALE; - } - - // Now scale X from tempxelrow into dst and write it out. - if (d->newcols == d->cols) { - // shortcut X scaling if possible - memcpy(dst.scanLine(rowswritten++), tempxelrow, d->newcols * 4); - } else { - register long a, r, g, b; - register long fraccoltofill, fraccolleft = 0; - register int needcol; - - nxP = (QRgb *)dst.scanLine(rowswritten++); - QRgb *nxPEnd = nxP + d->newcols; - fraccoltofill = SCALE; - a = r = g = b = HALFSCALE; - needcol = 0; - for (col = 0, xP = tempxelrow; col < d->cols; ++col, ++xP) { - fraccolleft = sxscale; - while (fraccolleft >= fraccoltofill) { - if (needcol) { - ++nxP; - a = r = g = b = HALFSCALE; - } - if (as) { - r += fraccoltofill * qRed(*xP) * qAlpha(*xP) / 255; - g += fraccoltofill * qGreen(*xP) * qAlpha(*xP) / 255; - b += fraccoltofill * qBlue(*xP) * qAlpha(*xP) / 255; - a += fraccoltofill * qAlpha(*xP); - if (a) { - r = r * 255 / a * SCALE; - g = g * 255 / a * SCALE; - b = b * 255 / a * SCALE; - } - } else { - r += fraccoltofill * qRed(*xP); - g += fraccoltofill * qGreen(*xP); - b += fraccoltofill * qBlue(*xP); - } - r /= SCALE; - if (r > maxval) - r = maxval; - g /= SCALE; - if (g > maxval) - g = maxval; - b /= SCALE; - if (b > maxval) - b = maxval; - if (as) { - a /= SCALE; - if (a > maxval) - a = maxval; - *nxP = qRgba((int)r, (int)g, (int)b, (int)a); - } else { - *nxP = qRgb((int)r, (int)g, (int)b); - } - fraccolleft -= fraccoltofill; - fraccoltofill = SCALE; - needcol = 1; - } - if (fraccolleft > 0) { - if (needcol) { - ++nxP; - a = r = g = b = HALFSCALE; - needcol = 0; - } - if (as) { - a += fraccolleft * qAlpha(*xP); - r += fraccolleft * qRed(*xP) * qAlpha(*xP) / 255; - g += fraccolleft * qGreen(*xP) * qAlpha(*xP) / 255; - b += fraccolleft * qBlue(*xP) * qAlpha(*xP) / 255; - } else { - r += fraccolleft * qRed(*xP); - g += fraccolleft * qGreen(*xP); - b += fraccolleft * qBlue(*xP); - } - fraccoltofill -= fraccolleft; - } - } - if (fraccoltofill > 0) { - --xP; - if (as) { - a += fraccolleft * qAlpha(*xP); - r += fraccoltofill * qRed(*xP) * qAlpha(*xP) / 255; - g += fraccoltofill * qGreen(*xP) * qAlpha(*xP) / 255; - b += fraccoltofill * qBlue(*xP) * qAlpha(*xP) / 255; - if (a) { - r = r * 255 / a * SCALE; - g = g * 255 / a * SCALE; - b = b * 255 / a * SCALE; - } - } else { - r += fraccoltofill * qRed(*xP); - g += fraccoltofill * qGreen(*xP); - b += fraccoltofill * qBlue(*xP); - } - } - if (nxP < nxPEnd) { - r /= SCALE; - if (r > maxval) - r = maxval; - g /= SCALE; - if (g > maxval) - g = maxval; - b /= SCALE; - if (b > maxval) - b = maxval; - if (as) { - a /= SCALE; - if (a > maxval) - a = maxval; - *nxP = qRgba((int)r, (int)g, (int)b, (int)a); - } else { - *nxP = qRgb((int)r, (int)g, (int)b); - } - while (++nxP != nxPEnd) - nxP[0] = nxP[-1]; - } - } - } - - if (d->newrows != d->rows && tempxelrow)// Robust, tempxelrow might be 0 1 day - delete [] tempxelrow; - if (as) // Avoid purify complaint - delete [] as; - if (rs) // Robust, rs might be 0 one day - delete [] rs; - if (gs) // Robust, gs might be 0 one day - delete [] gs; - if (bs) // Robust, bs might be 0 one day - delete [] bs; - - return dst; -} - -class jpegSmoothScaler : public QImageSmoothScaler -{ -public: - jpegSmoothScaler(struct jpeg_decompress_struct *info, const QSize& dstSize, const QRect& clipRect) - : QImageSmoothScaler(clipRect.width(), clipRect.height(), - dstSize.width(), dstSize.height()) - { - cinfo = info; - clip = clipRect; - imageCache = QImage(info->output_width, 1, QImage::Format_RGB32); - } - -private: - QRect clip; - QImage imageCache; - struct jpeg_decompress_struct *cinfo; - - QRgb *scanLine(const int line = 0, const QImage *src = 0) - { - QRgb *out; - uchar *in; - - Q_UNUSED(line); - Q_UNUSED(src); - - uchar* data = imageCache.bits(); - - // Read ahead if we haven't reached the first clipped scanline yet. - while (int(cinfo->output_scanline) < clip.y() && - cinfo->output_scanline < cinfo->output_height) - jpeg_read_scanlines(cinfo, &data, 1); - - // Read the next scanline. We assume that "line" - // will never be >= clip.height(). - jpeg_read_scanlines(cinfo, &data, 1); - if (cinfo->output_scanline == cinfo->output_height) - jpeg_finish_decompress(cinfo); - - out = ((QRgb*)data) + clip.x(); - - // - // The smooth scale algorithm only works on 32-bit images; - // convert from (8|24) bits to 32. - // - if (cinfo->output_components == 1) { - in = data + clip.right(); - for (int i = clip.width(); i--; ) { - out[i] = qRgb(*in, *in, *in); - in--; - } - } else if (cinfo->out_color_space == JCS_CMYK) { - in = data + clip.right() * 4; - for (int i = clip.width(); i--; ) { - int k = in[3]; - out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255); - in -= 4; - } - } else { - in = data + clip.right() * 3; - for (int i = clip.width(); i--; ) { - out[i] = qRgb(in[0], in[1], in[2]); - in -= 3; - } - } - - return out; - } - -}; -#endif - struct my_error_mgr : public jpeg_error_mgr { jmp_buf setjmp_buffer; }; @@ -844,93 +415,82 @@ static bool read_jpeg_image(QIODevice *device, QImage *outImage, clip = clip.intersected(imageRect); } -#ifndef QT_NO_IMAGE_SMOOTHSCALE - if (scaledSize.isValid() && scaledSize != clip.size() - && quality >= HIGH_QUALITY_THRESHOLD) { + // Allocate memory for the clipped QImage. + if (!ensureValidImage(outImage, &cinfo, clip.size())) + longjmp(jerr.setjmp_buffer, 1); + + // Avoid memcpy() overhead if grayscale with no clipping. + bool quickGray = (cinfo.output_components == 1 && + clip == imageRect); + if (!quickGray) { + // Ask the jpeg library to allocate a temporary row. + // The library will automatically delete it for us later. + // The libjpeg docs say we should do this before calling + // jpeg_start_decompress(). We can't use "new" here + // because we are inside the setjmp() block and an error + // in the jpeg input stream would cause a memory leak. + JSAMPARRAY rows = (cinfo.mem->alloc_sarray) + ((j_common_ptr)&cinfo, JPOOL_IMAGE, + cinfo.output_width * cinfo.output_components, 1); (void) jpeg_start_decompress(&cinfo); - jpegSmoothScaler scaler(&cinfo, scaledSize, clip); - *outImage = scaler.scale(); - } else -#endif - { - // Allocate memory for the clipped QImage. - if (!ensureValidImage(outImage, &cinfo, clip.size())) - longjmp(jerr.setjmp_buffer, 1); - - // Avoid memcpy() overhead if grayscale with no clipping. - bool quickGray = (cinfo.output_components == 1 && - clip == imageRect); - if (!quickGray) { - // Ask the jpeg library to allocate a temporary row. - // The library will automatically delete it for us later. - // The libjpeg docs say we should do this before calling - // jpeg_start_decompress(). We can't use "new" here - // because we are inside the setjmp() block and an error - // in the jpeg input stream would cause a memory leak. - JSAMPARRAY rows = (cinfo.mem->alloc_sarray) - ((j_common_ptr)&cinfo, JPOOL_IMAGE, - cinfo.output_width * cinfo.output_components, 1); - - (void) jpeg_start_decompress(&cinfo); - - while (cinfo.output_scanline < cinfo.output_height) { - int y = int(cinfo.output_scanline) - clip.y(); - if (y >= clip.height()) - break; // We've read the entire clip region, so abort. - - (void) jpeg_read_scanlines(&cinfo, rows, 1); - - if (y < 0) - continue; // Haven't reached the starting line yet. - - if (cinfo.output_components == 3) { - // Expand 24->32 bpp. - uchar *in = rows[0] + clip.x() * 3; - QRgb *out = (QRgb*)outImage->scanLine(y); - for (int i = 0; i < clip.width(); ++i) { - *out++ = qRgb(in[0], in[1], in[2]); - in += 3; - } - } else if (cinfo.out_color_space == JCS_CMYK) { - // Convert CMYK->RGB. - uchar *in = rows[0] + clip.x() * 4; - QRgb *out = (QRgb*)outImage->scanLine(y); - for (int i = 0; i < clip.width(); ++i) { - int k = in[3]; - *out++ = qRgb(k * in[0] / 255, k * in[1] / 255, - k * in[2] / 255); - in += 4; - } - } else if (cinfo.output_components == 1) { - // Grayscale. - memcpy(outImage->scanLine(y), - rows[0] + clip.x(), clip.width()); + while (cinfo.output_scanline < cinfo.output_height) { + int y = int(cinfo.output_scanline) - clip.y(); + if (y >= clip.height()) + break; // We've read the entire clip region, so abort. + + (void) jpeg_read_scanlines(&cinfo, rows, 1); + + if (y < 0) + continue; // Haven't reached the starting line yet. + + if (cinfo.output_components == 3) { + // Expand 24->32 bpp. + uchar *in = rows[0] + clip.x() * 3; + QRgb *out = (QRgb*)outImage->scanLine(y); + for (int i = 0; i < clip.width(); ++i) { + *out++ = qRgb(in[0], in[1], in[2]); + in += 3; } - } - } else { - // Load unclipped grayscale data directly into the QImage. - (void) jpeg_start_decompress(&cinfo); - while (cinfo.output_scanline < cinfo.output_height) { - uchar *row = outImage->scanLine(cinfo.output_scanline); - (void) jpeg_read_scanlines(&cinfo, &row, 1); + } else if (cinfo.out_color_space == JCS_CMYK) { + // Convert CMYK->RGB. + uchar *in = rows[0] + clip.x() * 4; + QRgb *out = (QRgb*)outImage->scanLine(y); + for (int i = 0; i < clip.width(); ++i) { + int k = in[3]; + *out++ = qRgb(k * in[0] / 255, k * in[1] / 255, + k * in[2] / 255); + in += 4; + } + } else if (cinfo.output_components == 1) { + // Grayscale. + memcpy(outImage->scanLine(y), + rows[0] + clip.x(), clip.width()); } } + } else { + // Load unclipped grayscale data directly into the QImage. + (void) jpeg_start_decompress(&cinfo); + while (cinfo.output_scanline < cinfo.output_height) { + uchar *row = outImage->scanLine(cinfo.output_scanline); + (void) jpeg_read_scanlines(&cinfo, &row, 1); + } + } - if (cinfo.output_scanline == cinfo.output_height) - (void) jpeg_finish_decompress(&cinfo); + if (cinfo.output_scanline == cinfo.output_height) + (void) jpeg_finish_decompress(&cinfo); - if (cinfo.density_unit == 1) { - outImage->setDotsPerMeterX(int(100. * cinfo.X_density / 2.54)); - outImage->setDotsPerMeterY(int(100. * cinfo.Y_density / 2.54)); - } else if (cinfo.density_unit == 2) { - outImage->setDotsPerMeterX(int(100. * cinfo.X_density)); - outImage->setDotsPerMeterY(int(100. * cinfo.Y_density)); - } + if (cinfo.density_unit == 1) { + outImage->setDotsPerMeterX(int(100. * cinfo.X_density / 2.54)); + outImage->setDotsPerMeterY(int(100. * cinfo.Y_density / 2.54)); + } else if (cinfo.density_unit == 2) { + outImage->setDotsPerMeterX(int(100. * cinfo.X_density)); + outImage->setDotsPerMeterY(int(100. * cinfo.Y_density)); + } - if (scaledSize.isValid() && scaledSize != clip.size()) - *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::FastTransformation); + if (scaledSize.isValid() && scaledSize != clip.size()) { + *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, quality >= HIGH_QUALITY_THRESHOLD ? Qt::SmoothTransformation : Qt::FastTransformation); } } -- cgit v0.12 From 5f6456d420a762cf935271c9329178ad7112c4a1 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 8 Feb 2010 18:58:02 +1000 Subject: XMLHttpRequest collection bug QmlXMLHttpRequest was holding a reference to the callback function indefinately. If the callback function also referenced the XMLHttpRequest (which they always do) the QmlXMLHttpRequest would not be destroyed until the application exited. --- src/declarative/qml/qmlxmlhttprequest.cpp | 90 +++++++++++++++---------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/declarative/qml/qmlxmlhttprequest.cpp b/src/declarative/qml/qmlxmlhttprequest.cpp index 86bec20..1883d1b 100644 --- a/src/declarative/qml/qmlxmlhttprequest.cpp +++ b/src/declarative/qml/qmlxmlhttprequest.cpp @@ -943,21 +943,19 @@ public: QmlXMLHttpRequest(QNetworkAccessManager *manager); virtual ~QmlXMLHttpRequest(); - QScriptValue callback() const; - void setCallback(const QScriptValue &); - bool sendFlag() const; bool errorFlag() const; quint32 readyState() const; int replyStatus() const; QString replyStatusText() const; - QScriptValue open(const QString &, const QUrl &); + QScriptValue open(QScriptValue *me, const QString &, const QUrl &); + void addHeader(const QString &, const QString &); QString header(const QString &name); QString headers(); - QScriptValue send(const QByteArray &); - QScriptValue abort(); + QScriptValue send(QScriptValue *me, const QByteArray &); + QScriptValue abort(QScriptValue *me); QString responseBody() const; private slots: @@ -982,8 +980,9 @@ private: HeadersList m_headersList; void fillHeadersList(); - QScriptValue dispatchCallback(); - QScriptValue m_callback; + QScriptValue m_me; // Set to the data object while a send() is ongoing (to access the callback) + + QScriptValue dispatchCallback(QScriptValue *me); void printError(const QScriptValue&); int m_status; @@ -1007,16 +1006,6 @@ QmlXMLHttpRequest::~QmlXMLHttpRequest() destroyNetwork(); } -QScriptValue QmlXMLHttpRequest::callback() const -{ - return m_callback; -} - -void QmlXMLHttpRequest::setCallback(const QScriptValue &c) -{ - m_callback = c; -} - bool QmlXMLHttpRequest::sendFlag() const { return m_sendFlag; @@ -1042,7 +1031,7 @@ QString QmlXMLHttpRequest::replyStatusText() const return m_statusText; } -QScriptValue QmlXMLHttpRequest::open(const QString &method, const QUrl &url) +QScriptValue QmlXMLHttpRequest::open(QScriptValue *me, const QString &method, const QUrl &url) { destroyNetwork(); m_sendFlag = false; @@ -1051,7 +1040,7 @@ QScriptValue QmlXMLHttpRequest::open(const QString &method, const QUrl &url) m_method = method; m_url = url; m_state = Opened; - return dispatchCallback(); + return dispatchCallback(me); } void QmlXMLHttpRequest::addHeader(const QString &name, const QString &value) @@ -1155,19 +1144,20 @@ void QmlXMLHttpRequest::requestFromUrl(const QUrl &url) this, SLOT(finished())); } -QScriptValue QmlXMLHttpRequest::send(const QByteArray &data) +QScriptValue QmlXMLHttpRequest::send(QScriptValue *me, const QByteArray &data) { m_errorFlag = false; m_sendFlag = true; m_redirectCount = 0; m_data = data; + m_me = *me; requestFromUrl(m_url); return QScriptValue(); } -QScriptValue QmlXMLHttpRequest::abort() +QScriptValue QmlXMLHttpRequest::abort(QScriptValue *me) { destroyNetwork(); m_responseEntityBody = QByteArray(); @@ -1180,7 +1170,7 @@ QScriptValue QmlXMLHttpRequest::abort() m_state = Done; m_sendFlag = false; - QScriptValue cbv = dispatchCallback(); + QScriptValue cbv = dispatchCallback(me); if (cbv.isError()) return cbv; } @@ -1200,7 +1190,7 @@ void QmlXMLHttpRequest::downloadProgress(qint64 bytes) if (m_state < HeadersReceived) { m_state = HeadersReceived; fillHeadersList (); - QScriptValue cbv = dispatchCallback(); + QScriptValue cbv = dispatchCallback(&m_me); if (cbv.isError()) printError(cbv); } @@ -1208,7 +1198,7 @@ void QmlXMLHttpRequest::downloadProgress(qint64 bytes) m_responseEntityBody.append(m_network->readAll()); if (wasEmpty && !m_responseEntityBody.isEmpty()) { m_state = Loading; - QScriptValue cbv = dispatchCallback(); + QScriptValue cbv = dispatchCallback(&m_me); if (cbv.isError()) printError(cbv); } } @@ -1233,14 +1223,14 @@ void QmlXMLHttpRequest::error(QNetworkReply::NetworkError error) error == QNetworkReply::AuthenticationRequiredError || error == QNetworkReply::ContentReSendError) { m_state = Loading; - QScriptValue cbv = dispatchCallback(); + QScriptValue cbv = dispatchCallback(&m_me); if (cbv.isError()) printError(cbv); } else { m_errorFlag = true; } m_state = Done; - QScriptValue cbv = dispatchCallback(); + QScriptValue cbv = dispatchCallback(&m_me); if (cbv.isError()) printError(cbv); } @@ -1266,7 +1256,7 @@ void QmlXMLHttpRequest::finished() if (m_state < HeadersReceived) { m_state = HeadersReceived; fillHeadersList (); - QScriptValue cbv = dispatchCallback(); + QScriptValue cbv = dispatchCallback(&m_me); if (cbv.isError()) printError(cbv); } m_responseEntityBody.append(m_network->readAll()); @@ -1274,12 +1264,14 @@ void QmlXMLHttpRequest::finished() destroyNetwork(); if (m_state < Loading) { m_state = Loading; - QScriptValue cbv = dispatchCallback(); + QScriptValue cbv = dispatchCallback(&m_me); if (cbv.isError()) printError(cbv); } m_state = Done; - QScriptValue cbv = dispatchCallback(); + QScriptValue cbv = dispatchCallback(&m_me); if (cbv.isError()) printError(cbv); + + m_me = QScriptValue(); } @@ -1288,9 +1280,10 @@ QString QmlXMLHttpRequest::responseBody() const return QString::fromUtf8(m_responseEntityBody); } -QScriptValue QmlXMLHttpRequest::dispatchCallback() +QScriptValue QmlXMLHttpRequest::dispatchCallback(QScriptValue *me) { - return m_callback.call(); + QScriptValue v = me->property(QLatin1String("callback")); + return v.call(); } void QmlXMLHttpRequest::printError(const QScriptValue& sv) @@ -1312,7 +1305,8 @@ void QmlXMLHttpRequest::destroyNetwork() // XMLHttpRequest methods static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngine *engine) { - QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + QScriptValue dataObject = context->thisObject().data(); + QmlXMLHttpRequest *request = qobject_cast(dataObject.toQObject()); if (!request) THROW_REFERENCE("Not an XMLHttpRequest object"); @@ -1354,7 +1348,7 @@ static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngin if (!username.isNull()) url.setUserName(username); if (!password.isNull()) url.setPassword(password); - return request->open(method, url); + return request->open(&dataObject, method, url); } static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine) @@ -1405,9 +1399,10 @@ static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, return engine->undefinedValue(); } -static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *engine) +static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *) { - QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + QScriptValue dataObject = context->thisObject().data(); + QmlXMLHttpRequest *request = qobject_cast(dataObject.toQObject()); if (!request) THROW_REFERENCE("Not an XMLHttpRequest object"); @@ -1421,16 +1416,17 @@ static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngin if (context->argumentCount() > 0) data = context->argument(0).toString().toUtf8(); - return request->send(data); + return request->send(&dataObject, data); } static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *) { - QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + QScriptValue dataObject = context->thisObject().data(); + QmlXMLHttpRequest *request = qobject_cast(dataObject.toQObject()); if (!request) THROW_REFERENCE("Not an XMLHttpRequest object"); - return request->abort(); + return request->abort(&dataObject); } static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, QScriptEngine *engine) @@ -1545,15 +1541,19 @@ static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScri static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine) { - Q_UNUSED(engine) - QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + Q_UNUSED(engine); + QScriptValue dataObject = context->thisObject().data(); + QmlXMLHttpRequest *request = qobject_cast(dataObject.toQObject()); if (!request) THROW_REFERENCE("Not an XMLHttpRequest object"); - if (context->argumentCount()) - request->setCallback(context->argument(0)); - - return request->callback(); + if (context->argumentCount()) { + QScriptValue v = context->argument(0); + dataObject.setProperty(QLatin1String("callback"), v); + return v; + } else { + return dataObject.property(QLatin1String("callback")); + } } // Constructor -- cgit v0.12 From af76a0b5ddc7af8515b9430b6842d5afd49ea940 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 8 Feb 2010 13:46:13 +0100 Subject: re-enable QT_USE_FAST_CONCATENATION includes workaround for breakage with old g++ --- src/declarative/qml/parser/qmljsgrammar_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/qml/parser/qmljsgrammar_p.h b/src/declarative/qml/parser/qmljsgrammar_p.h index 903e2c4..c2e2693 100644 --- a/src/declarative/qml/parser/qmljsgrammar_p.h +++ b/src/declarative/qml/parser/qmljsgrammar_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE class QmlJSGrammar { public: - enum { + enum VariousConstants { EOF_SYMBOL = 0, REDUCE_HERE = 99, SHIFT_THERE = 98, -- cgit v0.12 From 08c74ed63f509a10f15c660c7506596501b81592 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 8 Feb 2010 13:53:11 +0100 Subject: Changed define name to reflect change in Creator. --- src/declarative/qml/parser/qmljsglobal_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/declarative/qml/parser/qmljsglobal_p.h b/src/declarative/qml/parser/qmljsglobal_p.h index 59762ff..49e50cf 100644 --- a/src/declarative/qml/parser/qmljsglobal_p.h +++ b/src/declarative/qml/parser/qmljsglobal_p.h @@ -47,13 +47,13 @@ # define QT_QML_BEGIN_NAMESPACE # define QT_QML_END_NAMESPACE -# ifdef QML_BUILD_LIB +# ifdef QMLJS_BUILD_DIR # define QML_PARSER_EXPORT Q_DECL_EXPORT # elif QML_BUILD_STATIC_LIB # define QML_PARSER_EXPORT # else # define QML_PARSER_EXPORT Q_DECL_IMPORT -# endif // QML_BUILD_LIB +# endif // QMLJS_BUILD_DIR #else // !QT_CREATOR # define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE -- cgit v0.12 From 322fb5291f91ab389300ec5e28155bf881bcd518 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Mon, 8 Feb 2010 14:01:07 +0100 Subject: Document QtObject Task-number:QTBUG-6034 --- doc/src/declarative/elements.qdoc | 1 + doc/src/declarative/qmlviewer.qdoc | 2 +- src/declarative/qml/qmlengine.cpp | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/src/declarative/elements.qdoc b/doc/src/declarative/elements.qdoc index 81a6c96..cfbabf2 100644 --- a/doc/src/declarative/elements.qdoc +++ b/doc/src/declarative/elements.qdoc @@ -99,6 +99,7 @@ The following table lists the QML elements provided by the Qt Declarative module \o \l Connection \o \l Component \o \l Timer +\o \l QtObject \endlist \endtable diff --git a/doc/src/declarative/qmlviewer.qdoc b/doc/src/declarative/qmlviewer.qdoc index 6a107ce..a5cb671 100644 --- a/doc/src/declarative/qmlviewer.qdoc +++ b/doc/src/declarative/qmlviewer.qdoc @@ -84,7 +84,7 @@ To use this from within your QML file, import QmlViewer 1.0 and create a Screen object. This object has a property, orientation, which can be either - Screen.Lanscape or Screen.Portrait and which can be bound to in your + Screen.Landscape or Screen.Portrait and which can be bound to in your application. An example is below: \code diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 5624da1..bb26d30 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -110,6 +110,25 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE) QML_DEFINE_TYPE(Qt,4,6,QtObject,QObject) +/*! + \qmlclass QtObject QObject + \brief The QtObject element is the most basic element in QML + + The QtObject element is a non-visual element which contains only + the objectName property. It is useful for when you need an extremely + lightweight element to place your own custom properties in. + + It can also be useful for C++ integration, as it is just a plain QObject. See + the QObject documentation for further details. +*/ +/*! + \qmlproperty string QtObject::objectName + This property allows you to give a name to this specific object instance. + + See \l{scripting.html#accessing-child-qobjects}{Accessing Child QObjects} + in the scripting documentation for details how objectName can be used from + scripts. +*/ struct StaticQtMetaObject : public QObject { -- cgit v0.12 From 43b61d3a9fd8eaf5cbca046d376ea82b2311c967 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 4 Feb 2010 16:24:48 +0100 Subject: Add getter functions to QAbstractDynamicMetaObject and QmlOpenMetaObjectType We need some internal stuff in the derived class. Reviewed-By: Kai Koehne --- src/declarative/util/qmlopenmetaobject.cpp | 17 +++++++++++++++++ src/declarative/util/qmlopenmetaobject_p.h | 7 ++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/declarative/util/qmlopenmetaobject.cpp b/src/declarative/util/qmlopenmetaobject.cpp index 373be2d..1be81de 100644 --- a/src/declarative/util/qmlopenmetaobject.cpp +++ b/src/declarative/util/qmlopenmetaobject.cpp @@ -81,6 +81,17 @@ QmlOpenMetaObjectType::~QmlOpenMetaObjectType() delete d; } + +int QmlOpenMetaObjectType::propertyOffset() const +{ + return d->propertyOffset; +} + +int QmlOpenMetaObjectType::signalOffset() const +{ + return d->signalOffset; +} + int QmlOpenMetaObjectType::createProperty(const QByteArray &name) { int id = d->mob.propertyCount(); @@ -226,6 +237,11 @@ int QmlOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a) } } +QAbstractDynamicMetaObject *QmlOpenMetaObject::parent() const +{ + return d->parent; +} + QVariant QmlOpenMetaObject::value(int id) const { return d->getData(id); @@ -293,6 +309,7 @@ void QmlOpenMetaObject::setCached(bool c) } } + int QmlOpenMetaObject::createProperty(const char *name, const char *) { if (d->autoCreate) diff --git a/src/declarative/util/qmlopenmetaobject_p.h b/src/declarative/util/qmlopenmetaobject_p.h index 450f258..c6da71a 100644 --- a/src/declarative/util/qmlopenmetaobject_p.h +++ b/src/declarative/util/qmlopenmetaobject_p.h @@ -57,7 +57,7 @@ QT_MODULE(Declarative) class QmlEngine; class QMetaPropertyBuilder; class QmlOpenMetaObjectTypePrivate; -class QmlOpenMetaObjectType : public QmlRefCount +class Q_DECLARATIVE_EXPORT QmlOpenMetaObjectType : public QmlRefCount { public: QmlOpenMetaObjectType(const QMetaObject *base, QmlEngine *engine); @@ -65,6 +65,9 @@ public: int createProperty(const QByteArray &name); + int propertyOffset() const; + int signalOffset() const; + protected: virtual void propertyCreated(int, QMetaPropertyBuilder &); @@ -108,6 +111,8 @@ protected: virtual void propertyWrite(int); virtual void propertyCreated(int, QMetaPropertyBuilder &); + QAbstractDynamicMetaObject *parent() const; + private: QmlOpenMetaObjectPrivate *d; friend class QmlOpenMetaObjectType; -- cgit v0.12 From 3e8e1b369752d8a0b42f088f577f3d33eb29f8a9 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Mon, 8 Feb 2010 14:04:32 +0100 Subject: Add empty constructor for validators. Needed to use them in QML. Also adds Q_ENUMS macro for an enum used by QDoubleValidator. Reviewed-by: trustme --- src/gui/widgets/qvalidator.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/qvalidator.h b/src/gui/widgets/qvalidator.h index e996a01..63734ca 100644 --- a/src/gui/widgets/qvalidator.h +++ b/src/gui/widgets/qvalidator.h @@ -137,10 +137,11 @@ class Q_GUI_EXPORT QDoubleValidator : public QValidator Q_PROPERTY(double bottom READ bottom WRITE setBottom) Q_PROPERTY(double top READ top WRITE setTop) Q_PROPERTY(int decimals READ decimals WRITE setDecimals) + Q_ENUMS(Notation) Q_PROPERTY(Notation notation READ notation WRITE setNotation) public: - explicit QDoubleValidator(QObject * parent); + explicit QDoubleValidator(QObject * parent = 0); QDoubleValidator(double bottom, double top, int decimals, QObject * parent); ~QDoubleValidator(); @@ -184,7 +185,7 @@ class Q_GUI_EXPORT QRegExpValidator : public QValidator Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp) public: - explicit QRegExpValidator(QObject *parent); + explicit QRegExpValidator(QObject *parent = 0); QRegExpValidator(const QRegExp& rx, QObject *parent); ~QRegExpValidator(); -- cgit v0.12 From a764c32ee5cab4b40a0ce6807e1e7c3efcc7bdc8 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Mon, 8 Feb 2010 16:09:00 +0100 Subject: Support the other validators Note that a resolution will be required for QTBUG-8025 before the QRegExpValidator is useful. Task-number: QTBUG-7068 --- .../graphicsitems/qmlgraphicstextinput.cpp | 21 +++++ .../graphicsitems/qmlgraphicstextinput_p.h | 2 + .../tst_qmlgraphicstextinput.cpp | 95 ++++++++++++++++++++-- 3 files changed, 112 insertions(+), 6 deletions(-) diff --git a/src/declarative/graphicsitems/qmlgraphicstextinput.cpp b/src/declarative/graphicsitems/qmlgraphicstextinput.cpp index 427f9ff..6d79c7a 100644 --- a/src/declarative/graphicsitems/qmlgraphicstextinput.cpp +++ b/src/declarative/graphicsitems/qmlgraphicstextinput.cpp @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE QML_DEFINE_TYPE(Qt,4,6,TextInput,QmlGraphicsTextInput); QML_DEFINE_NOCREATE_TYPE(QValidator); QML_DEFINE_TYPE(Qt,4,6,QIntValidator,QIntValidator); +QML_DEFINE_TYPE(Qt,4,6,QDoubleValidator,QDoubleValidator); +QML_DEFINE_TYPE(Qt,4,6,QRegExpValidator,QRegExpValidator); /*! \qmlclass TextInput QmlGraphicsTextInput @@ -437,6 +439,25 @@ void QmlGraphicsTextInput::setFocusOnPress(bool b) an acceptable or intermediate state. The accepted signal will only be sent if the text is in an acceptable state when enter is pressed. + Currently supported validators are QIntValidator, QDoubleValidator and + QRegExpValidator. For details, refer to their C++ documentation and remember + that all Q_PROPERTIES are accessible from Qml. A brief usage guide follows: + + QIntValidator and QDoubleValidator both are controllable through two properties, + top and bottom. The difference is that for QIntValidator the top and bottom properties + should be integers, and for QDoubleValidator they should be doubles. QRegExpValidator + has a single string property, regExp, which should be set to the regular expression to + be used for validation. An example of using validators is shown below, which allows + input of integers between 11 and 31 into the text input: + + \code + import Qt 4.6 + TextInput{ + validator: QIntValidator{bottom: 11; top: 31;} + focus: true + } + \endcode + \sa acceptableInput, inputMask */ QValidator* QmlGraphicsTextInput::validator() const diff --git a/src/declarative/graphicsitems/qmlgraphicstextinput_p.h b/src/declarative/graphicsitems/qmlgraphicstextinput_p.h index 56f16a5..68f28f8 100644 --- a/src/declarative/graphicsitems/qmlgraphicstextinput_p.h +++ b/src/declarative/graphicsitems/qmlgraphicstextinput_p.h @@ -220,6 +220,8 @@ QT_END_NAMESPACE QML_DECLARE_TYPE(QmlGraphicsTextInput) QML_DECLARE_TYPE(QValidator) QML_DECLARE_TYPE(QIntValidator) +QML_DECLARE_TYPE(QDoubleValidator) +QML_DECLARE_TYPE(QRegExpValidator) QT_END_HEADER diff --git a/tests/auto/declarative/qmlgraphicstextinput/tst_qmlgraphicstextinput.cpp b/tests/auto/declarative/qmlgraphicstextinput/tst_qmlgraphicstextinput.cpp index 7223ff9..7896464 100644 --- a/tests/auto/declarative/qmlgraphicstextinput/tst_qmlgraphicstextinput.cpp +++ b/tests/auto/declarative/qmlgraphicstextinput/tst_qmlgraphicstextinput.cpp @@ -397,13 +397,96 @@ void tst_qmlgraphicstextinput::masks() void tst_qmlgraphicstextinput::validators() { - QString componentStr = "import Qt 4.6\nTextInput { maximumLength: 10; }"; - QmlComponent textinputComponent(&engine); - textinputComponent.setData(componentStr.toLatin1(), QUrl()); - QmlGraphicsTextInput *textinputObject = qobject_cast(textinputComponent.create()); - QVERIFY(textinputObject != 0); + // Note that this test assumes that the validators are working properly + // so you may need to run their tests first. All validators are checked + // here to ensure that their exposure to QML is working. + + QmlView *canvas = createView(SRCDIR "/data/validators.qml"); + canvas->execute(); + canvas->show(); + canvas->setFocus(); + + QVERIFY(canvas->root() != 0); - //TODO: Me + QmlGraphicsTextInput *intInput = qobject_cast(qvariant_cast(canvas->root()->property("intInput"))); + QVERIFY(intInput); + intInput->setFocus(true); + QTRY_VERIFY(intInput->hasFocus()); + QTest::keyPress(canvas, Qt::Key_1); + QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10); + QCOMPARE(intInput->text(), QLatin1String("1")); + QCOMPARE(intInput->hasAcceptableInput(), false); + QTest::keyPress(canvas, Qt::Key_2); + QTest::keyRelease(canvas, Qt::Key_2, Qt::NoModifier ,10); + QCOMPARE(intInput->text(), QLatin1String("1")); + QCOMPARE(intInput->hasAcceptableInput(), false); + QTest::keyPress(canvas, Qt::Key_1); + QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10); + QCOMPARE(intInput->text(), QLatin1String("11")); + QCOMPARE(intInput->hasAcceptableInput(), true); + QTest::keyPress(canvas, Qt::Key_0); + QTest::keyRelease(canvas, Qt::Key_0, Qt::NoModifier ,10); + QCOMPARE(intInput->text(), QLatin1String("11")); + QCOMPARE(intInput->hasAcceptableInput(), true); + + QmlGraphicsTextInput *dblInput = qobject_cast(qvariant_cast(canvas->root()->property("dblInput"))); + QTRY_VERIFY(dblInput); + dblInput->setFocus(true); + QVERIFY(dblInput->hasFocus() == true); + QTest::keyPress(canvas, Qt::Key_1); + QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10); + QCOMPARE(dblInput->text(), QLatin1String("1")); + QCOMPARE(dblInput->hasAcceptableInput(), false); + QTest::keyPress(canvas, Qt::Key_2); + QTest::keyRelease(canvas, Qt::Key_2, Qt::NoModifier ,10); + QCOMPARE(dblInput->text(), QLatin1String("12")); + QCOMPARE(dblInput->hasAcceptableInput(), true); + QTest::keyPress(canvas, Qt::Key_Period); + QTest::keyRelease(canvas, Qt::Key_Period, Qt::NoModifier ,10); + QCOMPARE(dblInput->text(), QLatin1String("12.")); + QCOMPARE(dblInput->hasAcceptableInput(), true); + QTest::keyPress(canvas, Qt::Key_1); + QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10); + QCOMPARE(dblInput->text(), QLatin1String("12.1")); + QCOMPARE(dblInput->hasAcceptableInput(), true); + QTest::keyPress(canvas, Qt::Key_1); + QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10); + QCOMPARE(dblInput->text(), QLatin1String("12.11")); + QCOMPARE(dblInput->hasAcceptableInput(), true); + QTest::keyPress(canvas, Qt::Key_1); + QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10); + QCOMPARE(dblInput->text(), QLatin1String("12.11")); + QCOMPARE(dblInput->hasAcceptableInput(), true); + + QmlGraphicsTextInput *strInput = qobject_cast(qvariant_cast(canvas->root()->property("strInput"))); + QTRY_VERIFY(strInput); + strInput->setFocus(true); + QVERIFY(strInput->hasFocus() == true); + QTest::keyPress(canvas, Qt::Key_1); + QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10); + QEXPECT_FAIL("","Will not work until QTBUG-8025 is resolved", Abort); + QCOMPARE(strInput->text(), QLatin1String("")); + QCOMPARE(strInput->hasAcceptableInput(), false); + QTest::keyPress(canvas, Qt::Key_A); + QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10); + QCOMPARE(strInput->text(), QLatin1String("a")); + QCOMPARE(strInput->hasAcceptableInput(), false); + QTest::keyPress(canvas, Qt::Key_A); + QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10); + QCOMPARE(strInput->text(), QLatin1String("aa")); + QCOMPARE(strInput->hasAcceptableInput(), true); + QTest::keyPress(canvas, Qt::Key_A); + QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10); + QCOMPARE(strInput->text(), QLatin1String("aaa")); + QCOMPARE(strInput->hasAcceptableInput(), true); + QTest::keyPress(canvas, Qt::Key_A); + QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10); + QCOMPARE(strInput->text(), QLatin1String("aaaa")); + QCOMPARE(strInput->hasAcceptableInput(), true); + QTest::keyPress(canvas, Qt::Key_A); + QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10); + QCOMPARE(strInput->text(), QLatin1String("aaaa")); + QCOMPARE(strInput->hasAcceptableInput(), true); } /* -- cgit v0.12