diff options
author | Marius Bugge Monsen <mmonsen@trolltech.com> | 2009-09-23 14:02:06 (GMT) |
---|---|---|
committer | Marius Bugge Monsen <mmonsen@trolltech.com> | 2009-09-23 14:02:06 (GMT) |
commit | 17c13775085cfa2ce3c5352cff51c02daaa6662b (patch) | |
tree | ab9a3e088dcae02d10f1bfa16e3955a57a981b66 | |
parent | 465ae8e6180c812eb91279ee4ccf047a4de2932d (diff) | |
parent | aed412fd14e39a356a886c5a472ceade3da56d13 (diff) | |
download | Qt-17c13775085cfa2ce3c5352cff51c02daaa6662b.zip Qt-17c13775085cfa2ce3c5352cff51c02daaa6662b.tar.gz Qt-17c13775085cfa2ce3c5352cff51c02daaa6662b.tar.bz2 |
Merge branch '4.6' of git@scm.dev.nokia.troll.no:qt/qt into 4.6
39 files changed, 1193 insertions, 760 deletions
diff --git a/examples/animation/easing/animation.h b/examples/animation/easing/animation.h index 45a7b17..78fdc14 100644 --- a/examples/animation/easing/animation.h +++ b/examples/animation/easing/animation.h @@ -68,7 +68,7 @@ public: m_path = QPainterPath(); } - void updateCurrentTime(int msecs) + void updateCurrentTime() { if (m_pathType == CirclePath) { if (m_path.isEmpty()) { @@ -90,7 +90,7 @@ public: updateCurrentValue(pt); emit valueChanged(pt); } else { - QPropertyAnimation::updateCurrentTime(msecs); + QPropertyAnimation::updateCurrentTime(); } } diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 6306882..9027be0 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -81,12 +81,12 @@ 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. + duration for the animation (as discussed above). The animation + framework calls updateCurrentTime() when current time has changed. + 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 @@ -604,7 +604,7 @@ void QAbstractAnimation::setCurrentTime(int msecs) } } - updateCurrentTime(msecs); + updateCurrentTime(); if (d->currentLoop != oldLoop) emit currentLoopChanged(d->currentLoop); @@ -705,10 +705,10 @@ bool QAbstractAnimation::event(QEvent *event) } /*! - \fn virtual void QAbstractAnimation::updateCurrentTime(int msecs) = 0; + \fn virtual void QAbstractAnimation::updateCurrentTime() = 0; This pure virtual function is called every time the animation's current - time changes. The \a msecs argument is the current time. + time changes. \sa updateState() */ diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h index dc0af19..516f5e9 100644 --- a/src/corelib/animation/qabstractanimation.h +++ b/src/corelib/animation/qabstractanimation.h @@ -119,7 +119,7 @@ protected: QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent = 0); bool event(QEvent *event); - virtual void updateCurrentTime(int msecs) = 0; + virtual void updateCurrentTime() = 0; virtual void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); virtual void updateDirection(QAbstractAnimation::Direction direction); diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp index 349090b..82d5224 100644 --- a/src/corelib/animation/qparallelanimationgroup.cpp +++ b/src/corelib/animation/qparallelanimationgroup.cpp @@ -125,7 +125,7 @@ int QParallelAnimationGroup::duration() const /*! \reimp */ -void QParallelAnimationGroup::updateCurrentTime(int) +void QParallelAnimationGroup::updateCurrentTime() { Q_D(QParallelAnimationGroup); if (d->animations.isEmpty()) diff --git a/src/corelib/animation/qparallelanimationgroup.h b/src/corelib/animation/qparallelanimationgroup.h index f013bc7..6afe4a7 100644 --- a/src/corelib/animation/qparallelanimationgroup.h +++ b/src/corelib/animation/qparallelanimationgroup.h @@ -67,7 +67,7 @@ protected: QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd, QObject *parent); bool event(QEvent *event); - void updateCurrentTime(int msecs); + void updateCurrentTime(); void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); void updateDirection(QAbstractAnimation::Direction direction); diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp index 8bfed08..c382b19 100644 --- a/src/corelib/animation/qpauseanimation.cpp +++ b/src/corelib/animation/qpauseanimation.cpp @@ -141,9 +141,8 @@ bool QPauseAnimation::event(QEvent *e) /*! \reimp */ -void QPauseAnimation::updateCurrentTime(int msecs) +void QPauseAnimation::updateCurrentTime() { - Q_UNUSED(msecs); } diff --git a/src/corelib/animation/qpauseanimation.h b/src/corelib/animation/qpauseanimation.h index 05eb3b3..caac9e9 100644 --- a/src/corelib/animation/qpauseanimation.h +++ b/src/corelib/animation/qpauseanimation.h @@ -68,7 +68,7 @@ public: protected: bool event(QEvent *e); - void updateCurrentTime(int msecs); + void updateCurrentTime(); private: Q_DISABLE_COPY(QPauseAnimation) diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp index 53fc4f3..9ad433f 100644 --- a/src/corelib/animation/qsequentialanimationgroup.cpp +++ b/src/corelib/animation/qsequentialanimationgroup.cpp @@ -112,17 +112,13 @@ int QSequentialAnimationGroupPrivate::animationActualTotalDuration(int index) co return ret; } -QSequentialAnimationGroupPrivate::AnimationIndex QSequentialAnimationGroupPrivate::indexForTime(int msecs) const +QSequentialAnimationGroupPrivate::AnimationIndex QSequentialAnimationGroupPrivate::indexForCurrentTime() 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); @@ -131,8 +127,8 @@ QSequentialAnimationGroupPrivate::AnimationIndex QSequentialAnimationGroupPrivat // 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)) { + if (duration == -1 || currentTime < (ret.timeOffset + duration) + || (currentTime == (ret.timeOffset + duration) && direction == QAbstractAnimation::Backward)) { ret.index = i; return ret; } @@ -338,13 +334,13 @@ int QSequentialAnimationGroup::duration() const /*! \reimp */ -void QSequentialAnimationGroup::updateCurrentTime(int msecs) +void QSequentialAnimationGroup::updateCurrentTime() { Q_D(QSequentialAnimationGroup); if (!d->currentAnimation) return; - const QSequentialAnimationGroupPrivate::AnimationIndex newAnimationIndex = d->indexForTime(msecs); + const QSequentialAnimationGroupPrivate::AnimationIndex newAnimationIndex = d->indexForCurrentTime(); // remove unneeded animations from actualDuration list while (newAnimationIndex.index < d->actualDuration.size()) @@ -363,7 +359,7 @@ void QSequentialAnimationGroup::updateCurrentTime(int msecs) d->setCurrentAnimation(newAnimationIndex.index); - const int newCurrentTime = msecs - newAnimationIndex.timeOffset; + const int newCurrentTime = d->currentTime - newAnimationIndex.timeOffset; if (d->currentAnimation) { d->currentAnimation->setCurrentTime(newCurrentTime); diff --git a/src/corelib/animation/qsequentialanimationgroup.h b/src/corelib/animation/qsequentialanimationgroup.h index e17e103..1c9e4cc 100644 --- a/src/corelib/animation/qsequentialanimationgroup.h +++ b/src/corelib/animation/qsequentialanimationgroup.h @@ -77,7 +77,7 @@ protected: QSequentialAnimationGroup(QSequentialAnimationGroupPrivate &dd, QObject *parent); bool event(QEvent *event); - void updateCurrentTime(int msecs); + void updateCurrentTime(); void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); void updateDirection(QAbstractAnimation::Direction direction); diff --git a/src/corelib/animation/qsequentialanimationgroup_p.h b/src/corelib/animation/qsequentialanimationgroup_p.h index 2e65cc0..ab41d35 100644 --- a/src/corelib/animation/qsequentialanimationgroup_p.h +++ b/src/corelib/animation/qsequentialanimationgroup_p.h @@ -79,7 +79,7 @@ public: }; int animationActualTotalDuration(int index) const; - AnimationIndex indexForTime(int msecs) const; + AnimationIndex indexForCurrentTime() const; void setCurrentAnimation(int index, bool intermediate = false); void activateCurrentAnimation(bool intermediate = false); diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp index c831a34..ae8bf2f 100644 --- a/src/corelib/animation/qvariantanimation.cpp +++ b/src/corelib/animation/qvariantanimation.cpp @@ -656,9 +656,8 @@ QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &t /*! \reimp */ -void QVariantAnimation::updateCurrentTime(int msecs) +void QVariantAnimation::updateCurrentTime() { - Q_UNUSED(msecs); d_func()->recalculateCurrentInterval(); } diff --git a/src/corelib/animation/qvariantanimation.h b/src/corelib/animation/qvariantanimation.h index c803150..98c1aec 100644 --- a/src/corelib/animation/qvariantanimation.h +++ b/src/corelib/animation/qvariantanimation.h @@ -102,7 +102,7 @@ protected: QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent = 0); bool event(QEvent *event); - void updateCurrentTime(int msecs); + void updateCurrentTime(); void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); virtual void updateCurrentValue(const QVariant &value) = 0; diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index c575509..9a93685 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -345,7 +345,7 @@ void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) } #elif defined(Q_OS_SYMBIAN) && defined (QT_NO_DEBUG) // no implementation in release builds, but keep the symbol present -void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) +void QCoreApplicationPrivate::checkReceiverThread(QObject * /* receiver */) { } #endif diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index 2ed65ea..a891637 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -161,10 +161,8 @@ public: #endif #if defined(Q_OS_SYMBIAN) - enum ConversionMode { CopyData, DuplicateHandle }; - - CFbsBitmap *toSymbianCFbsBitmap(ConversionMode mode = DuplicateHandle) const; - static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode = DuplicateHandle); + CFbsBitmap *toSymbianCFbsBitmap() const; + static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap); RSgImage* toSymbianRSgImage() const; static QPixmap fromSymbianRSgImage(RSgImage *sgImage); #endif diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp index 303e923..cab6116 100644 --- a/src/gui/image/qpixmap_s60.cpp +++ b/src/gui/image/qpixmap_s60.cpp @@ -297,231 +297,55 @@ QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h) } /*! - \enum QPixmap::ConversionMode - - \bold{Symbian only:} This enum defines how the conversion between \c - CFbsBitmap and QPixmap is performed. - - \warning This enum is only available on Symbian. - - \value CopyData Copied CFbsBitmap data. - - \value DuplicateHandle Duplicates CFbsBitmap handle. This also means - that pixmap data will be explicitly shared. - - \sa fromSymbianCFbsBitmap(), toSymbianCFbsBitmap() -*/ - - -/*! - \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap(ConversionMode mode) + \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap() \since 4.6 - Creates \c CFbsBitmap that is equivalent to the QPixmap, based on - the given \a mode. If the creation then this function returns 0. + Creates a \c CFbsBitmap that is equivalent to the QPixmap. Internally this + function will try to duplicate the handle instead of copying the data, + however in scenarios where this is not possible the data will be copied. + If the creation fails or the pixmap is null, then this function returns 0. It is the caller's responsibility to release the \c CFbsBitmap data after use either by deleting the bitmap or calling \c Reset(). - \warning On S60 3.1 and S60 3.2 conversion mode will always be CopyData - if QPixmap pixels have alpha values. + \warning On S60 3.1 and S60 3.2, semi-transparent pixmaps are always copied + and not duplicated. \warning This function is only available on Symbian OS. \sa fromSymbianCFbsBitmap() */ -CFbsBitmap *QPixmap::toSymbianCFbsBitmap(ConversionMode mode) const +CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const { - QS60PixmapData *s60data = static_cast<QS60PixmapData *>(data.data()); - - if (isNull() || !s60data->cfbsBitmap) + QPixmapData *data = pixmapData(); + if (data->isNull()) return 0; - bool convertToArgb32 = false; - - QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion(); - if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) { - // Convert argb32_premultiplied to argb32 since Symbian 9.2 and Symbian 9.3 do - // not support premultipied format. - - if (s60data->image.format() == QImage::Format_ARGB32_Premultiplied) { - mode = CopyData; - convertToArgb32 = true; - } - } - - CFbsBitmap *bitmap = 0; - - TDisplayMode displayMode = s60data->cfbsBitmap->DisplayMode(); - - if(displayMode == EGray2) { - //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid - //So invert mono bitmaps so that masks work correctly. - s60data->image.invertPixels(); - mode = CopyData; - } - - if (mode == CopyData) { - QImage source; - - if (convertToArgb32) { - source = s60data->image.convertToFormat(QImage::Format_ARGB32); - displayMode = EColor16MA; - } else { - source = s60data->image; - } - - CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode); - const uchar *sptr = source.bits(); - s60data->symbianBitmapDataAccess->beginDataAccess(newBitmap); - - uchar *dptr = (uchar*)newBitmap->DataAddress(); - Mem::Copy(dptr, sptr, source.numBytes()); - - s60data->symbianBitmapDataAccess->endDataAccess(newBitmap); - - bitmap = newBitmap; - } else { - - QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap); - - TInt err = bitmap->Duplicate(s60data->cfbsBitmap->Handle()); - if (err != KErrNone) { - qWarning("Could not duplicate CFbsBitmap"); - delete bitmap; - bitmap = 0; - } - } - - if(displayMode == EGray2) { - // restore pixels - s60data->image.invertPixels(); - } - - return bitmap; + return reinterpret_cast<CFbsBitmap*>(data->toNativeType(QPixmapData::FbsBitmap)); } /*! - \fn QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode) + \fn QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap) \since 4.6 - Creates a QPixmap from native \c CFbsBitmap \a bitmap. The conversion - is based on the specified \a mode. Conversion mode is always QPixmap::CopyData - if given \a bitmap does not have display mode of TDisplayMode::EGray2, - \c TDisplayMode::EColor16MU or \c TDisplayMode::EColor16MAP. - + Creates a QPixmap from a \c CFbsBitmap \a bitmap. Internally this function + will try to duplicate the bitmap handle instead of copying the data, however + in scenarios where this is not possible the data will be copied. + To be sure that QPixmap does not modify your original instance, you should + make a copy of your \c CFbsBitmap before calling this function. If the CFbsBitmap is not valid this function will return a null QPixmap. \warning This function is only available on Symbian OS. \sa toSymbianCFbsBitmap(), {QPixmap#Pixmap Conversion}{Pixmap Conversion} */ -QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode) +QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap) { - if (bitmap) { - - bool deleteSourceBitmap = false; - -#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE - - // Rasterize extended bitmaps - - TUid extendedBitmapType = bitmap->ExtendedBitmapType(); - if (extendedBitmapType != KNullUid) { - CFbsBitmap *rasterBitmap = createSymbianCFbsBitmap(bitmap->SizeInPixels(), EColor16MA); - - CFbsBitmapDevice *rasterBitmapDev = 0; - QT_TRAP_THROWING(rasterBitmapDev = CFbsBitmapDevice::NewL(rasterBitmap)); - - CFbsBitGc *rasterBitmapGc = 0; - TInt err = rasterBitmapDev->CreateContext(rasterBitmapGc); - if (err != KErrNone) { - delete rasterBitmap; - delete rasterBitmapDev; - rasterBitmapDev = 0; - return QPixmap(); - } - - rasterBitmapGc->BitBlt(TPoint( 0, 0), bitmap); - - bitmap = rasterBitmap; - - delete rasterBitmapDev; - delete rasterBitmapGc; - - rasterBitmapDev = 0; - rasterBitmapGc = 0; - - deleteSourceBitmap = true; - } -#endif - - - deleteSourceBitmap = bitmap->IsCompressedInRAM(); - CFbsBitmap *sourceBitmap = uncompress(bitmap); - - TDisplayMode displayMode = sourceBitmap->DisplayMode(); - QImage::Format format = qt_TDisplayMode2Format(displayMode); - - QImage::Format opaqueFormat = QNativeImage::systemFormat(); - QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; - - if (format != opaqueFormat && format != alphaFormat && format != QImage::Format_MonoLSB) - mode = CopyData; - - - QPixmapData::PixelType type = (format!=QImage::Format_MonoLSB) - ? QPixmapData::PixmapType - : QPixmapData::BitmapType; - - QS60PixmapData *pixmapData = 0; - - if (mode == CopyData) { - - TSize size = sourceBitmap->SizeInPixels(); - - QSymbianBitmapDataAccess da; - da.beginDataAccess(sourceBitmap); - uchar *bytes = (uchar*)sourceBitmap->DataAddress(); - QImage img = QImage(bytes, size.iWidth, size.iHeight, format); - da.endDataAccess(sourceBitmap); - - pixmapData = new QS60PixmapData(type); - pixmapData->fromImage(img, Qt::AutoColor); - - if(deleteSourceBitmap) - delete sourceBitmap; - - if(displayMode == EGray2) { - //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid - //So invert mono bitmaps so that masks work correctly. - pixmapData->image.invertPixels(); - } - } else { - CFbsBitmap* duplicate = 0; - QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap); - - TInt err = duplicate->Duplicate(sourceBitmap->Handle()); - if (err != KErrNone) { - qWarning("Could not duplicate CFbsBitmap"); - - if(deleteSourceBitmap) - delete sourceBitmap; - - delete duplicate; - return QPixmap(); - } - - pixmapData = new QS60PixmapData(type); - pixmapData->fromSymbianBitmap(duplicate); - - if(deleteSourceBitmap) - delete sourceBitmap; - } - - return QPixmap(pixmapData); - } + if (!bitmap) + return QPixmap(); - return QPixmap(); + QPixmap pixmap; + pixmap.pixmapData()->fromNativeType(reinterpret_cast<void*>(bitmap), QPixmapData::FbsBitmap); + return pixmap; } QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type), @@ -921,7 +745,7 @@ QPixmap QPixmap::fromSymbianRSgImage(RSgImage *sgImage) return QPixmap(); QPixmap pixmap; - pixmap.pixmapData()->fromRSgImage(sgImage); + pixmap.pixmapData()->fromNativeType(reinterpret_cast<void*>(sgImage), QPixmapData::SgImage); return pixmap; } @@ -949,9 +773,193 @@ RSgImage *QPixmap::toSymbianRSgImage() const if (isNull()) return 0; - RSgImage *sgImage = pixmapData()->toRSgImage(); + RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmapData()->toNativeType(QPixmapData::SgImage)); return sgImage; } +void* QS60PixmapData::toNativeType(NativeType type) +{ + if (type == QPixmapData::SgImage) { + return 0; + } else if (type == QPixmapData::FbsBitmap) { + + if (isNull() || !cfbsBitmap) + return 0; + + bool convertToArgb32 = false; + bool needsCopy = false; + + QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion(); + if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) { + // Convert argb32_premultiplied to argb32 since Symbian 9.2 and Symbian 9.3 do + // not support premultipied format. + + if (image.format() == QImage::Format_ARGB32_Premultiplied) { + needsCopy = true; + convertToArgb32 = true; + } + } + + CFbsBitmap *bitmap = 0; + + TDisplayMode displayMode = cfbsBitmap->DisplayMode(); + + if(displayMode == EGray2) { + //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid + //So invert mono bitmaps so that masks work correctly. + image.invertPixels(); + needsCopy = true; + } + + if (needsCopy) { + QImage source; + + if (convertToArgb32) { + source = image.convertToFormat(QImage::Format_ARGB32); + displayMode = EColor16MA; + } else { + source = image; + } + + CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode); + const uchar *sptr = source.bits(); + symbianBitmapDataAccess->beginDataAccess(newBitmap); + + uchar *dptr = (uchar*)newBitmap->DataAddress(); + Mem::Copy(dptr, sptr, source.numBytes()); + + symbianBitmapDataAccess->endDataAccess(newBitmap); + + bitmap = newBitmap; + } else { + + QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap); + + TInt err = bitmap->Duplicate(cfbsBitmap->Handle()); + if (err != KErrNone) { + qWarning("Could not duplicate CFbsBitmap"); + delete bitmap; + bitmap = 0; + } + } + + if(displayMode == EGray2) { + // restore pixels + image.invertPixels(); + } + + return reinterpret_cast<void*>(bitmap); + + } + + return 0; +} + +void QS60PixmapData::fromNativeType(void* pixmap, NativeType nativeType) +{ + if (nativeType == QPixmapData::SgImage) { + return; + } else if (nativeType == QPixmapData::FbsBitmap && pixmap) { + + CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap); + + bool deleteSourceBitmap = false; + bool needsCopy = false; + +#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE + + // Rasterize extended bitmaps + + TUid extendedBitmapType = bitmap->ExtendedBitmapType(); + if (extendedBitmapType != KNullUid) { + CFbsBitmap *rasterBitmap = createSymbianCFbsBitmap(bitmap->SizeInPixels(), EColor16MA); + + CFbsBitmapDevice *rasterBitmapDev = 0; + QT_TRAP_THROWING(rasterBitmapDev = CFbsBitmapDevice::NewL(rasterBitmap)); + + CFbsBitGc *rasterBitmapGc = 0; + TInt err = rasterBitmapDev->CreateContext(rasterBitmapGc); + if (err != KErrNone) { + delete rasterBitmap; + delete rasterBitmapDev; + rasterBitmapDev = 0; + return; + } + + rasterBitmapGc->BitBlt(TPoint( 0, 0), bitmap); + + bitmap = rasterBitmap; + + delete rasterBitmapDev; + delete rasterBitmapGc; + + rasterBitmapDev = 0; + rasterBitmapGc = 0; + + deleteSourceBitmap = true; + } +#endif + + + deleteSourceBitmap = bitmap->IsCompressedInRAM(); + CFbsBitmap *sourceBitmap = uncompress(bitmap); + + TDisplayMode displayMode = sourceBitmap->DisplayMode(); + QImage::Format format = qt_TDisplayMode2Format(displayMode); + + QImage::Format opaqueFormat = QNativeImage::systemFormat(); + QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; + + if (format != opaqueFormat && format != alphaFormat && format != QImage::Format_MonoLSB) + needsCopy = true; + + + type = (format != QImage::Format_MonoLSB) + ? QPixmapData::PixmapType + : QPixmapData::BitmapType; + + if (needsCopy) { + + TSize size = sourceBitmap->SizeInPixels(); + + QSymbianBitmapDataAccess da; + da.beginDataAccess(sourceBitmap); + uchar *bytes = (uchar*)sourceBitmap->DataAddress(); + QImage img = QImage(bytes, size.iWidth, size.iHeight, format); + da.endDataAccess(sourceBitmap); + + fromImage(img, Qt::AutoColor); + + if(deleteSourceBitmap) + delete sourceBitmap; + + if(displayMode == EGray2) { + //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid + //So invert mono bitmaps so that masks work correctly. + image.invertPixels(); + } + } else { + CFbsBitmap* duplicate = 0; + QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap); + + TInt err = duplicate->Duplicate(sourceBitmap->Handle()); + if (err != KErrNone) { + qWarning("Could not duplicate CFbsBitmap"); + + if(deleteSourceBitmap) + delete sourceBitmap; + + delete duplicate; + return; + } + + fromSymbianBitmap(duplicate); + + if(deleteSourceBitmap) + delete sourceBitmap; + } + } +} + QT_END_NAMESPACE diff --git a/src/gui/image/qpixmap_s60_p.h b/src/gui/image/qpixmap_s60_p.h index 21f1bb3..4498c05 100644 --- a/src/gui/image/qpixmap_s60_p.h +++ b/src/gui/image/qpixmap_s60_p.h @@ -66,17 +66,17 @@ class QSymbianBitmapDataAccess; class QSymbianFbsHeapLock { public: - + enum LockAction { Unlock }; - + explicit QSymbianFbsHeapLock(LockAction a); ~QSymbianFbsHeapLock(); - void relock(); - + void relock(); + private: - + LockAction action; bool wasLocked; }; @@ -102,13 +102,16 @@ public: void beginDataAccess(); void endDataAccess(bool readOnly=false) const; + void* toNativeType(NativeType type); + void fromNativeType(void* pixmap, NativeType type); + private: - void release(); - void fromSymbianBitmap(CFbsBitmap* bitmap); - bool initSymbianBitmapContext(); + void release(); + void fromSymbianBitmap(CFbsBitmap* bitmap); + bool initSymbianBitmapContext(); QSymbianBitmapDataAccess *symbianBitmapDataAccess; - + CFbsBitmap *cfbsBitmap; CFbsBitmapDevice *bitmapDevice; CBitmapContext *bitmapContext; diff --git a/src/gui/image/qpixmapdata.cpp b/src/gui/image/qpixmapdata.cpp index 65899a4..93fc2eb 100644 --- a/src/gui/image/qpixmapdata.cpp +++ b/src/gui/image/qpixmapdata.cpp @@ -224,14 +224,15 @@ QImage* QPixmapData::buffer() } #if defined(Q_OS_SYMBIAN) -RSgImage* QPixmapData::toRSgImage() +void* QPixmapData::toNativeType(NativeType /* type */) { return 0; } -void QPixmapData::fromRSgImage(RSgImage* rsgImage) +void QPixmapData::fromNativeType(void* /* pixmap */, NativeType /* typre */) { return; } #endif + QT_END_NAMESPACE diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h index 5920a06..3e85236 100644 --- a/src/gui/image/qpixmapdata_p.h +++ b/src/gui/image/qpixmapdata_p.h @@ -56,10 +56,6 @@ #include <QtGui/qpixmap.h> #include <QtCore/qatomic.h> -#if defined(Q_OS_SYMBIAN) -class RSgImage; -#endif - QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QPixmapData @@ -70,6 +66,12 @@ public: // Must match QPixmap::Type PixmapType, BitmapType }; +#if defined(Q_OS_SYMBIAN) + enum NativeType { + FbsBitmap, + SgImage + }; +#endif enum ClassId { RasterClass, X11Class, MacClass, DirectFBClass, OpenGLClass, OpenVGClass, CustomClass = 1024 }; @@ -114,8 +116,8 @@ public: inline bool isNull() const { return is_null; } #if defined(Q_OS_SYMBIAN) - virtual RSgImage* toRSgImage(); - virtual void fromRSgImage(RSgImage* rsgImage); + virtual void* toNativeType(NativeType type); + virtual void fromNativeType(void* pixmap, NativeType type); #endif protected: @@ -129,6 +131,7 @@ private: friend class QPixmap; friend class QGLContextPrivate; friend class QX11PixmapData; + friend class QS60PixmapData; friend class QGLTextureCache; //Needs to check the reference count friend class QExplicitlySharedDataPointer<QPixmapData>; diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 707caaa..aec21fd 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -576,6 +576,11 @@ public: void _q_readRX71MultiTouchEvents(); #endif +#if defined(Q_WS_S60) + int maxTouchPressure; + QList<QTouchEvent::TouchPoint> appAllTouchPoints; +#endif + private: #ifdef Q_WS_QWS QMap<const QScreen*, QRect> maxWindowRects; diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index a5d07fd..58aca83 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -368,8 +368,77 @@ void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, cons m_previousEventLongTap = true; } +void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event) +{ + QApplicationPrivate *d = QApplicationPrivate::instance(); + + QRect screenGeometry = qApp->desktop()->screenGeometry(qwidget); + + while (d->appAllTouchPoints.count() <= event->PointerNumber()) + d->appAllTouchPoints.append(QTouchEvent::TouchPoint(d->appAllTouchPoints.count())); + + Qt::TouchPointStates allStates = 0; + for (int i = 0; i < d->appAllTouchPoints.count(); ++i) { + QTouchEvent::TouchPoint &touchPoint = d->appAllTouchPoints[i]; + + if (touchPoint.id() == event->PointerNumber()) { + Qt::TouchPointStates state; + switch (event->iType) { + case TPointerEvent::EButton1Down: + case TPointerEvent::EEnterHighPressure: + state = Qt::TouchPointPressed; + break; + case TPointerEvent::EButton1Up: + case TPointerEvent::EExitCloseProximity: + state = Qt::TouchPointReleased; + break; + case TPointerEvent::EDrag: + state = Qt::TouchPointMoved; + break; + default: + // how likely is this to happen? + state = Qt::TouchPointStationary; + break; + } + if (event->PointerNumber() == 0) + state |= Qt::TouchPointPrimary; + touchPoint.setState(state); + + QPointF screenPos = QPointF(event->iPosition.iX, event->iPosition.iY); + touchPoint.setScreenPos(screenPos); + touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(), + screenPos.y() / screenGeometry.height())); + + touchPoint.setPressure(event->Pressure() / qreal(d->maxTouchPressure)); + } else if (touchPoint.state() != Qt::TouchPointReleased) { + // all other active touch points should be marked as stationary + touchPoint.setState(Qt::TouchPointStationary); + } + + allStates |= touchPoint.state(); + } + + if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) { + // all touch points released + d->appAllTouchPoints.clear(); + } + + QApplicationPrivate::translateRawTouchEvent(qwidget, + QTouchEvent::TouchScreen, + d->appAllTouchPoints); +} + void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent) { + if (pEvent.IsAdvancedPointerEvent()) { + const TAdvancedPointerEvent *advancedPointerEvent = pEvent.AdvancedPointerEvent(); + translateAdvancedPointerEvent(advancedPointerEvent); + if (advancedPointerEvent->PointerNumber() != 0) { + // only send mouse events for the first touch point + return; + } + } + m_longTapDetector->PointerEventL(pEvent); QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent)); } @@ -1441,9 +1510,12 @@ TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym) } } - void QApplicationPrivate::initializeMultitouch_sys() -{ } +{ + if (HAL::Get(HALData::EPointer3DMaxPressure, maxTouchPressure) != KErrNone) + maxTouchPressure = KMaxTInt; +} + void QApplicationPrivate::cleanupMultitouch_sys() { } diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index aa39f9d..9939f2c 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -167,6 +167,7 @@ private: TKeyResponse sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent); bool sendMouseEvent(QWidget *widget, QMouseEvent *mEvent); void HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ); + void translateAdvancedPointerEvent(const TAdvancedPointerEvent *event); private: QWidget *qwidget; diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 6f5781c..53ef682 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -10397,7 +10397,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) break; case Qt::WA_AcceptTouchEvents: -#if defined(Q_WS_WIN) || defined(Q_WS_MAC) +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_S60) if (on) d->registerTouchWindow(); #endif diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 5a9c48c..296c5b1 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -693,6 +693,7 @@ public: static QWidget *keyboardGrabber; void s60UpdateIsOpaque(); void reparentChildren(); + void registerTouchWindow(); #endif }; diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 4fef020..2e6139b 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -299,6 +299,9 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw); CBase::Delete(destroyw); } + + if (q->testAttribute(Qt::WA_AcceptTouchEvents)) + registerTouchWindow(); } @@ -800,6 +803,15 @@ void QWidgetPrivate::setMask_sys(const QRegion& /* region */) } +void QWidgetPrivate::registerTouchWindow() +{ + Q_Q(QWidget); + if (q->testAttribute(Qt::WA_WState_Created) && q->windowType() != Qt::Desktop) { + RWindow *rwindow = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow()); + rwindow->EnableAdvancedPointers(); + } +} + int QWidget::metric(PaintDeviceMetric m) const { Q_D(const QWidget); diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index e33b255..0f3a88b 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -1759,7 +1759,7 @@ QRenderRule QStyleSheetStyle::renderRule(const QWidget *w, const QStyleOption *o QStyle::SubControl subControl = knownPseudoElements[pseudoElement].subControl; if (!(complex->activeSubControls & subControl)) - state = QStyle::State(state & (QStyle::State_Enabled | QStyle::State_Horizontal)); + state &= (QStyle::State_Enabled | QStyle::State_Horizontal | QStyle::State_HasFocus); } switch (pseudoElement) { @@ -3136,19 +3136,25 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) { rule.drawRule(p, opt->rect); - QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderGroove); - if (!subRule.hasDrawable()) { - baseStyle()->drawComplexControl(cc, slider, p, w); - return; + QRenderRule grooveSubRule = renderRule(w, opt, PseudoElement_SliderGroove); + QRenderRule handleSubRule = renderRule(w, opt, PseudoElement_SliderHandle); + if (!grooveSubRule.hasDrawable()) { + QStyleOptionSlider slOpt(*slider); + bool handleHasRule = handleSubRule.hasDrawable(); + // If the style specifies a different handler rule, draw the groove without the handler. + if (handleHasRule) + slOpt.subControls &= ~SC_SliderHandle; + baseStyle()->drawComplexControl(cc, &slOpt, p, w); + if (!handleHasRule) + return; } QRect gr = subControlRect(cc, opt, SC_SliderGroove, w); if (slider->subControls & SC_SliderGroove) { - subRule.drawRule(p, gr); + grooveSubRule.drawRule(p, gr); } if (slider->subControls & SC_SliderHandle) { - QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderHandle); QRect hr = subControlRect(cc, opt, SC_SliderHandle, w); QRenderRule subRule1 = renderRule(w, opt, PseudoElement_SliderSubPage); @@ -3169,7 +3175,7 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC subRule2.drawRule(p, r); } - subRule.drawRule(p, subRule.boxRect(hr, Margin)); + handleSubRule.drawRule(p, grooveSubRule.boxRect(hr, Margin)); } if (slider->subControls & SC_SliderTickmarks) { diff --git a/src/gui/styles/qwindowsstyle.cpp b/src/gui/styles/qwindowsstyle.cpp index 2ed9303..0f72440 100644 --- a/src/gui/styles/qwindowsstyle.cpp +++ b/src/gui/styles/qwindowsstyle.cpp @@ -3030,6 +3030,8 @@ void QWindowsStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComp ar.adjust(2, 2, -2, -2); if (opt->state & State_Enabled) flags |= State_Enabled; + if (opt->state & State_HasFocus) + flags |= State_HasFocus; if (sunkenArrow) flags |= State_Sunken; diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index 8b85d2d..ce62834 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -92,8 +92,12 @@ QTextCursorPrivate::AdjustResult QTextCursorPrivate::adjustPosition(int position { QTextCursorPrivate::AdjustResult result = QTextCursorPrivate::CursorMoved; // not(!) <= , so that inserting text adjusts the cursor correctly - if (position < positionOfChange || - (position == positionOfChange && op == QTextUndoCommand::KeepCursor)) { + if (position < positionOfChange + || (position == positionOfChange + && (op == QTextUndoCommand::KeepCursor + || anchor < position) + ) + ) { result = CursorUnchanged; } else { if (charsAddedOrRemoved < 0 && position < positionOfChange - charsAddedOrRemoved) diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index 53975d7..38a89e6 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -381,167 +381,179 @@ void QVGPixmapData::cleanup() source = QImage(); } -void QVGPixmapData::fromRSgImage(RSgImage* sgImage) +void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) { - Q_UNUSED(sgImage); #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) - // when "0" used as argument then - // default display, context are used - if (!context) - context = qt_vg_create_context(0); + if (type == QPixmapData::SgImage && pixmap) { + RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap); + // when "0" used as argument then + // default display, context are used + if (!context) + context = qt_vg_create_context(0); - if (vgImage != VG_INVALID_HANDLE) { - vgDestroyImage(vgImage); - vgImage = VG_INVALID_HANDLE; - } - if (vgImageOpacity != VG_INVALID_HANDLE) { - vgDestroyImage(vgImageOpacity); - vgImageOpacity = VG_INVALID_HANDLE; - } + if (vgImage != VG_INVALID_HANDLE) { + vgDestroyImage(vgImage); + vgImage = VG_INVALID_HANDLE; + } + if (vgImageOpacity != VG_INVALID_HANDLE) { + vgDestroyImage(vgImageOpacity); + vgImageOpacity = VG_INVALID_HANDLE; + } - TInt err = 0; + TInt err = 0; - err = SgDriver::Open(); - if(err != KErrNone) { - cleanup(); - return; - } + err = SgDriver::Open(); + if(err != KErrNone) { + cleanup(); + return; + } - if(sgImage->IsNull()) { - cleanup(); - SgDriver::Close(); - return; - } + if(sgImage->IsNull()) { + cleanup(); + SgDriver::Close(); + return; + } - TSgImageInfo sgImageInfo; - err = sgImage->GetInfo(sgImageInfo); - if(err != KErrNone) { - cleanup(); - SgDriver::Close(); - return; - } + TSgImageInfo sgImageInfo; + err = sgImage->GetInfo(sgImageInfo); + if(err != KErrNone) { + cleanup(); + SgDriver::Close(); + return; + } - pfnEglCreateImageKHR eglCreateImageKHR = (pfnEglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); - pfnEglDestroyImageKHR eglDestroyImageKHR = (pfnEglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); - pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR"); + pfnEglCreateImageKHR eglCreateImageKHR = (pfnEglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); + pfnEglDestroyImageKHR eglDestroyImageKHR = (pfnEglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); + pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR"); - if(eglGetError() != EGL_SUCCESS || !eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateEGLImageTargetKHR) { - cleanup(); - SgDriver::Close(); - return; - } + if(eglGetError() != EGL_SUCCESS || !eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateEGLImageTargetKHR) { + cleanup(); + SgDriver::Close(); + return; + } - const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; - EGLImageKHR eglImage = eglCreateImageKHR(context->display(), - EGL_NO_CONTEXT, - EGL_NATIVE_PIXMAP_KHR, - (EGLClientBuffer)sgImage, - (EGLint*)KEglImageAttribs); + const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; + EGLImageKHR eglImage = eglCreateImageKHR(context->display(), + EGL_NO_CONTEXT, + EGL_NATIVE_PIXMAP_KHR, + (EGLClientBuffer)sgImage, + (EGLint*)KEglImageAttribs); + + if(eglGetError() != EGL_SUCCESS) { + cleanup(); + SgDriver::Close(); + return; + } - if(eglGetError() != EGL_SUCCESS) { - cleanup(); - SgDriver::Close(); - return; - } + vgImage = vgCreateEGLImageTargetKHR(eglImage); + if(vgGetError() != VG_NO_ERROR) { + cleanup(); + eglDestroyImageKHR(context->display(), eglImage); + SgDriver::Close(); + return; + } - vgImage = vgCreateEGLImageTargetKHR(eglImage); - if(vgGetError() != VG_NO_ERROR) { - cleanup(); + w = sgImageInfo.iSizeInPixels.iWidth; + h = sgImageInfo.iSizeInPixels.iHeight; + d = 32; // We always use ARGB_Premultiplied for VG pixmaps. + is_null = (w <= 0 || h <= 0); + source = QImage(); + recreate = false; + setSerialNumber(++qt_vg_pixmap_serial); + // release stuff eglDestroyImageKHR(context->display(), eglImage); SgDriver::Close(); - return; - } + } else if (type == QPixmapData::FbsBitmap) { - w = sgImageInfo.iSizeInPixels.iWidth; - h = sgImageInfo.iSizeInPixels.iHeight; - d = 32; // We always use ARGB_Premultiplied for VG pixmaps. - is_null = (w <= 0 || h <= 0); - source = QImage(); - recreate = false; - setSerialNumber(++qt_vg_pixmap_serial); - // release stuff - eglDestroyImageKHR(context->display(), eglImage); - SgDriver::Close(); + } #else + Q_UNUSED(pixmap); + Q_UNUSED(type); #endif } -RSgImage* QVGPixmapData::toRSgImage() +void* QVGPixmapData::toNativeType(NativeType type) { #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) - toVGImage(); - - if(!isValid() || vgImage == VG_INVALID_HANDLE) - return 0; - - TInt err = 0; + if (type == QPixmapData::SgImage) { + toVGImage(); + + if(!isValid() || vgImage == VG_INVALID_HANDLE) + return 0; + + TInt err = 0; + + err = SgDriver::Open(); + if(err != KErrNone) + return 0; + + TSgImageInfo sgInfo; + sgInfo.iPixelFormat = EUidPixelFormatARGB_8888_PRE; + sgInfo.iSizeInPixels.SetSize(w, h); + sgInfo.iUsage = ESgUsageOpenVgImage | ESgUsageOpenVgTarget; + sgInfo.iShareable = ETrue; + sgInfo.iCpuAccess = ESgCpuAccessNone; + sgInfo.iScreenId = KSgScreenIdMain; //KSgScreenIdAny; + sgInfo.iUserAttributes = NULL; + sgInfo.iUserAttributeCount = 0; + + RSgImage *sgImage = q_check_ptr(new RSgImage()); + err = sgImage->Create(sgInfo, NULL, NULL); + if(err != KErrNone) { + SgDriver::Close(); + return 0; + } - err = SgDriver::Open(); - if(err != KErrNone) - return 0; + pfnEglCreateImageKHR eglCreateImageKHR = (pfnEglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); + pfnEglDestroyImageKHR eglDestroyImageKHR = (pfnEglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); + pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR"); - TSgImageInfo sgInfo; - sgInfo.iPixelFormat = EUidPixelFormatARGB_8888_PRE; - sgInfo.iSizeInPixels.SetSize(w, h); - sgInfo.iUsage = ESgUsageOpenVgImage | ESgUsageOpenVgTarget; - sgInfo.iShareable = ETrue; - sgInfo.iCpuAccess = ESgCpuAccessNone; - sgInfo.iScreenId = KSgScreenIdMain; //KSgScreenIdAny; - sgInfo.iUserAttributes = NULL; - sgInfo.iUserAttributeCount = 0; - - RSgImage *sgImage = q_check_ptr(new RSgImage()); - err = sgImage->Create(sgInfo, NULL, NULL); - if(err != KErrNone) { - SgDriver::Close(); - return 0; - } + if(eglGetError() != EGL_SUCCESS || !eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateEGLImageTargetKHR) { + SgDriver::Close(); + return 0; + } - pfnEglCreateImageKHR eglCreateImageKHR = (pfnEglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); - pfnEglDestroyImageKHR eglDestroyImageKHR = (pfnEglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); - pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR"); + const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; + EGLImageKHR eglImage = eglCreateImageKHR(context->display(), + EGL_NO_CONTEXT, + EGL_NATIVE_PIXMAP_KHR, + (EGLClientBuffer)sgImage, + (EGLint*)KEglImageAttribs); + if(eglGetError() != EGL_SUCCESS) { + sgImage->Close(); + SgDriver::Close(); + return 0; + } - if(eglGetError() != EGL_SUCCESS || !eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateEGLImageTargetKHR) { - SgDriver::Close(); - return 0; - } + VGImage dstVgImage = vgCreateEGLImageTargetKHR(eglImage); + if(vgGetError() != VG_NO_ERROR) { + eglDestroyImageKHR(context->display(), eglImage); + sgImage->Close(); + SgDriver::Close(); + return 0; + } - const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; - EGLImageKHR eglImage = eglCreateImageKHR(context->display(), - EGL_NO_CONTEXT, - EGL_NATIVE_PIXMAP_KHR, - (EGLClientBuffer)sgImage, - (EGLint*)KEglImageAttribs); - if(eglGetError() != EGL_SUCCESS) { - sgImage->Close(); - SgDriver::Close(); - return 0; - } + vgCopyImage(dstVgImage, 0, 0, + vgImage, 0, 0, + w, h, VG_FALSE); - VGImage dstVgImage = vgCreateEGLImageTargetKHR(eglImage); - if(vgGetError() != VG_NO_ERROR) { + if(vgGetError() != VG_NO_ERROR) { + sgImage->Close(); + sgImage = 0; + } + // release stuff + vgDestroyImage(dstVgImage); eglDestroyImageKHR(context->display(), eglImage); - sgImage->Close(); SgDriver::Close(); + return reinterpret_cast<void*>(sgImage); + } else if (type == QPixmapData::FbsBitmap) { return 0; } - - vgCopyImage(dstVgImage, 0, 0, - vgImage, 0, 0, - w, h, VG_FALSE); - - if(vgGetError() != VG_NO_ERROR) { - sgImage->Close(); - sgImage = 0; - } - // release stuff - vgDestroyImage(dstVgImage); - eglDestroyImageKHR(context->display(), eglImage); - SgDriver::Close(); - return sgImage; #else + Q_UNUSED(type); return 0; #endif } #endif //Q_OS_SYMBIAN + QT_END_NAMESPACE diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h index 122f596..99115df 100644 --- a/src/openvg/qpixmapdata_vg_p.h +++ b/src/openvg/qpixmapdata_vg_p.h @@ -95,8 +95,8 @@ public: QSize size() const { return QSize(w, h); } #if defined(Q_OS_SYMBIAN) - RSgImage* toRSgImage(); - void fromRSgImage(RSgImage* sgImage); + void* toNativeType(NativeType type); + void fromNativeType(void* pixmap, NativeType type); #endif protected: diff --git a/src/openvg/qwindowsurface_vg.cpp b/src/openvg/qwindowsurface_vg.cpp index 1997ee8..6cc2e27 100644 --- a/src/openvg/qwindowsurface_vg.cpp +++ b/src/openvg/qwindowsurface_vg.cpp @@ -85,7 +85,6 @@ void QVGWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoin void QVGWindowSurface::setGeometry(const QRect &rect) { QWindowSurface::setGeometry(rect); - d_ptr->ensureContext(window()); } bool QVGWindowSurface::scroll(const QRegion &area, int dx, int dy) diff --git a/tests/auto/linguist/lupdate/testdata/good/parsecontexts/main.cpp b/tests/auto/linguist/lupdate/testdata/good/parsecontexts/main.cpp index 7e81b84..25c2c0d 100644 --- a/tests/auto/linguist/lupdate/testdata/good/parsecontexts/main.cpp +++ b/tests/auto/linguist/lupdate/testdata/good/parsecontexts/main.cpp @@ -262,6 +262,15 @@ QString C2::foo() } +namespace Fooish { + Q_DECLARE_TR_FUNCTIONS(Bears::And::Spiders) +} + +void Fooish::bar() +{ + return tr("whatever the context", "Bears::And::Spiders"); +} + int main(int /*argc*/, char ** /*argv*/) { return 0; diff --git a/tests/auto/linguist/lupdate/testdata/good/parsecontexts/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parsecontexts/project.ts.result index 9b00d53..2f21de2 100644 --- a/tests/auto/linguist/lupdate/testdata/good/parsecontexts/project.ts.result +++ b/tests/auto/linguist/lupdate/testdata/good/parsecontexts/project.ts.result @@ -102,6 +102,15 @@ </message> </context> <context> + <name>Bears::And::Spiders</name> + <message> + <location filename="main.cpp" line="271"/> + <source>whatever the context</source> + <comment>Bears::And::Spiders</comment> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>C1</name> <message> <location filename="main.cpp" line="230"/> diff --git a/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp b/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp index 209e68b..b14d6f8 100644 --- a/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp +++ b/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp @@ -169,10 +169,10 @@ public: int duration() const { return -1; /* not time driven */ } protected: - void updateCurrentTime(int msecs) + void updateCurrentTime() { - QPropertyAnimation::updateCurrentTime(msecs); - if (msecs >= QPropertyAnimation::duration()) + QPropertyAnimation::updateCurrentTime(); + if (currentTime() >= QPropertyAnimation::duration()) stop(); } }; diff --git a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp index e7d804a..50bb846 100644 --- a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -95,6 +95,7 @@ private slots: void embeddedFonts(); void opaquePaintEvent_data(); void opaquePaintEvent(); + void complexWidgetFocus(); void task188195_baseBackground(); void task232085_spinBoxLineEditBg(); @@ -1447,6 +1448,54 @@ void tst_QStyleSheetStyle::opaquePaintEvent() QCOMPARE(cl.autoFillBackground(), !styled ); } +void tst_QStyleSheetStyle::complexWidgetFocus() +{ + // This test is a simplified version of the focusColors() test above. + + // Tests if colors can be changed by altering the focus of the widget. + // To avoid messy pixel-by-pixel comparison, we assume that the goal + // is reached if at least ten pixels of the right color can be found in + // the image. + // For this reason, we use unusual and extremely ugly colors! :-) + + QDialog frame; + frame.setStyleSheet("*:focus { background: black; color: black } " + "QSpinBox::up-arrow:focus, QSpinBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084 } " + "QComboBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084 }" + "QSlider::handle:horizontal:focus { width: 7px; height: 7px; background: #ff0084 } "); + + QList<QWidget *> widgets; + widgets << new QSpinBox; + widgets << new QComboBox; + widgets << new QSlider(Qt::Horizontal); + + QLayout* layout = new QGridLayout; + layout->addWidget(new QLineEdit); // Avoids initial focus. + foreach (QWidget *widget, widgets) + layout->addWidget(widget); + frame.setLayout(layout); + + frame.show(); + QTest::qWaitForWindowShown(&frame); + QApplication::setActiveWindow(&frame); + foreach (QWidget *widget, widgets) { + widget->setFocus(); + QApplication::processEvents(); + + QImage image(frame.width(), frame.height(), QImage::Format_ARGB32); + frame.render(&image); + if (image.depth() < 24) { + QSKIP("Test doesn't support color depth < 24", SkipAll); + } + + QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)), + (QString::fromLatin1(widget->metaObject()->className()) + + " did not contain text color #ff0084, using style " + + QString::fromLatin1(qApp->style()->metaObject()->className())) + .toLocal8Bit().constData()); + } +} + void tst_QStyleSheetStyle::task188195_baseBackground() { QTreeView tree; diff --git a/tests/auto/qtextcursor/tst_qtextcursor.cpp b/tests/auto/qtextcursor/tst_qtextcursor.cpp index 88ecc73..d910c8d 100644 --- a/tests/auto/qtextcursor/tst_qtextcursor.cpp +++ b/tests/auto/qtextcursor/tst_qtextcursor.cpp @@ -147,6 +147,8 @@ private slots: void task244408_wordUnderCursor_data(); void task244408_wordUnderCursor(); + void adjustCursorsOnInsert(); + private: int blockCount(); @@ -1658,5 +1660,97 @@ void tst_QTextCursor::task244408_wordUnderCursor() QCOMPARE(cursor.selectedText(), expected); } +void tst_QTextCursor::adjustCursorsOnInsert() +{ + cursor.insertText("Some text before "); + int posBefore = cursor.position(); + cursor.insertText("selected text"); + int posAfter = cursor.position(); + cursor.insertText(" some text afterwards"); + + QTextCursor selection = cursor; + selection.setPosition(posBefore); + selection.setPosition(posAfter, QTextCursor::KeepAnchor); + + cursor.setPosition(posBefore-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore+1); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore+1); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter); + doc->undo(); + + cursor.setPosition(posAfter+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter); + doc->undo(); + + selection.setPosition(posAfter); + selection.setPosition(posBefore, QTextCursor::KeepAnchor); + + cursor.setPosition(posBefore-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore+1); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore+1); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter); + doc->undo(); + + + + +} + QTEST_MAIN(tst_QTextCursor) #include "tst_qtextcursor.moc" diff --git a/tests/benchmarks/qanimation/rectanimation.cpp b/tests/benchmarks/qanimation/rectanimation.cpp index e5f2f57..5522847 100644 --- a/tests/benchmarks/qanimation/rectanimation.cpp +++ b/tests/benchmarks/qanimation/rectanimation.cpp @@ -73,9 +73,9 @@ int RectAnimation::duration() const } -void RectAnimation::updateCurrentTime(int msecs) +void RectAnimation::updateCurrentTime() { - qreal progress = m_easing.valueForProgress( qreal(msecs) / qreal(m_dura) ); + qreal progress = m_easing.valueForProgress( currentTime() / qreal(m_dura) ); QRect now; now.setCoords(interpolateInteger(m_start.left(), m_end.left(), progress), interpolateInteger(m_start.top(), m_end.top(), progress), diff --git a/tests/benchmarks/qanimation/rectanimation.h b/tests/benchmarks/qanimation/rectanimation.h index 84ec97d..995becb 100644 --- a/tests/benchmarks/qanimation/rectanimation.h +++ b/tests/benchmarks/qanimation/rectanimation.h @@ -58,7 +58,7 @@ public: void setDuration(int d); int duration() const; - virtual void updateCurrentTime(int msecs); + virtual void updateCurrentTime(); virtual void updateState(QAbstractAnimation::State state); private: diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index be86c93..ed41edb 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -43,6 +43,7 @@ #include <translator.h> +#include <QtCore/QBitArray> #include <QtCore/QDebug> #include <QtCore/QFileInfo> #include <QtCore/QStack> @@ -56,74 +57,133 @@ QT_BEGIN_NAMESPACE /* qmake ignore Q_OBJECT */ -static const char MagicComment[] = "TRANSLATOR "; +static QString MagicComment(QLatin1String("TRANSLATOR")); #define STRING(s) static QString str##s(QLatin1String(#s)) //#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this -uint qHash(const QStringList &qsl) +class HashString { +public: + HashString() : m_hashed(false) {} + explicit HashString(const QString &str) : m_str(str), m_hashed(false) {} + void setValue(const QString &str) { m_str = str; m_hashed = false; } + const QString &value() const { return m_str; } + bool operator==(const HashString &other) const { return m_str == other.m_str; } +private: + QString m_str; + mutable uint m_hash; + mutable bool m_hashed; + friend uint qHash(const HashString &str); +}; + +uint qHash(const HashString &str) { - uint hash = 0; - foreach (const QString &qs, qsl) { - hash ^= qHash(qs) ^ 0xa09df22f; - hash = (hash << 13) | (hash >> 19); + if (!str.m_hashed) { + str.m_hashed = true; + str.m_hash = qHash(str.m_str); + } + return str.m_hash; +} + +class HashStringList { +public: + explicit HashStringList(const QList<HashString> &list) : m_list(list), m_hashed(false) {} + const QList<HashString> &value() const { return m_list; } + bool operator==(const HashStringList &other) const { return m_list == other.m_list; } +private: + QList<HashString> m_list; + mutable uint m_hash; + mutable bool m_hashed; + friend uint qHash(const HashStringList &list); +}; + +uint qHash(const HashStringList &list) +{ + if (!list.m_hashed) { + list.m_hashed = true; + uint hash = 0; + foreach (const HashString &qs, list.m_list) { + hash ^= qHash(qs) ^ 0xa09df22f; + hash = (hash << 13) | (hash >> 19); + } + list.m_hash = hash; } - return hash; + return list.m_hash; } +typedef QList<HashString> NamespaceList; + struct Namespace { Namespace() : - isClass(false), - hasTrFunctions(false), needsTrFunctions(false), complained(false) + classDef(this), + hasTrFunctions(false), complained(false) {} + ~Namespace() + { + qDeleteAll(children); + } - QString name; - QMap<QString, Namespace *> children; - QMap<QString, QStringList> aliases; - QSet<QStringList> usings; + QHash<HashString, Namespace *> children; + QHash<HashString, NamespaceList> aliases; + QList<HashStringList> usings; - int fileId; + // Class declarations set no flags and create no namespaces, so they are ignored. + // Class definitions may appear multiple times - but only because we are trying to + // "compile" all sources irrespective of build configuration. + // Nested classes may be forward-declared inside a definition, and defined in another file. + // The latter will detach the class' child list, so clones need a backlink to the original + // definition (either one in case of multiple definitions). + Namespace *classDef; - bool isClass; + QString trQualification; bool hasTrFunctions; - bool needsTrFunctions; bool complained; // ... that tr functions are missing. }; -typedef QList<Namespace *> NamespaceList; +static int nextFileId; -struct ParseResults { - - ParseResults() +class VisitRecorder { +public: + VisitRecorder() { - static int nextFileId; - rootNamespace.fileId = nextFileId++; - tor = 0; + m_ba.resize(nextFileId); } - bool detachNamespace(Namespace **that); - Namespace *include(Namespace *that, const Namespace *other); - void unite(const ParseResults *other); + bool tryVisit(int fileId) + { + if (m_ba.at(fileId)) + return false; + m_ba[fileId] = true; + return true; + } +private: + QBitArray m_ba; +}; +struct ParseResults { + int fileId; Namespace rootNamespace; - Translator *tor; - QSet<QString> allIncludes; + QSet<const ParseResults *> includes; }; typedef QHash<QString, const ParseResults *> ParseResultHash; +typedef QHash<QString, const Translator *> TranslatorHash; class CppFiles { public: static const ParseResults *getResults(const QString &cleanFile); static void setResults(const QString &cleanFile, const ParseResults *results); + static const Translator *getTranslator(const QString &cleanFile); + static void setTranslator(const QString &cleanFile, const Translator *results); static bool isBlacklisted(const QString &cleanFile); static void setBlacklisted(const QString &cleanFile); private: static ParseResultHash &parsedFiles(); + static TranslatorHash &translatedFiles(); static QSet<QString> &blacklistedFiles(); }; @@ -133,16 +193,16 @@ public: CppParser(ParseResults *results = 0); void setInput(const QString &in); void setInput(QTextStream &ts, const QString &fileName); - void setTranslator(Translator *tor) { results->tor = tor; } + void setTranslator(Translator *_tor) { tor = _tor; } void parse(const QString &initialContext, ConversionData &cd, QSet<QString> &inclusions); void parseInternal(ConversionData &cd, QSet<QString> &inclusions); - const ParseResults *getResults() const { return results; } + const ParseResults *recordResults(bool isHeader); void deleteResults() { delete results; } struct SavedState { - QStringList namespaces; + NamespaceList namespaces; QStack<int> namespaceDepths; - QStringList functionContext; + NamespaceList functionContext; QString functionContextUnresolved; QString pendingContext; }; @@ -164,10 +224,10 @@ private: uint getChar(); uint getToken(); + bool getMacroArgs(); bool match(uint t); bool matchString(QString *s); bool matchEncoding(bool *utf8); - bool matchInteger(qlonglong *number); bool matchStringOrNull(QString *s); bool matchExpression(); @@ -185,15 +245,28 @@ private: static QString stringifyNamespace(const NamespaceList &namespaces); static QStringList stringListifyNamespace(const NamespaceList &namespaces); - void modifyNamespace(NamespaceList *namespaces); - NamespaceList resolveNamespaces(const QStringList &segments); - bool qualifyOne(const NamespaceList &namespaces, int nsIdx, const QString &segment, - NamespaceList *resolved); - bool fullyQualify(const NamespaceList &namespaces, const QStringList &segments, + typedef bool (CppParser::*VisitNamespaceCallback)(const Namespace *ns, void *context) const; + bool visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context, + VisitRecorder &vr, const ParseResults *rslt) const; + bool visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context) const; + static QStringList stringListifySegments(const QList<HashString> &namespaces); + bool qualifyOneCallbackOwn(const Namespace *ns, void *context) const; + bool qualifyOneCallbackUsing(const Namespace *ns, void *context) const; + bool qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, + NamespaceList *resolved) const; + bool fullyQualify(const NamespaceList &namespaces, const QList<HashString> &segments, + bool isDeclaration, + NamespaceList *resolved, QStringList *unresolved) const; + bool fullyQualify(const NamespaceList &namespaces, const QString &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved); - void enterNamespace(NamespaceList *namespaces, const QString &name); + NamespaceList *resolved, QStringList *unresolved) const; + bool findNamespaceCallback(const Namespace *ns, void *context) const; + const Namespace *findNamespace(const NamespaceList &namespaces, int nsCount = -1) const; + void enterNamespace(NamespaceList *namespaces, const HashString &name); void truncateNamespaces(NamespaceList *namespaces, int lenght); + Namespace *modifyNamespace(NamespaceList *namespaces, bool tryOrigin = true); enum { Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, @@ -202,7 +275,7 @@ private: Tok_Ident, Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon, Tok_Equals, Tok_LeftBrace = 30, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon, - Tok_Integer = 40, + Tok_Null = 40, Tok_Integer, Tok_QuotedInclude = 50, Tok_AngledInclude, Tok_Other = 99 }; @@ -227,7 +300,7 @@ private: QTextCodec *yySourceCodec; bool yySourceIsUnicode; QString yyInStr; - int yyInPos; + const ushort *yyInPtr; // Parser state uint yyTok; @@ -239,6 +312,7 @@ private: QString prospectiveContext; QString pendingContext; ParseResults *results; + Translator *tor; bool directInclude; SavedState savedState; @@ -248,6 +322,7 @@ private: CppParser::CppParser(ParseResults *_results) { + tor = 0; if (_results) { results = _results; directInclude = true; @@ -255,7 +330,6 @@ CppParser::CppParser(ParseResults *_results) results = new ParseResults; directInclude = false; } - yyInPos = 0; yyBraceDepth = 0; yyParenDepth = 0; yyCurLineNo = 1; @@ -308,29 +382,32 @@ void CppParser::setInput(QTextStream &ts, const QString &fileName) uint CppParser::getChar() { - int len = yyInStr.size(); - const ushort *uc = (const ushort *)yyInStr.unicode(); + const ushort *uc = yyInPtr; forever { - if (yyInPos >= len) + ushort c = *uc; + if (!c) { + yyInPtr = uc; return EOF; - uint c = uc[yyInPos++]; - if (c == '\\' && yyInPos < len) { - if (uc[yyInPos] == '\n') { + } + ++uc; + if (c == '\\') { + ushort cc = *uc; + if (cc == '\n') { ++yyCurLineNo; - ++yyInPos; + ++uc; continue; } - if (uc[yyInPos] == '\r') { + if (cc == '\r') { ++yyCurLineNo; - ++yyInPos; - if (yyInPos < len && uc[yyInPos] == '\n') - ++yyInPos; + ++uc; + if (*uc == '\n') + ++uc; continue; } } if (c == '\r') { - if (yyInPos < len && uc[yyInPos] == '\n') - ++yyInPos; + if (*uc == '\n') + ++uc; c = '\n'; ++yyCurLineNo; yyAtNewline = true; @@ -340,10 +417,39 @@ uint CppParser::getChar() } else if (c != ' ' && c != '\t' && c != '#') { yyAtNewline = false; } + yyInPtr = uc; return c; } } +// This ignores commas, parens and comments. +// IOW, it understands only a single, simple argument. +bool CppParser::getMacroArgs() +{ + // Failing this assertion would mean losing the preallocated buffer. + Q_ASSERT(yyWord.isDetached()); + yyWord.resize(0); + + while (isspace(yyCh)) + yyCh = getChar(); + if (yyCh != '(') + return false; + do { + yyCh = getChar(); + } while (isspace(yyCh)); + ushort *ptr = (ushort *)yyWord.unicode(); + while (yyCh != ')') { + if (yyCh == EOF) + return false; + *ptr++ = yyCh; + yyCh = getChar(); + } + yyCh = getChar(); + for (; ptr != (ushort *)yyWord.unicode() && isspace(*(ptr - 1)); --ptr) ; + yyWord.resize(ptr - (ushort *)yyWord.unicode()); + return true; +} + STRING(Q_OBJECT); STRING(Q_DECLARE_TR_FUNCTIONS); STRING(QT_TR_NOOP); @@ -561,12 +667,13 @@ uint CppParser::getToken() } } while (yyCh != '\n' && yyCh != EOF); yyCh = getChar(); - } else if (isalpha(yyCh) || yyCh == '_') { + } else if ((yyCh >= 'A' && yyCh <= 'Z') || (yyCh >= 'a' && yyCh <= 'z') || yyCh == '_') { ushort *ptr = (ushort *)yyWord.unicode(); do { *ptr++ = yyCh; yyCh = getChar(); - } while (isalnum(yyCh) || yyCh == '_'); + } while ((yyCh >= 'A' && yyCh <= 'Z') || (yyCh >= 'a' && yyCh <= 'z') + || (yyCh >= '0' && yyCh <= '9') || yyCh == '_'); yyWord.resize(ptr - (ushort *)yyWord.unicode()); //qDebug() << "IDENT: " << yyWord; @@ -795,6 +902,17 @@ uint CppParser::getToken() yyCh = getChar(); return Tok_Semicolon; case '0': + yyCh = getChar(); + if (yyCh == 'x') { + do { + yyCh = getChar(); + } while ((yyCh >= '0' && yyCh <= '9') + || (yyCh >= 'a' && yyCh <= 'f') || (yyCh >= 'A' && yyCh <= 'F')); + return Tok_Integer; + } + if (yyCh < '0' || yyCh > '9') + return Tok_Null; + // Fallthrough case '1': case '2': case '3': @@ -804,25 +922,10 @@ uint CppParser::getToken() case '7': case '8': case '9': - { - QByteArray ba; - ba += yyCh; + do { yyCh = getChar(); - bool hex = yyCh == 'x'; - if (hex) { - ba += yyCh; - yyCh = getChar(); - } - while (hex ? isxdigit(yyCh) : isdigit(yyCh)) { - ba += yyCh; - yyCh = getChar(); - } - bool ok; - yyInteger = ba.toLongLong(&ok); - if (ok) - return Tok_Integer; - break; - } + } while (yyCh >= '0' && yyCh <= '9'); + return Tok_Integer; default: yyCh = getChar(); break; @@ -839,86 +942,40 @@ uint CppParser::getToken() void CppParser::saveState(SavedState *state) { - state->namespaces = stringListifyNamespace(namespaces); + state->namespaces = namespaces; state->namespaceDepths = namespaceDepths; - state->functionContext = stringListifyNamespace(functionContext); + state->functionContext = functionContext; state->functionContextUnresolved = functionContextUnresolved; state->pendingContext = pendingContext; } void CppParser::loadState(const SavedState *state) { - namespaces = resolveNamespaces(state->namespaces); + namespaces = state->namespaces; namespaceDepths = state->namespaceDepths; - functionContext = resolveNamespaces(state->functionContext); + functionContext = state->functionContext; functionContextUnresolved = state->functionContextUnresolved; pendingContext = state->pendingContext; } -bool ParseResults::detachNamespace(Namespace **that) +Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool tryOrigin) { - if ((*that)->fileId != rootNamespace.fileId) { - Namespace *newThat = new Namespace; - *newThat = **that; - newThat->fileId = rootNamespace.fileId; - *that = newThat; - return true; - } - return false; -} - -Namespace *ParseResults::include(Namespace *that, const Namespace *other) -{ - Namespace *origThat = that; - foreach (Namespace *otherSub, other->children) { - if (Namespace *thisSub = that->children.value(otherSub->name)) { - // Don't make these cause a detach - it's best - // (though not necessary) if they are shared - thisSub->isClass |= otherSub->isClass; - thisSub->hasTrFunctions |= otherSub->hasTrFunctions; - thisSub->needsTrFunctions |= otherSub->needsTrFunctions; - thisSub->complained |= otherSub->complained; - - if (Namespace *newSub = include(thisSub, otherSub)) { - thisSub = newSub; - detachNamespace(&that); - that->children[thisSub->name] = thisSub; - } - } else { - detachNamespace(&that); - that->children[otherSub->name] = otherSub; - } - } - if ((that->aliases != other->aliases && !other->aliases.isEmpty()) - || (that->usings != other->usings && !other->usings.isEmpty())) { - detachNamespace(&that); - that->aliases.unite(other->aliases); - that->usings.unite(other->usings); - } - return (that != origThat) ? that : 0; -} - -void ParseResults::unite(const ParseResults *other) -{ - allIncludes.unite(other->allIncludes); - include(&rootNamespace, &other->rootNamespace); -} - -void CppParser::modifyNamespace(NamespaceList *namespaces) -{ - Namespace *pns = 0; - int i = namespaces->count(); - forever { - --i; - Namespace *ns = namespaces->at(i); - bool detached = results->detachNamespace(&ns); - if (pns) - ns->children[pns->name] = pns; - if (!detached) // Known to be true for root namespace - return; + Namespace *pns, *ns = &results->rootNamespace; + for (int i = 1; i < namespaces->count(); ++i) { pns = ns; - namespaces->replace(i, ns); + if (!(ns = pns->children.value(namespaces->at(i)))) { + do { + ns = new Namespace; + if (tryOrigin) + if (const Namespace *ons = findNamespace(*namespaces, i + 1)) + ns->classDef = ons->classDef; + pns->children.insert(namespaces->at(i), ns); + pns = ns; + } while (++i < namespaces->count()); + break; + } } + return ns; } QString CppParser::stringifyNamespace(const NamespaceList &namespaces) @@ -927,7 +984,7 @@ QString CppParser::stringifyNamespace(const NamespaceList &namespaces) for (int i = 1; i < namespaces.count(); ++i) { if (i > 1) ret += QLatin1String("::"); - ret += namespaces.at(i)->name; + ret += namespaces.at(i).value(); } return ret; } @@ -936,58 +993,102 @@ QStringList CppParser::stringListifyNamespace(const NamespaceList &namespaces) { QStringList ret; for (int i = 1; i < namespaces.count(); ++i) - ret << namespaces.at(i)->name; + ret << namespaces.at(i).value(); return ret; } -// This function is called only with known-existing namespaces -NamespaceList CppParser::resolveNamespaces(const QStringList &segments) +bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context, + VisitRecorder &vr, const ParseResults *rslt) const { - NamespaceList ret; - Namespace *ns = &results->rootNamespace; - ret << ns; - foreach (const QString &seg, segments) { - ns = ns->children.value(seg); - ret << ns; - } + const Namespace *ns = &rslt->rootNamespace; + for (int i = 1; i < nsCount; ++i) + if (!(ns = ns->children.value(namespaces.at(i)))) + goto supers; + if ((this->*callback)(ns, context)) + return true; +supers: + foreach (const ParseResults *sup, rslt->includes) + if (vr.tryVisit(sup->fileId) + && visitNamespace(namespaces, nsCount, callback, context, vr, sup)) + return true; + return false; +} + +bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context) const +{ + VisitRecorder vr; + return visitNamespace(namespaces, nsCount, callback, context, vr, results); +} + +QStringList CppParser::stringListifySegments(const QList<HashString> &segments) +{ + QStringList ret; + for (int i = 0; i < segments.count(); ++i) + ret << segments.at(i).value(); return ret; } -bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsIdx, const QString &segment, - NamespaceList *resolved) +struct QualifyOneData { + const NamespaceList &namespaces; + int nsCount; + const HashString &segment; + NamespaceList *resolved; + QSet<HashStringList> visitedUsings; +}; + +bool CppParser::qualifyOneCallbackOwn(const Namespace *ns, void *context) const { - const Namespace *ns = namespaces.at(nsIdx); - QMap<QString, Namespace *>::ConstIterator cnsi = ns->children.constFind(segment); - if (cnsi != ns->children.constEnd()) { - *resolved = namespaces.mid(0, nsIdx + 1); - *resolved << *cnsi; + QualifyOneData *data = (QualifyOneData *)context; + if (ns->children.contains(data->segment)) { + *data->resolved = data->namespaces.mid(0, data->nsCount); + *data->resolved << data->segment; return true; } - QMap<QString, QStringList>::ConstIterator nsai = ns->aliases.constFind(segment); + QHash<HashString, NamespaceList>::ConstIterator nsai = ns->aliases.constFind(data->segment); if (nsai != ns->aliases.constEnd()) { - *resolved = resolveNamespaces(*nsai); + *data->resolved = *nsai; return true; } - foreach (const QStringList &use, ns->usings) { - NamespaceList usedNs = resolveNamespaces(use); - if (qualifyOne(usedNs, usedNs.count() - 1, segment, resolved)) - return true; - } return false; } -bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList &segments, +bool CppParser::qualifyOneCallbackUsing(const Namespace *ns, void *context) const +{ + QualifyOneData *data = (QualifyOneData *)context; + foreach (const HashStringList &use, ns->usings) + if (!data->visitedUsings.contains(use)) { + data->visitedUsings.insert(use); + if (qualifyOne(use.value(), use.value().count(), data->segment, data->resolved)) + return true; + } + return false; +} + +bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, + NamespaceList *resolved) const +{ + QualifyOneData data = { namespaces, nsCnt, segment, resolved, QSet<HashStringList>() }; + + if (visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackOwn, &data)) + return true; + + return visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackUsing, &data); +} + +bool CppParser::fullyQualify(const NamespaceList &namespaces, const QList<HashString> &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved) + NamespaceList *resolved, QStringList *unresolved) const { int nsIdx; int initSegIdx; - if (segments.first().isEmpty()) { + if (segments.first().value().isEmpty()) { // fully qualified if (segments.count() == 1) { resolved->clear(); - *resolved << &results->rootNamespace; + *resolved << HashString(QString()); return true; } initSegIdx = 1; @@ -998,12 +1099,12 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList } do { - if (qualifyOne(namespaces, nsIdx, segments[initSegIdx], resolved)) { + if (qualifyOne(namespaces, nsIdx + 1, segments[initSegIdx], resolved)) { int segIdx = initSegIdx; while (++segIdx < segments.count()) { - if (!qualifyOne(*resolved, resolved->count() - 1, segments[segIdx], resolved)) { + if (!qualifyOne(*resolved, resolved->count(), segments[segIdx], resolved)) { if (unresolved) - *unresolved = segments.mid(segIdx); + *unresolved = stringListifySegments(segments.mid(segIdx)); return false; } } @@ -1011,23 +1112,44 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList } } while (!isDeclaration && --nsIdx >= 0); resolved->clear(); - *resolved << &results->rootNamespace; + *resolved << HashString(QString()); if (unresolved) - *unresolved = segments.mid(initSegIdx); + *unresolved = stringListifySegments(segments.mid(initSegIdx)); return false; } -void CppParser::enterNamespace(NamespaceList *namespaces, const QString &name) +bool CppParser::fullyQualify(const NamespaceList &namespaces, const QString &quali, + bool isDeclaration, + NamespaceList *resolved, QStringList *unresolved) const { - Namespace *ns = namespaces->last()->children.value(name); - if (!ns) { - ns = new Namespace; - ns->fileId = results->rootNamespace.fileId; - ns->name = name; - modifyNamespace(namespaces); - namespaces->last()->children[name] = ns; - } - *namespaces << ns; + static QString strColons(QLatin1String("::")); + + QList<HashString> segments; + foreach (const QString &str, quali.split(strColons)) // XXX slow, but needs to be fast(?) + segments << HashString(str); + return fullyQualify(namespaces, segments, isDeclaration, resolved, unresolved); +} + +bool CppParser::findNamespaceCallback(const Namespace *ns, void *context) const +{ + *((const Namespace **)context) = ns; + return true; +} + +const Namespace *CppParser::findNamespace(const NamespaceList &namespaces, int nsCount) const +{ + const Namespace *ns = 0; + if (nsCount == -1) + nsCount = namespaces.count(); + visitNamespace(namespaces, nsCount, &CppParser::findNamespaceCallback, &ns); + return ns; +} + +void CppParser::enterNamespace(NamespaceList *namespaces, const HashString &name) +{ + *namespaces << name; + if (!findNamespace(*namespaces)) + modifyNamespace(namespaces, false); } void CppParser::truncateNamespaces(NamespaceList *namespaces, int length) @@ -1047,6 +1169,13 @@ ParseResultHash &CppFiles::parsedFiles() return parsed; } +TranslatorHash &CppFiles::translatedFiles() +{ + static TranslatorHash tors; + + return tors; +} + QSet<QString> &CppFiles::blacklistedFiles() { static QSet<QString> blacklisted; @@ -1056,10 +1185,7 @@ QSet<QString> &CppFiles::blacklistedFiles() const ParseResults *CppFiles::getResults(const QString &cleanFile) { - ParseResultHash::ConstIterator it = parsedFiles().find(cleanFile); - if (it == parsedFiles().constEnd()) - return 0; - return *it; + return parsedFiles().value(cleanFile); } void CppFiles::setResults(const QString &cleanFile, const ParseResults *results) @@ -1067,6 +1193,16 @@ void CppFiles::setResults(const QString &cleanFile, const ParseResults *results) parsedFiles().insert(cleanFile, results); } +const Translator *CppFiles::getTranslator(const QString &cleanFile) +{ + return translatedFiles().value(cleanFile); +} + +void CppFiles::setTranslator(const QString &cleanFile, const Translator *tor) +{ + translatedFiles().insert(cleanFile, tor); +} + bool CppFiles::isBlacklisted(const QString &cleanFile) { return blacklistedFiles().contains(cleanFile); @@ -1077,6 +1213,12 @@ void CppFiles::setBlacklisted(const QString &cleanFile) blacklistedFiles().insert(cleanFile); } +static bool isHeader(const QString &name) +{ + QString fileExt = QFileInfo(name).suffix(); + return fileExt.isEmpty() || fileExt.startsWith(QLatin1Char('h'), Qt::CaseInsensitive); +} + void CppParser::processInclude(const QString &file, ConversionData &cd, QSet<QString> &inclusions) { @@ -1095,21 +1237,15 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, bool isIndirect = false; if (namespaces.count() == 1 && functionContext.count() == 1 && functionContextUnresolved.isEmpty() && pendingContext.isEmpty() - && !CppFiles::isBlacklisted(cleanFile)) { - QString fileExt = QFileInfo(cleanFile).suffix(); - if (fileExt.isEmpty() || fileExt.startsWith(QLatin1Char('h'), Qt::CaseInsensitive)) { - - if (results->allIncludes.contains(cleanFile)) - return; - results->allIncludes.insert(cleanFile); + && !CppFiles::isBlacklisted(cleanFile) + && isHeader(cleanFile)) { - if (const ParseResults *res = CppFiles::getResults(cleanFile)) { - results->unite(res); - return; - } - - isIndirect = true; + if (const ParseResults *res = CppFiles::getResults(cleanFile)) { + results->includes.insert(res); + return; } + + isIndirect = true; } QFile f(cleanFile); @@ -1134,8 +1270,7 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, } parser.setInput(ts, cleanFile); parser.parse(cd.m_defaultContext, cd, inclusions); - CppFiles::setResults(cleanFile, parser.getResults()); - results->unite(parser.results); + results->includes.insert(parser.recordResults(true)); } else { CppParser parser(results); parser.namespaces = namespaces; @@ -1144,12 +1279,6 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, parser.pendingContext = pendingContext; parser.setInput(ts, cleanFile); parser.parseInternal(cd, inclusions); - // Don't wreak havoc if not enough braces were found. - truncateNamespaces(&parser.namespaces, namespaces.count()); - truncateNamespaces(&parser.functionContext, functionContext.count()); - // Copy them back - the pointers might have changed. - namespaces = parser.namespaces; - functionContext = parser.functionContext; // Avoid that messages obtained by direct scanning are used CppFiles::setBlacklisted(cleanFile); } @@ -1176,26 +1305,28 @@ bool CppParser::match(uint t) bool CppParser::matchString(QString *s) { - bool matches = (yyTok == Tok_String); + bool matches = false; s->clear(); - while (yyTok == Tok_String) { + forever { + while (yyTok == Tok_Comment) + yyTok = getToken(); + if (yyTok != Tok_String) + return matches; + matches = true; *s += yyWord; s->detach(); - do { - yyTok = getToken(); - } while (yyTok == Tok_Comment); + yyTok = getToken(); } - return matches; } +STRING(QApplication); +STRING(QCoreApplication); +STRING(UnicodeUTF8); +STRING(DefaultCodec); +STRING(CodecForTr); + bool CppParser::matchEncoding(bool *utf8) { - STRING(QApplication); - STRING(QCoreApplication); - STRING(UnicodeUTF8); - STRING(DefaultCodec); - STRING(CodecForTr); - if (yyTok != Tok_Ident) return false; if (yyWord == strQApplication || yyWord == strQCoreApplication) { @@ -1211,28 +1342,14 @@ bool CppParser::matchEncoding(bool *utf8) if (yyWord == strDefaultCodec || yyWord == strCodecForTr) { *utf8 = false; yyTok = getToken(); - return true; + return true; } return false; } -bool CppParser::matchInteger(qlonglong *number) -{ - bool matches = (yyTok == Tok_Integer); - if (matches) { - yyTok = getToken(); - *number = yyInteger; - } - return matches; -} - bool CppParser::matchStringOrNull(QString *s) { - bool matches = matchString(s); - qlonglong num = 0; - if (!matches) - matches = matchInteger(&num); - return matches && num == 0; + return matchString(s) || match(Tok_Null); } /* @@ -1251,7 +1368,7 @@ bool CppParser::matchStringOrNull(QString *s) */ bool CppParser::matchExpression() { - if (match(Tok_Integer)) + if (match(Tok_Null) || match(Tok_Integer)) return true; int parenlevel = 0; @@ -1339,16 +1456,16 @@ void CppParser::recordMessage( msg.setExtras(extra); if ((utf8 || yyForceUtf8) && !yyCodecIsUtf8 && msg.needs8Bit()) msg.setUtf8(true); - results->tor->append(msg); + tor->append(msg); } void CppParser::parse(const QString &initialContext, ConversionData &cd, QSet<QString> &inclusions) { - if (results->tor) - yyCodecIsUtf8 = (results->tor->codecName() == "UTF-8"); + if (tor) + yyCodecIsUtf8 = (tor->codecName() == "UTF-8"); - namespaces << &results->rootNamespace; + namespaces << HashString(); functionContext = namespaces; functionContextUnresolved = initialContext; @@ -1375,6 +1492,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) bool yyTokColonSeen = false; // Start of c'tor's initializer list yyWord.reserve(yyInStr.size()); // Rather insane. That's because we do no length checking. + yyInPtr = (const ushort *)yyInStr.unicode(); yyCh = getChar(); yyTok = getToken(); while (yyTok != Tok_Eof) { @@ -1411,8 +1529,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } case Tok_friend: yyTok = getToken(); - // Ensure that these don't end up being interpreted as forward declarations - // (they are forwards, but with different namespacing). + // These are forward declarations, so ignore them. if (yyTok == Tok_class) yyTok = getToken(); break; @@ -1423,7 +1540,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) */ yyTok = getToken(); if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) { - QStringList fct; + QList<HashString> quali; + HashString fct; do { /* This code should execute only once, but we play @@ -1433,50 +1551,50 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) */ text = yyWord; text.detach(); - fct = QStringList(text); + fct.setValue(text); yyTok = getToken(); } while (yyTok == Tok_Ident); while (yyTok == Tok_ColonColon) { yyTok = getToken(); if (yyTok != Tok_Ident) break; // Oops ... + quali << fct; text = yyWord; text.detach(); - fct += text; + fct.setValue(text); yyTok = getToken(); } - if (fct.count() > 1) { - // Forward-declared class definitions can be namespaced - NamespaceList nsl; - if (!fullyQualify(namespaces, fct, true, &nsl, 0)) { - qWarning("%s:%d: Ignoring definition of undeclared qualified class\n", - qPrintable(yyFileName), yyLineNo); - break; - } - namespaceDepths.push(namespaces.count()); - namespaces = nsl; - } else { - namespaceDepths.push(namespaces.count()); - enterNamespace(&namespaces, fct.first()); - } - namespaces.last()->isClass = true; - while (yyTok == Tok_Comment) yyTok = getToken(); if (yyTok == Tok_Colon) { - // Skip any token until '{' since lupdate might do things wrong if it finds + // Skip any token until '{' since we might do things wrong if we find // a '::' token here. do { yyTok = getToken(); } while (yyTok != Tok_LeftBrace && yyTok != Tok_Eof); } else { if (yyTok != Tok_LeftBrace) { - // Obviously a forward decl - truncateNamespaces(&namespaces, namespaceDepths.pop()); + // Obviously a forward declaration. We skip those, as they + // don't create actually usable namespaces. break; } } + if (!quali.isEmpty()) { + // Forward-declared class definitions can be namespaced. + NamespaceList nsl; + if (!fullyQualify(namespaces, quali, true, &nsl, 0)) { + qWarning("%s:%d: Ignoring definition of undeclared qualified class\n", + qPrintable(yyFileName), yyLineNo); + break; + } + namespaceDepths.push(namespaces.count()); + namespaces = nsl; + } else { + namespaceDepths.push(namespaces.count()); + } + enterNamespace(&namespaces, fct); + functionContext = namespaces; functionContextUnresolved.clear(); // Pointless prospectiveContext.clear(); @@ -1487,8 +1605,9 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) yyTokColonSeen = false; yyTok = getToken(); if (yyTok == Tok_Ident) { - QString ns = yyWord; - ns.detach(); + text = yyWord; + text.detach(); + HashString ns = HashString(text); yyTok = getToken(); if (yyTok == Tok_LeftBrace) { namespaceDepths.push(namespaces.count()); @@ -1496,25 +1615,23 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) yyTok = getToken(); } else if (yyTok == Tok_Equals) { // e.g. namespace Is = OuterSpace::InnerSpace; - QStringList fullName; + QList<HashString> fullName; yyTok = getToken(); if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } if (fullName.isEmpty()) break; NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { - modifyNamespace(&namespaces); - namespaces.last()->aliases.insert(ns, stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, false)->aliases[ns] = nsl; } } else if (yyTok == Tok_LeftBrace) { // Anonymous namespace @@ -1524,49 +1641,45 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) break; case Tok_using: yyTok = getToken(); + // XXX this should affect only the current scope, not the entire current namespace if (yyTok == Tok_namespace) { - QStringList fullName; + QList<HashString> fullName; yyTok = getToken(); if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } NamespaceList nsl; - QStringList unresolved; - if (fullyQualify(namespaces, fullName, false, &nsl, &unresolved)) { - modifyNamespace(&namespaces); - namespaces.last()->usings.insert(stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, false)->usings << HashStringList(nsl); } else { - QStringList fullName; + QList<HashString> fullName; if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } if (fullName.isEmpty()) break; NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { - modifyNamespace(&namespaces); - namespaces.last()->aliases.insert(nsl.last()->name, stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, true)->aliases[nsl.last()] = nsl; } break; case Tok_tr: case Tok_trUtf8: - if (!results->tor) + if (!tor) goto case_default; if (!sourcetext.isEmpty()) qWarning("%s:%d: //%% cannot be used with tr() / QT_TR_NOOP(). Ignoring\n", @@ -1589,8 +1702,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } if (!pendingContext.isEmpty()) { QStringList unresolved; - if (!fullyQualify(namespaces, pendingContext.split(strColons), true, - &functionContext, &unresolved)) { + if (!fullyQualify(namespaces, pendingContext, true, &functionContext, &unresolved)) { functionContextUnresolved = unresolved.join(strColons); qWarning("%s:%d: Qualifying with unknown namespace/class %s::%s\n", qPrintable(yyFileName), yyLineNo, @@ -1607,25 +1719,32 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) qPrintable(yyFileName), yyLineNo); break; } - while (!functionContext.at(idx - 1)->hasTrFunctions) { - if (idx == 1 || !functionContext.at(idx - 2)->isClass) { - idx = functionContext.length(); - if (!functionContext.last()->complained) { + Namespace *fctx; + while (!(fctx = findNamespace(functionContext, idx)->classDef)->hasTrFunctions) { + if (idx == 1) { + context = stringifyNamespace(functionContext); + fctx = findNamespace(functionContext)->classDef; + if (!fctx->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, - qPrintable(stringifyNamespace(functionContext))); - functionContext.last()->complained = true; + qPrintable(context)); + fctx->complained = true; } - break; + goto gotctx; } --idx; } - context.clear(); - for (int i = 1;;) { - context += functionContext.at(i)->name; - if (++i == idx) - break; - context += strColons; + if (fctx->trQualification.isEmpty()) { + context.clear(); + for (int i = 1;;) { + context += functionContext.at(i).value(); + if (++i == idx) + break; + context += strColons; + } + fctx->trQualification = context; + } else { + context = fctx->trQualification; } } else { context = (stringListifyNamespace(functionContext) @@ -1644,20 +1763,27 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) prefix.chop(2); NamespaceList nsl; QStringList unresolved; - if (fullyQualify(functionContext, prefix.split(strColons), false, &nsl, &unresolved)) { - if (!nsl.last()->hasTrFunctions && !nsl.last()->complained) { + if (fullyQualify(functionContext, prefix, false, &nsl, &unresolved)) { + Namespace *fctx = findNamespace(nsl)->classDef; + if (fctx->trQualification.isEmpty()) { + context = stringifyNamespace(nsl); + fctx->trQualification = context; + } else { + context = fctx->trQualification; + } + if (!fctx->hasTrFunctions && !fctx->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, - qPrintable(stringifyNamespace(nsl))); - nsl.last()->complained = true; + qPrintable(context)); + fctx->complained = true; } - context = stringifyNamespace(nsl); } else { context = (stringListifyNamespace(nsl) + unresolved).join(strColons); } prefix.clear(); } + gotctx: recordMessage(line, context, text, comment, extracomment, msgid, extra, utf8, plural); } extracomment.clear(); @@ -1666,7 +1792,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) break; case Tok_translateUtf8: case Tok_translate: - if (!results->tor) + if (!tor) goto case_default; if (!sourcetext.isEmpty()) qWarning("%s:%d: //%% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n", @@ -1721,7 +1847,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) extra.clear(); break; case Tok_trid: - if (!results->tor) + if (!tor) goto case_default; if (sourcetext.isEmpty()) { yyTok = getToken(); @@ -1744,8 +1870,16 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) extra.clear(); break; case Tok_Q_DECLARE_TR_FUNCTIONS: + if (getMacroArgs()) { + Namespace *ns = modifyNamespace(&namespaces, true); + ns->hasTrFunctions = true; + ns->trQualification = yyWord; + ns->trQualification.detach(); + } + yyTok = getToken(); + break; case Tok_Q_OBJECT: - namespaces.last()->hasTrFunctions = true; + modifyNamespace(&namespaces, true)->hasTrFunctions = true; yyTok = getToken(); break; case Tok_Ident: @@ -1759,7 +1893,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } break; case Tok_Comment: - if (!results->tor) + if (!tor) goto case_default; if (yyWord.startsWith(QLatin1Char(':'))) { yyWord.remove(0, 1); @@ -1814,9 +1948,15 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } sourcetext.resize(ptr - (ushort *)sourcetext.data()); } else { - comment = yyWord.simplified(); - if (comment.startsWith(QLatin1String(MagicComment))) { - comment.remove(0, sizeof(MagicComment) - 1); + const ushort *uc = (const ushort *)yyWord.unicode(); // Is zero-terminated + int idx = 0; + ushort c; + while ((c = uc[idx]) == ' ' || c == '\t' || c == '\n') + ++idx; + if (!memcmp(uc + idx, MagicComment.unicode(), MagicComment.length() * 2)) { + idx += MagicComment.length(); + comment = QString::fromRawData(yyWord.unicode() + idx, + yyWord.length() - idx).simplified(); int k = comment.indexOf(QLatin1Char(' ')); if (k == -1) { context = comment; @@ -1826,11 +1966,9 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) recordMessage(yyLineNo, context, QString(), comment, extracomment, QString(), TranslatorMessage::ExtraData(), false, false); extracomment.clear(); - results->tor->setExtras(extra); + tor->setExtras(extra); extra.clear(); } - } else { - comment.detach(); } } yyTok = getToken(); @@ -1854,17 +1992,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) #endif break; case Tok_RightBrace: - if (yyBraceDepth + 1 == namespaceDepths.count()) { - // class or namespace - Namespace *ns = namespaces.last(); - if (ns->needsTrFunctions && !ns->hasTrFunctions && !ns->complained) { - qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", - qPrintable(yyFileName), yyLineNo, - qPrintable(stringifyNamespace(namespaces))); - ns->complained = true; - } + if (yyBraceDepth + 1 == namespaceDepths.count()) // class or namespace truncateNamespaces(&namespaces, namespaceDepths.pop()); - } if (yyBraceDepth == namespaceDepths.count()) { // function, class or namespace if (!yyBraceDepth && !directInclude) { @@ -1922,6 +2051,37 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) qPrintable(yyFileName), yyParenLineNo); } +const ParseResults *CppParser::recordResults(bool isHeader) +{ + if (tor) { + if (tor->messageCount()) { + CppFiles::setTranslator(yyFileName, tor); + } else { + delete tor; + tor = 0; + } + } + if (isHeader) { + const ParseResults *pr; + if (!tor && results->includes.count() == 1 + && results->rootNamespace.children.isEmpty() + && results->rootNamespace.aliases.isEmpty() + && results->rootNamespace.usings.isEmpty()) { + // This is a forwarding header. Slash it. + pr = *results->includes.begin(); + delete results; + } else { + results->fileId = nextFileId++; + pr = results; + } + CppFiles::setResults(yyFileName, pr); + return pr; + } else { + delete results; + return 0; + } +} + /* Fetches tr() calls in C++ code in UI files (inside "<function>" tag). This mechanism is obsolete. @@ -1966,12 +2126,12 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat parser.setTranslator(tor); QSet<QString> inclusions; parser.parse(cd.m_defaultContext, cd, inclusions); - CppFiles::setResults(filename, parser.getResults()); + parser.recordResults(isHeader(filename)); } - foreach (const QString filename, filenames) + foreach (const QString &filename, filenames) if (!CppFiles::isBlacklisted(filename)) - if (Translator *tor = CppFiles::getResults(filename)->tor) + if (const Translator *tor = CppFiles::getTranslator(filename)) foreach (const TranslatorMessage &msg, tor->messages()) translator.extend(msg); } diff --git a/tools/linguist/lupdate/main.cpp b/tools/linguist/lupdate/main.cpp index 3cba90d..e8cf121 100644 --- a/tools/linguist/lupdate/main.cpp +++ b/tools/linguist/lupdate/main.cpp @@ -62,23 +62,14 @@ static void printOut(const QString & out) } static void recursiveFileInfoList(const QDir &dir, - const QStringList &nameFilters, QDir::Filters filter, bool recursive, + const QSet<QString> &nameFilters, QDir::Filters filter, QFileInfoList *fileinfolist) { - if (recursive) - filter |= QDir::AllDirs; - QFileInfoList entries = dir.entryInfoList(nameFilters, filter); - - QFileInfoList::iterator it; - for (it = entries.begin(); it != entries.end(); ++it) { - QString fname = it->fileName(); - if (fname != QLatin1String(".") && fname != QLatin1String("..")) { - if (it->isDir()) - recursiveFileInfoList(QDir(it->absoluteFilePath()), nameFilters, filter, recursive, fileinfolist); - else - fileinfolist->append(*it); - } - } + foreach (const QFileInfo &fi, dir.entryInfoList(filter)) + if (fi.isDir()) + recursiveFileInfoList(QDir(fi.absoluteFilePath()), nameFilters, filter, fileinfolist); + else if (nameFilters.contains(fi.suffix())) + fileinfolist->append(fi); } static void printUsage() @@ -243,7 +234,7 @@ int main(int argc, char **argv) bool recursiveScan = true; QString extensions = m_defaultExtensions; - QStringList extensionsNameFilters; + QSet<QString> extensionsNameFilters; for (int i = 1; i < argc; ++i) { if (args.at(i) == QLatin1String("-ts")) @@ -418,15 +409,15 @@ int main(int argc, char **argv) foreach (QString ext, extensions.split(QLatin1Char(','))) { ext = ext.trimmed(); if (ext.startsWith(QLatin1Char('.'))) - ext.remove(0,1); - ext.insert(0, QLatin1String("*.")); - extensionsNameFilters << ext; + ext.remove(0, 1); + extensionsNameFilters.insert(ext); } } QDir::Filters filters = QDir::Files | QDir::NoSymLinks; + if (recursiveScan) + filters |= QDir::AllDirs | QDir::NoDotAndDotDot; QFileInfoList fileinfolist; - recursiveFileInfoList(dir, extensionsNameFilters, filters, - recursiveScan, &fileinfolist); + recursiveFileInfoList(dir, extensionsNameFilters, filters, &fileinfolist); int scanRootLen = dir.absolutePath().length(); foreach (const QFileInfo &fi, fileinfolist) { QString fn = QDir::cleanPath(fi.absoluteFilePath()); |