From 3ed427637dd76da371174e14b0f7f2a15801fcac Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 2 Dec 2009 11:39:44 +0000 Subject: Added error strings to Phonon MMF backend Note that changing Utils from a namespace into a class, and then using Q_DECLARE_TR_FUNCTIONS in the class declaration, was necessary in order to be able to call tr(...) from the implementation of Utils::symbianErrorToString. Task-number: QTBUG-4994 Reviewed-by: Oswald Buddenhagen --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 26 ++++--- src/3rdparty/phonon/mmf/abstractplayer.cpp | 12 ++- src/3rdparty/phonon/mmf/abstractplayer.h | 16 +++- src/3rdparty/phonon/mmf/audioplayer.cpp | 13 ++-- src/3rdparty/phonon/mmf/mediaobject.cpp | 12 +-- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 22 +++--- src/3rdparty/phonon/mmf/utils.cpp | 98 +++++++++++++++++++++++++ src/3rdparty/phonon/mmf/utils.h | 22 ++++-- 8 files changed, 170 insertions(+), 51 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 99e96cd..bc38513 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -70,7 +70,7 @@ void MMF::AbstractMediaPlayer::play() switch (privateState()) { case GroundState: - setError(NormalError); + setError(tr("Not ready to play")); break; case LoadingState: @@ -226,10 +226,13 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f m_source = source; TInt symbianErr = KErrNone; + QString errorMessage; switch (m_source.type()) { case MediaSource::LocalFile: { symbianErr = openFile(file); + if (KErrNone != symbianErr) + errorMessage = tr("Error opening file"); break; } @@ -238,11 +241,12 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f if (url.scheme() == QLatin1String("file")) { symbianErr = openFile(file); + if (KErrNone != symbianErr) + errorMessage = tr("Error opening URL"); } else { - TRACE_0("Source type not supported"); - // TODO: support network URLs - symbianErr = KErrNotSupported; + TRACE_0("Error opening URL: protocol not supported"); + errorMessage = tr("Error opening URL: protocol not supported"); } break; @@ -251,8 +255,8 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f case MediaSource::Invalid: case MediaSource::Disc: case MediaSource::Stream: - TRACE_0("Source type not supported"); - symbianErr = KErrNotSupported; + TRACE_0("Error opening source: type not supported"); + errorMessage = tr("Error opening source: type not supported"); break; case MediaSource::Empty: @@ -265,11 +269,13 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f TRACE_PANIC(InvalidMediaTypePanic); } - if (KErrNone == symbianErr) { + if (errorMessage.isEmpty()) { changeState(LoadingState); } else { - TRACE("error %d", symbianErr) - setError(NormalError); + if (symbianErr) + setError(errorMessage, symbianErr); + else + setError(errorMessage); } TRACE_EXIT_0(); @@ -318,7 +324,7 @@ void MMF::AbstractMediaPlayer::doVolumeChanged() const int err = setDeviceVolume(volume); if (KErrNone != err) { - setError(NormalError); + setError(tr("Setting volume failed"), err); } break; } diff --git a/src/3rdparty/phonon/mmf/abstractplayer.cpp b/src/3rdparty/phonon/mmf/abstractplayer.cpp index caf4092..13ff5fb 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractplayer.cpp @@ -113,19 +113,23 @@ void MMF::AbstractPlayer::videoOutputChanged() // Default behaviour is empty - overridden by VideoPlayer } -void MMF::AbstractPlayer::setError(Phonon::ErrorType error, - const QString &errorMessage) +void MMF::AbstractPlayer::setError(const QString &errorMessage) { TRACE_CONTEXT(AbstractPlayer::setError, EAudioInternal); - TRACE_ENTRY("state %d error %d", m_state, error); + TRACE_ENTRY("state %d", m_state); - m_error = error; + m_error = Phonon::NormalError; m_errorString = errorMessage; changeState(ErrorState); TRACE_EXIT_0(); } +void MMF::AbstractPlayer::setError(const QString &errorMessage, int symbianError) +{ + setError(errorMessage + ": " + Utils::symbianErrorToString(symbianError)); +} + Phonon::ErrorType MMF::AbstractPlayer::errorType() const { const Phonon::ErrorType result = (ErrorState == m_state) diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h index 2e9cfa0..9af1362 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.h +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -87,10 +87,20 @@ public: void setVideoOutput(VideoOutput* videoOutput); /** - * Records error and changes state to ErrorState + * Records error message and changes state to ErrorState */ - void setError(Phonon::ErrorType error, - const QString &errorMessage = QString()); + void setError(const QString &errorMessage); + + /** + * Records error message and changes state to ErrorState + * + * Appends a human-readable version of symbianErrorCode to the error message, + * e.g. + * setError(NormalError, "Opening file failed", KErrPermissionDenied) + * results in the following error message: + * "Opening file failed: permission denied" + */ + void setError(const QString &errorMessage, int symbianErrorCode); Phonon::State state() const; diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 8fccfe6..72d6684 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -51,9 +51,8 @@ void MMF::AudioPlayer::construct() TRACE_ENTRY_0(); TRAPD(err, m_player.reset(CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone))); - if (KErrNone != err) { - changeState(ErrorState); - } + if (KErrNone != err) + setError("Creation of audio player failed", err); TRACE_EXIT_0(); } @@ -151,7 +150,7 @@ qint64 MMF::AudioPlayer::currentTime() const // If we don't cast away constness here, we simply have to ignore // the error. - const_cast(this)->setError(NormalError); + const_cast(this)->setError(tr("Getting position failed"), err); } return result; @@ -186,8 +185,7 @@ void MMF::AudioPlayer::MapcInitComplete(TInt aError, updateMetaData(); changeState(StoppedState); } else { - // TODO: set different error states according to value of aError? - setError(NormalError); + setError(tr("Opening clip failed"), aError); } TRACE_EXIT_0(); @@ -208,8 +206,7 @@ void MMF::AudioPlayer::MapcPlayComplete(TInt aError) changeState(StoppedState); // TODO: move on to m_nextSource } else { - // TODO: do something with aError? - setError(NormalError); + setError(tr("Playback complete"), aError); } /* diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index 21dcfe1..6158ca1 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -238,7 +238,6 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) const bool oldPlayerHasVideo = oldPlayer->hasVideo(); const bool oldPlayerSeekable = oldPlayer->isSeekable(); - Phonon::ErrorType error = NoError; QString errorMessage; // Determine media type @@ -255,7 +254,6 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) } else { errorMessage = QLatin1String("Network streaming not supported yet"); - error = NormalError; } } break; @@ -263,8 +261,7 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) case MediaSource::Invalid: case MediaSource::Disc: case MediaSource::Stream: - TRACE_0("Unsupported media type"); - error = NormalError; + errorMessage = tr("Error opening source: type not supported"); break; case MediaSource::Empty: @@ -287,8 +284,7 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) newPlayer = new DummyPlayer(); } - error = NormalError; - errorMessage = tr("Media type could not be determined"); + errorMessage = tr("Error opening source: media type could not be determined"); break; case MediaTypeAudio: @@ -326,9 +322,9 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) // We need to call setError() after doing the connects, otherwise the // error won't be received. - if (error != NoError) { + if (!errorMessage.isEmpty()) { Q_ASSERT(m_player); - m_player->setError(error, errorMessage); + m_player->setError(errorMessage); } TRACE_EXIT_0(); diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index b6f53ae..4619f54 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -93,7 +93,7 @@ void MMF::VideoPlayer::construct() m_dsaActive = true; if (KErrNone != err) - changeState(ErrorState); + setError("Creation of video player failed", err); TRACE_EXIT_0(); } @@ -129,7 +129,7 @@ void MMF::VideoPlayer::doPause() TRAPD(err, m_player->PauseL()); if (KErrNone != err) { TRACE("PauseL error %d", err); - setError(NormalError); + setError(tr("Pause failed"), err); } } @@ -158,7 +158,7 @@ void MMF::VideoPlayer::doSeek(qint64 ms) } else { TRACE("SetPositionL error %d", err); - setError(NormalError); + setError(tr("Seek failed"), err); } } @@ -200,7 +200,7 @@ qint64 MMF::VideoPlayer::currentTime() const // If we don't cast away constness here, we simply have to ignore // the error. - const_cast(this)->setError(NormalError); + const_cast(this)->setError(tr("Getting position failed"), err); } return result; @@ -226,7 +226,7 @@ void MMF::VideoPlayer::MvpuoOpenComplete(TInt aError) if (KErrNone == aError) m_player->Prepare(); else - setError(NormalError); + setError(tr("Opening clip failed"), aError); TRACE_EXIT_0(); } @@ -252,7 +252,7 @@ void MMF::VideoPlayer::MvpuoPrepareComplete(TInt aError) emit totalTimeChanged(totalTime()); changeState(StoppedState); } else { - setError(NormalError); + setError(tr("Buffering clip failed"), err); } TRACE_EXIT_0(); @@ -412,7 +412,7 @@ void MMF::VideoPlayer::startDirectScreenAccess() if(KErrNone == err) m_dsaActive = true; else - setError(NormalError); + setError(tr("Video display error"), err); } } @@ -424,7 +424,7 @@ bool MMF::VideoPlayer::stopDirectScreenAccess() if(KErrNone == err) m_dsaActive = false; else - setError(NormalError); + setError(tr("Video display error"), err); } return dsaWasActive; } @@ -600,7 +600,7 @@ void MMF::VideoPlayer::applyVideoWindowChange() TRAPD(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight, antialias)); if(KErrNone != err) { TRACE("SetScaleFactorL (1) err %d", err); - setError(NormalError); + setError(tr("Video display error"), err); } if(KErrNone == err) { @@ -615,13 +615,13 @@ void MMF::VideoPlayer::applyVideoWindowChange() if (KErrNone != err) { TRACE("SetDisplayWindowL err %d", err); - setError(NormalError); + setError(tr("Video display error"), err); } else { m_dsaActive = true; TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight, antialias)); if(KErrNone != err) { TRACE("SetScaleFactorL (2) err %d", err); - setError(NormalError); + setError(tr("Video display error"), err); } } } diff --git a/src/3rdparty/phonon/mmf/utils.cpp b/src/3rdparty/phonon/mmf/utils.cpp index d728fcf..75fec9f 100644 --- a/src/3rdparty/phonon/mmf/utils.cpp +++ b/src/3rdparty/phonon/mmf/utils.cpp @@ -18,6 +18,7 @@ along with this library. If not, see . #include "utils.h" #include +#include QT_BEGIN_NAMESPACE @@ -69,6 +70,103 @@ MMF::MediaType MMF::Utils::mimeTypeToMediaType(const TDesC& mimeType) return result; } +QString MMF::Utils::symbianErrorToString(int errorCode) +{ + /** + * Here we translate only the error codes which are likely to be + * meaningful to the user. For example, when an error occurs + * during opening of a media file, displaying "not found" or + * "permission denied" is informative. On the other hand, + * differentiating between KErrGeneral and KErrArgument at the UI + * level does not make sense. + */ + switch (errorCode) + { + // System-wide errors + case KErrNone: + return tr("no error"); + case KErrNotFound: + return tr("not found"); + case KErrNoMemory: + return tr("out of memory"); + case KErrNotSupported: + return tr("not supported"); + case KErrOverflow: + return tr("overflow"); + case KErrUnderflow: + return tr("underflow"); + case KErrAlreadyExists: + return tr("already exists"); + case KErrPathNotFound: + return tr("path not found"); + case KErrInUse: + return tr("in use"); + case KErrNotReady: + return tr("not ready"); + case KErrAccessDenied: + return tr("access denied"); + case KErrCouldNotConnect: + return tr("could not connect"); + case KErrDisconnected: + return tr("disconnected"); + case KErrPermissionDenied: + return tr("permission denied"); + + // Multimedia framework errors + case KErrMMNotEnoughBandwidth: + return tr("insufficient bandwidth"); + case KErrMMSocketServiceNotFound: + case KErrMMServerSocket: + return tr("network unavailable"); + case KErrMMNetworkRead: + case KErrMMNetworkWrite: + case KErrMMUDPReceive: + return tr("network communication error"); + case KErrMMServerNotSupported: + return tr("streaming not supported"); + case KErrMMServerAlert: + return tr("server alert"); + case KErrMMInvalidProtocol: + return tr("invalid protocol"); + case KErrMMInvalidURL: + return tr("invalid URL"); + case KErrMMMulticast: + return tr("multicast error"); + case KErrMMProxyServer: + case KErrMMProxyServerConnect: + return tr("proxy server error"); + case KErrMMProxyServerNotSupported: + return tr("proxy server not supported"); + case KErrMMAudioDevice: + return tr("audio output error"); + case KErrMMVideoDevice: + return tr("video output error"); + case KErrMMDecoder: + return tr("decoder error"); + case KErrMMPartialPlayback: + return tr("audio or video components could not be played"); + case KErrMMDRMNotAuthorized: + return tr("DRM error"); + + /* + // We don't use QoS settings + case KErrMMQosLowBandwidth: + case KErrMMQosUnsupportedTrafficClass: + case KErrMMQosPoorTrafficClass: + case KErrMMQosUnsupportedParameters: + case KErrMMQosPoorParameters: + case KErrMMQosNotSupported: + */ + + // Catch-all for errors other than those above + default: + { + QString errorString; + errorString.setNum(errorCode); + return tr("unknown error") + " (" + errorString + ")"; + } + } +} #ifndef QT_NO_DEBUG diff --git a/src/3rdparty/phonon/mmf/utils.h b/src/3rdparty/phonon/mmf/utils.h index 7e363e8..60c03a5 100644 --- a/src/3rdparty/phonon/mmf/utils.h +++ b/src/3rdparty/phonon/mmf/utils.h @@ -21,7 +21,7 @@ along with this library. If not, see . #include #include // for RDebug - +#include // for Q_DECLARE_TR_FUNCTIONS #include #include "defs.h" @@ -41,32 +41,40 @@ enum PanicCode { InvalidBackendInterfaceClass = 3 }; -namespace Utils +class Utils { + Q_DECLARE_TR_FUNCTIONS(Utils) + +public: /** * Raise a fatal exception */ -void panic(PanicCode code); +static void panic(PanicCode code); /** * Determines whether the provided MIME type is an audio or video * type. If it is neither, the function returns MediaTypeUnknown. */ -MediaType mimeTypeToMediaType(const TDesC& mimeType); +static MediaType mimeTypeToMediaType(const TDesC& mimeType); + +/** + * Translates a Symbian error code into a user-readable string. + */ +static QString symbianErrorToString(int errorCode); #ifndef QT_NO_DEBUG /** * Retrieve color of specified pixel from the screen. */ -QColor getScreenPixel(const QPoint& pos); +static QColor getScreenPixel(const QPoint& pos); /** * Samples a small number of pixels from the screen, and dumps their * colors to the debug log. */ -void dumpScreenPixelSample(); +static void dumpScreenPixelSample(); #endif -} +}; /** * Available trace categories; -- cgit v0.12 From dfa9343cc1e634eebdb0f3a2cf931ada9829ae6b Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 1 Dec 2009 14:35:43 +0000 Subject: Fixed bug which caused Phonon backend error messages to be suppressed When the mediaplayer receives a state change into the ErrorState, it calls pause() on the media object. Previously, this caused the backend to transition into PausedState. When the mediaplayer subsequently called errorString() to retrieve the error message, an empty string was returned because the backend was no longer in the ErrorState. Task-number: QTBUG-4994 Reviewed-by: trustme --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 11 ++++++----- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index bc38513..adade9c 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -104,21 +104,22 @@ void MMF::AbstractMediaPlayer::pause() TRACE_ENTRY("state %d", privateState()); m_playPending = false; + stopTickTimer(); switch (privateState()) { case GroundState: case LoadingState: case PausedState: + case StoppedState: // Do nothing break; - case StoppedState: case PlayingState: - case ErrorState: case BufferingState: - doPause(); - stopTickTimer(); changeState(PausedState); + // Fall through + case ErrorState: + doPause(); break; // Protection against adding new states and forgetting to update this switch @@ -135,6 +136,7 @@ void MMF::AbstractMediaPlayer::stop() TRACE_ENTRY("state %d", privateState()); m_playPending = false; + stopTickTimer(); switch (privateState()) { case GroundState: @@ -148,7 +150,6 @@ void MMF::AbstractMediaPlayer::stop() case BufferingState: case PausedState: doStop(); - stopTickTimer(); changeState(StoppedState); break; diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 4619f54..eb6f690 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -127,7 +127,7 @@ void MMF::VideoPlayer::doPause() TRACE_CONTEXT(VideoPlayer::doPause, EVideoApi); TRAPD(err, m_player->PauseL()); - if (KErrNone != err) { + if (KErrNone != err && state() != ErrorState) { TRACE("PauseL error %d", err); setError(tr("Pause failed"), err); } -- cgit v0.12 From db782f7ab22241d8161190b95c41af4d56c05b82 Mon Sep 17 00:00:00 2001 From: Frans Englich Date: Mon, 7 Dec 2009 15:09:33 +0100 Subject: Symbian: More i18n strings work. * Consistently capitalize error sentences * Simplify & fix code/documentation. Task-number: QTBUG-4994 Reviewed-by: TrustMe --- src/3rdparty/phonon/mmf/abstractplayer.h | 4 +- src/3rdparty/phonon/mmf/utils.cpp | 64 ++++++++++++++++---------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h index 9af1362..cd15baf 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.h +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -96,7 +96,9 @@ public: * * Appends a human-readable version of symbianErrorCode to the error message, * e.g. - * setError(NormalError, "Opening file failed", KErrPermissionDenied) + * @code + * setError("Opening file failed", KErrPermissionDenied) + * @endcode * results in the following error message: * "Opening file failed: permission denied" */ diff --git a/src/3rdparty/phonon/mmf/utils.cpp b/src/3rdparty/phonon/mmf/utils.cpp index 75fec9f..2d17bd2 100644 --- a/src/3rdparty/phonon/mmf/utils.cpp +++ b/src/3rdparty/phonon/mmf/utils.cpp @@ -84,67 +84,67 @@ QString MMF::Utils::symbianErrorToString(int errorCode) { // System-wide errors case KErrNone: - return tr("no error"); + return tr("No error"); case KErrNotFound: - return tr("not found"); + return tr("Not found"); case KErrNoMemory: - return tr("out of memory"); + return tr("Out of memory"); case KErrNotSupported: - return tr("not supported"); + return tr("Not supported"); case KErrOverflow: - return tr("overflow"); + return tr("Overflow"); case KErrUnderflow: - return tr("underflow"); + return tr("Underflow"); case KErrAlreadyExists: - return tr("already exists"); + return tr("Already exists"); case KErrPathNotFound: - return tr("path not found"); + return tr("Path not found"); case KErrInUse: - return tr("in use"); + return tr("In use"); case KErrNotReady: - return tr("not ready"); + return tr("Not ready"); case KErrAccessDenied: - return tr("access denied"); + return tr("Access denied"); case KErrCouldNotConnect: - return tr("could not connect"); + return tr("Could not connect"); case KErrDisconnected: - return tr("disconnected"); + return tr("Disconnected"); case KErrPermissionDenied: - return tr("permission denied"); + return tr("Permission denied"); // Multimedia framework errors case KErrMMNotEnoughBandwidth: - return tr("insufficient bandwidth"); + return tr("Insufficient bandwidth"); case KErrMMSocketServiceNotFound: case KErrMMServerSocket: - return tr("network unavailable"); + return tr("Network unavailable"); case KErrMMNetworkRead: case KErrMMNetworkWrite: case KErrMMUDPReceive: - return tr("network communication error"); + return tr("Network communication error"); case KErrMMServerNotSupported: - return tr("streaming not supported"); + return tr("Streaming not supported"); case KErrMMServerAlert: - return tr("server alert"); + return tr("Server alert"); case KErrMMInvalidProtocol: - return tr("invalid protocol"); + return tr("Invalid protocol"); case KErrMMInvalidURL: - return tr("invalid URL"); + return tr("Invalid URL"); case KErrMMMulticast: - return tr("multicast error"); + return tr("Multicast error"); case KErrMMProxyServer: case KErrMMProxyServerConnect: - return tr("proxy server error"); + return tr("Proxy server error"); case KErrMMProxyServerNotSupported: - return tr("proxy server not supported"); + return tr("Proxy server not supported"); case KErrMMAudioDevice: - return tr("audio output error"); + return tr("Audio output error"); case KErrMMVideoDevice: - return tr("video output error"); + return tr("Video output error"); case KErrMMDecoder: - return tr("decoder error"); + return tr("Decoder error"); case KErrMMPartialPlayback: - return tr("audio or video components could not be played"); + return tr("Audio or video components could not be played"); case KErrMMDRMNotAuthorized: return tr("DRM error"); @@ -160,11 +160,9 @@ QString MMF::Utils::symbianErrorToString(int errorCode) // Catch-all for errors other than those above default: - { - QString errorString; - errorString.setNum(errorCode); - return tr("unknown error") + " (" + errorString + ")"; - } + { + return tr("Unknown error (%1)").arg(errorCode); + } } } -- cgit v0.12 From 99b10b64fd5f68c63e0c406558b507e429eea248 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 2 Dec 2009 16:59:46 +0000 Subject: Removed stale TODO comments from Phonon MMF backend Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/mediaobject.h | 1 - src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 2 -- src/3rdparty/phonon/mmf/objectdump.cpp | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index ee94ea2..d6f4c7b 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -98,7 +98,6 @@ Q_SIGNALS: void aboutToFinish(); // TODO: emit prefinishMarkReached from MediaObject void prefinishMarkReached(qint32); - // TODO: emit metaDataChanged from MediaObject void metaDataChanged(const QMultiMap& metaData); void currentSourceChanged(const MediaSource& source); void stateChanged(Phonon::State oldState, diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index eb6f690..66bbe38 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -277,7 +277,6 @@ void MMF::VideoPlayer::MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError) TRACE_CONTEXT(VideoPlayer::MvpuoFrameReady, EVideoApi); TRACE_ENTRY("state %d error %d", state(), aError); - // TODO Q_UNUSED(aFrame); Q_UNUSED(aError); // suppress warnings in release builds @@ -300,7 +299,6 @@ void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent) TRACE_CONTEXT(VideoPlayer::MvpuoEvent, EVideoApi); TRACE_ENTRY("state %d", state()); - // TODO Q_UNUSED(aEvent); TRACE_EXIT_0(); diff --git a/src/3rdparty/phonon/mmf/objectdump.cpp b/src/3rdparty/phonon/mmf/objectdump.cpp index 3d10be4..778cde9 100644 --- a/src/3rdparty/phonon/mmf/objectdump.cpp +++ b/src/3rdparty/phonon/mmf/objectdump.cpp @@ -390,7 +390,7 @@ void QVisitorPrivate::dumpNode // No annotations - just dump the object pointer const bool isNodeLine = true; QByteArray buffer = branchBuffer(branches, isNodeLine, isLastChild); - qDebug() << 0; // TODO + qDebug() << 0; } else { // Dump annotations -- cgit v0.12 From bbab8eabb91b95dcd946c94b5f0ac59413e7a929 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Thu, 3 Dec 2009 15:44:55 +0000 Subject: Phonon MMF: leaves during object construction throw exceptions Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/audioplayer.cpp | 6 +++--- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 10 ++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 72d6684..2ce10db 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -50,9 +50,9 @@ void MMF::AudioPlayer::construct() TRACE_CONTEXT(AudioPlayer::AudioPlayer, EAudioApi); TRACE_ENTRY_0(); - TRAPD(err, m_player.reset(CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone))); - if (KErrNone != err) - setError("Creation of audio player failed", err); + CPlayerType *player = 0; + QT_TRAP_THROWING(player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone)); + m_player.reset(player); TRACE_EXIT_0(); } diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 66bbe38..0a1c78f 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -78,23 +78,21 @@ void MMF::VideoPlayer::construct() const TInt priority = 0; const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone; - TRAPD(err, - m_player.reset(CVideoPlayerUtility::NewL + CVideoPlayerUtility *player = 0; + QT_TRAP_THROWING(player = CVideoPlayerUtility::NewL ( *this, priority, preference, m_wsSession, m_screenDevice, *m_window, m_videoRect, m_videoRect - )) + ) ); + m_player.reset(player); // CVideoPlayerUtility::NewL starts DSA m_dsaActive = true; - if (KErrNone != err) - setError("Creation of video player failed", err); - TRACE_EXIT_0(); } -- cgit v0.12 From 3117e3a6a9c1bf95fc30ebee4d8d11b646cb7125 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Thu, 5 Nov 2009 18:13:47 +0000 Subject: Added support for streaming playback to Phonon MMF backend Because the MIME type of the stream cannot always be deduced from the URL, we assume that it is a video stream. This is based on the assumption that the video controllers will be capable of parsing the container formats for audio-only, as well as video clips. Note that this assumption may not hold on all devices. Note that most implementations of the MMF client APIs do not support HTTP streaming (a.k.a. progressive download). The backend has therefore only been tested with RTSP streams - see the JIRA entry for further details. Task-number: QTBUG-4660 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 8 ++++---- src/3rdparty/phonon/mmf/abstractmediaplayer.h | 1 + src/3rdparty/phonon/mmf/audioplayer.cpp | 11 +++++++++++ src/3rdparty/phonon/mmf/audioplayer.h | 1 + src/3rdparty/phonon/mmf/mediaobject.cpp | 5 ++++- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 6 ++++++ src/3rdparty/phonon/mmf/mmf_videoplayer.h | 1 + src/3rdparty/phonon/mmf/utils.h | 3 ++- 8 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index adade9c..260d8e6 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -243,12 +243,12 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f if (url.scheme() == QLatin1String("file")) { symbianErr = openFile(file); if (KErrNone != symbianErr) + errorMessage = tr("Error opening file"); + } else { + symbianErr = openUrl(url.toString()); + if (KErrNone != symbianErr) errorMessage = tr("Error opening URL"); } - else { - TRACE_0("Error opening URL: protocol not supported"); - errorMessage = tr("Error opening URL: protocol not supported"); - } break; } diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index cb6e437..0432b07 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -68,6 +68,7 @@ protected: virtual void doSeek(qint64 pos) = 0; virtual int setDeviceVolume(int mmfVolume) = 0; virtual int openFile(RFile& file) = 0; + virtual int openUrl(const QString& url) = 0; virtual void close() = 0; virtual void changeState(PrivateState newState); diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 2ce10db..2d618b8 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -124,6 +124,17 @@ int MMF::AudioPlayer::openFile(RFile& file) return err; } +int MMF::AudioPlayer::openUrl(const QString& /*url*/) +{ + // Streaming playback is generally not supported by the implementation + // of the audio player API, so we use CVideoPlayerUtility for both + // audio and video streaming. + Utils::panic(AudioUtilityUrlNotSupported); + + // Silence warning + return 0; +} + void MMF::AudioPlayer::close() { m_player->Close(); diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index bc60076..4674afc 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -63,6 +63,7 @@ public: virtual void doSeek(qint64 milliseconds); virtual int setDeviceVolume(int mmfVolume); virtual int openFile(RFile& file); + virtual int openUrl(const QString& url); virtual void close(); // MediaObjectInterface diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index 6158ca1..ca3e837 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -253,7 +253,10 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) mediaType = fileMediaType(url.toLocalFile()); } else { - errorMessage = QLatin1String("Network streaming not supported yet"); + // Streaming playback is generally not supported by the implementation + // of the audio player API, so we use CVideoPlayerUtility for both + // audio and video streaming. + mediaType = MediaTypeVideo; } } break; diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 0a1c78f..62bbdef 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -172,6 +172,12 @@ int MMF::VideoPlayer::openFile(RFile& file) return err; } +int MMF::VideoPlayer::openUrl(const QString& url) +{ + TRAPD(err, m_player->OpenUrlL(qt_QString2TPtrC(url))); + return err; +} + void MMF::VideoPlayer::close() { m_player->Close(); diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h index abb1da8..7c42991 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.h +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h @@ -54,6 +54,7 @@ public: virtual void doSeek(qint64 milliseconds); virtual int setDeviceVolume(int mmfVolume); virtual int openFile(RFile& file); + virtual int openUrl(const QString& url); virtual void close(); // MediaObjectInterface diff --git a/src/3rdparty/phonon/mmf/utils.h b/src/3rdparty/phonon/mmf/utils.h index 60c03a5..56ccafc 100644 --- a/src/3rdparty/phonon/mmf/utils.h +++ b/src/3rdparty/phonon/mmf/utils.h @@ -38,7 +38,8 @@ namespace MMF enum PanicCode { InvalidStatePanic = 1, InvalidMediaTypePanic = 2, - InvalidBackendInterfaceClass = 3 + InvalidBackendInterfaceClass = 3, + AudioUtilityUrlNotSupported = 4 }; class Utils -- cgit v0.12 From bed33ac62d87073120d56ff75a3d2356c99c64ea Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 1 Dec 2009 17:55:30 +0000 Subject: Implemented buffer status notifications in Phonon MMF backend When clips are buffering (either at the start of playback, or during playback, when buffer levels drop due to e.g. CPU, file system or network load), the backend receives notification from the MMF. While buffering is ongoing, the backend periodically queries the filling status and emits a signal. Task-number: QTBUG-4660 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 80 +++++++++++++++++++------ src/3rdparty/phonon/mmf/abstractmediaplayer.h | 23 ++++--- src/3rdparty/phonon/mmf/abstractplayer.h | 1 + src/3rdparty/phonon/mmf/audioplayer.cpp | 25 +++++++- src/3rdparty/phonon/mmf/audioplayer.h | 34 +++++------ src/3rdparty/phonon/mmf/mediaobject.cpp | 1 + src/3rdparty/phonon/mmf/mediaobject.h | 1 - src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 27 ++++++++- src/3rdparty/phonon/mmf/mmf_videoplayer.h | 32 ++++++---- 9 files changed, 162 insertions(+), 62 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 260d8e6..6e7f458 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -36,6 +36,7 @@ using namespace Phonon::MMF; //----------------------------------------------------------------------------- const int NullMaxVolume = -1; +const int BufferStatusTimerInterval = 100; // ms //----------------------------------------------------------------------------- @@ -44,19 +45,23 @@ const int NullMaxVolume = -1; MMF::AbstractMediaPlayer::AbstractMediaPlayer() : m_playPending(false) - , m_tickTimer(new QTimer(this)) + , m_positionTimer(new QTimer(this)) + , m_bufferStatusTimer(new QTimer(this)) , m_mmfMaxVolume(NullMaxVolume) { - connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick())); + connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); + connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); } MMF::AbstractMediaPlayer::AbstractMediaPlayer(const AbstractPlayer& player) : AbstractPlayer(player) , m_playPending(false) - , m_tickTimer(new QTimer(this)) + , m_positionTimer(new QTimer(this)) + , m_bufferStatusTimer(new QTimer(this)) , m_mmfMaxVolume(NullMaxVolume) { - connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick())); + connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); + connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); } //----------------------------------------------------------------------------- @@ -80,7 +85,7 @@ void MMF::AbstractMediaPlayer::play() case StoppedState: case PausedState: doPlay(); - startTickTimer(); + startPositionTimer(); changeState(PlayingState); break; @@ -104,7 +109,7 @@ void MMF::AbstractMediaPlayer::pause() TRACE_ENTRY("state %d", privateState()); m_playPending = false; - stopTickTimer(); + stopTimers(); switch (privateState()) { case GroundState: @@ -136,7 +141,7 @@ void MMF::AbstractMediaPlayer::stop() TRACE_ENTRY("state %d", privateState()); m_playPending = false; - stopTickTimer(); + stopTimers(); switch (privateState()) { case GroundState: @@ -174,14 +179,13 @@ void MMF::AbstractMediaPlayer::seek(qint64 ms) case PlayingState: case LoadingState: { - const bool tickTimerWasRunning = m_tickTimer->isActive(); - stopTickTimer(); + const bool positionTimerWasRunning = m_positionTimer->isActive(); + stopPositionTimer(); doSeek(ms); - if (tickTimerWasRunning) { - startTickTimer(); - } + if (positionTimerWasRunning) + startPositionTimer(); break; } case BufferingState: @@ -204,7 +208,7 @@ void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval) TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi); TRACE_ENTRY("state %d m_interval %d interval %d", privateState(), tickInterval(), interval); - m_tickTimer->setInterval(interval); + m_positionTimer->setInterval(interval); TRACE_EXIT_0(); } @@ -307,6 +311,35 @@ void MMF::AbstractMediaPlayer::volumeChanged(qreal volume) TRACE_EXIT_0(); } +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- + +void MMF::AbstractMediaPlayer::startPositionTimer() +{ + m_positionTimer->start(tickInterval()); +} + +void MMF::AbstractMediaPlayer::stopPositionTimer() +{ + m_positionTimer->stop(); +} + +void MMF::AbstractMediaPlayer::startBufferStatusTimer() +{ + m_bufferStatusTimer->start(BufferStatusTimerInterval); +} + +void MMF::AbstractMediaPlayer::stopBufferStatusTimer() +{ + m_bufferStatusTimer->stop(); +} + +void MMF::AbstractMediaPlayer::stopTimers() +{ + stopPositionTimer(); + stopBufferStatusTimer(); +} void MMF::AbstractMediaPlayer::doVolumeChanged() { @@ -342,14 +375,19 @@ void MMF::AbstractMediaPlayer::doVolumeChanged() // Protected functions //----------------------------------------------------------------------------- -void MMF::AbstractMediaPlayer::startTickTimer() +void MMF::AbstractMediaPlayer::bufferingStarted() { - m_tickTimer->start(tickInterval()); + m_stateBeforeBuffering = privateState(); + changeState(BufferingState); + bufferStatusTick(); + startBufferStatusTimer(); } -void MMF::AbstractMediaPlayer::stopTickTimer() +void MMF::AbstractMediaPlayer::bufferingComplete() { - m_tickTimer->stop(); + stopBufferStatusTimer(); + emit MMF::AbstractPlayer::bufferStatus(100); + changeState(m_stateBeforeBuffering); } void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume) @@ -367,12 +405,16 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds // Slots //----------------------------------------------------------------------------- -void MMF::AbstractMediaPlayer::tick() +void MMF::AbstractMediaPlayer::positionTick() { - // For the MWC compiler, we need to qualify the base class. emit MMF::AbstractPlayer::tick(currentTime()); } +void MMF::AbstractMediaPlayer::bufferStatusTick() +{ + emit MMF::AbstractPlayer::bufferStatus(bufferStatus()); +} + void MMF::AbstractMediaPlayer::changeState(PrivateState newState) { TRACE_CONTEXT(AbstractMediaPlayer::changeState, EAudioInternal); diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index 0432b07..7c11ec7 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -69,6 +69,7 @@ protected: virtual int setDeviceVolume(int mmfVolume) = 0; virtual int openFile(RFile& file) = 0; virtual int openUrl(const QString& url) = 0; + virtual int bufferStatus() const = 0; virtual void close() = 0; virtual void changeState(PrivateState newState); @@ -77,21 +78,22 @@ protected: virtual QPair metaDataEntry(int index) const = 0; protected: - bool tickTimerRunning() const; - void startTickTimer(); - void stopTickTimer(); + void bufferingStarted(); + void bufferingComplete(); void maxVolumeChanged(int maxVolume); - static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &); private: + void startPositionTimer(); + void stopPositionTimer(); + void startBufferStatusTimer(); + void stopBufferStatusTimer(); + void stopTimers(); void doVolumeChanged(); private Q_SLOTS: - /** - * Receives signal from m_tickTimer - */ - void tick(); + void positionTick(); + void bufferStatusTick(); private: /** @@ -101,7 +103,10 @@ private: */ bool m_playPending; - QScopedPointer m_tickTimer; + QScopedPointer m_positionTimer; + + QScopedPointer m_bufferStatusTimer; + PrivateState m_stateBeforeBuffering; int m_mmfMaxVolume; diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h index cd15baf..5aaae3c 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.h +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -110,6 +110,7 @@ Q_SIGNALS: void totalTimeChanged(qint64 length); void finished(); void tick(qint64 time); + void bufferStatus(int percentFilled); void stateChanged(Phonon::State oldState, Phonon::State newState); void metaDataChanged(const QMultiMap& metaData); diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 2d618b8..0967a27 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -53,6 +53,7 @@ void MMF::AudioPlayer::construct() CPlayerType *player = 0; QT_TRAP_THROWING(player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone)); m_player.reset(player); + m_player->RegisterForAudioLoadingNotification(*this); TRACE_EXIT_0(); } @@ -135,6 +136,13 @@ int MMF::AudioPlayer::openUrl(const QString& /*url*/) return 0; } +int MMF::AudioPlayer::bufferStatus() const +{ + int result = 0; + TRAP_IGNORE(m_player->GetAudioLoadingProgressL(result)); + return result; +} + void MMF::AudioPlayer::close() { m_player->Close(); @@ -211,8 +219,6 @@ void MMF::AudioPlayer::MapcPlayComplete(TInt aError) TRACE_CONTEXT(AudioPlayer::MapcPlayComplete, EAudioInternal); TRACE_ENTRY("state %d error %d", state(), aError); - stopTickTimer(); - if (KErrNone == aError) { changeState(StoppedState); // TODO: move on to m_nextSource @@ -260,6 +266,21 @@ void MMF::AudioPlayer::MaloLoadingComplete() //----------------------------------------------------------------------------- +// MAudioLoadingObserver callbacks +//----------------------------------------------------------------------------- + +void MMF::AudioPlayer::MaloLoadingStarted() +{ + bufferingStarted(); +} + +void MMF::AudioPlayer::MaloLoadingComplete() +{ + bufferingComplete(); +} + + +//----------------------------------------------------------------------------- // Private functions //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index 4674afc..5c7cfc1 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -45,9 +45,7 @@ namespace MMF */ class AudioPlayer : public AbstractMediaPlayer , public MPlayerObserverType // typedef -#ifdef QT_PHONON_MMF_AUDIO_DRM , public MAudioLoadingObserver -#endif { Q_OBJECT @@ -64,6 +62,7 @@ public: virtual int setDeviceVolume(int mmfVolume); virtual int openFile(RFile& file); virtual int openUrl(const QString& url); + virtual int bufferStatus() const; virtual void close(); // MediaObjectInterface @@ -71,15 +70,24 @@ public: virtual qint64 currentTime() const; virtual qint64 totalTime() const; + // AbstractMediaPlayer + virtual int numberOfMetaDataEntries() const; + virtual QPair metaDataEntry(int index) const; + + /** + * This class owns the pointer. + */ + CPlayerType *player() const; + +private: + void construct(); + +private: #ifdef QT_PHONON_MMF_AUDIO_DRM // MDrmAudioPlayerCallback virtual void MdapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds &aDuration); virtual void MdapcPlayComplete(TInt aError); - - // MAudioLoadingObserver - virtual void MaloLoadingStarted(); - virtual void MaloLoadingComplete(); #else // MMdaAudioPlayerCallback virtual void MapcInitComplete(TInt aError, @@ -87,17 +95,9 @@ public: virtual void MapcPlayComplete(TInt aError); #endif - /** - * This class owns the pointer. - */ - CPlayerType *player() const; - -private: - void construct(); - - // AbstractMediaPlayer - virtual int numberOfMetaDataEntries() const; - virtual QPair metaDataEntry(int index) const; + // MAudioLoadingObserver + virtual void MaloLoadingStarted(); + virtual void MaloLoadingComplete(); private: /** diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index ca3e837..bf1f268 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -321,6 +321,7 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) connect(m_player.data(), SIGNAL(stateChanged(Phonon::State,Phonon::State)), SIGNAL(stateChanged(Phonon::State,Phonon::State))); connect(m_player.data(), SIGNAL(finished()), SIGNAL(finished())); connect(m_player.data(), SIGNAL(tick(qint64)), SIGNAL(tick(qint64))); + connect(m_player.data(), SIGNAL(bufferStatus(int)), SIGNAL(bufferStatus(int))); connect(m_player.data(), SIGNAL(metaDataChanged(QMultiMap)), SIGNAL(metaDataChanged(QMultiMap))); // We need to call setError() after doing the connects, otherwise the diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index d6f4c7b..07baad0 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -92,7 +92,6 @@ Q_SIGNALS: void totalTimeChanged(qint64 length); void hasVideoChanged(bool hasVideo); void seekableChanged(bool seekable); - // TODO: emit bufferStatus from MediaObject void bufferStatus(int); // TODO: emit aboutToFinish from MediaObject void aboutToFinish(); diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 62bbdef..4a70d58 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -93,6 +93,8 @@ void MMF::VideoPlayer::construct() // CVideoPlayerUtility::NewL starts DSA m_dsaActive = true; + m_player->RegisterForVideoLoadingNotification(*this); + TRACE_EXIT_0(); } @@ -178,6 +180,13 @@ int MMF::VideoPlayer::openUrl(const QString& url) return err; } +int MMF::VideoPlayer::bufferStatus() const +{ + int result = 0; + TRAP_IGNORE(m_player->GetVideoLoadingProgressL(result)); + return result; +} + void MMF::VideoPlayer::close() { m_player->Close(); @@ -292,7 +301,8 @@ void MMF::VideoPlayer::MvpuoPlayComplete(TInt aError) TRACE_CONTEXT(VideoPlayer::MvpuoPlayComplete, EVideoApi) TRACE_ENTRY("state %d error %d", state(), aError); - Q_UNUSED(aError); // suppress warnings in release builds + // TODO: handle aError + Q_UNUSED(aError); changeState(StoppedState); TRACE_EXIT_0(); @@ -310,6 +320,21 @@ void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent) //----------------------------------------------------------------------------- +// MVideoLoadingObserver callbacks +//----------------------------------------------------------------------------- + +void MMF::VideoPlayer::MvloLoadingStarted() +{ + bufferingStarted(); +} + +void MMF::VideoPlayer::MvloLoadingComplete() +{ + bufferingComplete(); +} + + +//----------------------------------------------------------------------------- // Video window updates //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h index 7c42991..3ece19c 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.h +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h @@ -39,6 +39,7 @@ namespace MMF */ class VideoPlayer : public AbstractMediaPlayer , public MVideoPlayerUtilityObserver + , public MVideoLoadingObserver { Q_OBJECT @@ -55,6 +56,7 @@ public: virtual int setDeviceVolume(int mmfVolume); virtual int openFile(RFile& file); virtual int openUrl(const QString& url); + virtual int bufferStatus() const; virtual void close(); // MediaObjectInterface @@ -62,12 +64,12 @@ public: virtual qint64 currentTime() const; virtual qint64 totalTime() const; - // MVideoPlayerUtilityObserver - virtual void MvpuoOpenComplete(TInt aError); - virtual void MvpuoPrepareComplete(TInt aError); - virtual void MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError); - virtual void MvpuoPlayComplete(TInt aError); - virtual void MvpuoEvent(const TMMFEvent &aEvent); + // AbstractPlayer + virtual void videoOutputChanged(); + + // AbstractMediaPlayer + virtual int numberOfMetaDataEntries() const; + virtual QPair metaDataEntry(int index) const; public Q_SLOTS: void videoWindowChanged(); @@ -81,12 +83,8 @@ private: void doPrepareCompleteL(TInt aError); - // AbstractPlayer - virtual void videoOutputChanged(); - void getVideoWindow(); void initVideoOutput(); - void updateVideoRect(); void applyPendingChanges(); @@ -95,9 +93,17 @@ private: void startDirectScreenAccess(); bool stopDirectScreenAccess(); - // AbstractMediaPlayer - virtual int numberOfMetaDataEntries() const; - virtual QPair metaDataEntry(int index) const; +private: + // MVideoPlayerUtilityObserver + virtual void MvpuoOpenComplete(TInt aError); + virtual void MvpuoPrepareComplete(TInt aError); + virtual void MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError); + virtual void MvpuoPlayComplete(TInt aError); + virtual void MvpuoEvent(const TMMFEvent &aEvent); + + // MVideoLoadingObserver + virtual void MvloLoadingStarted(); + virtual void MvloLoadingComplete(); private: QScopedPointer m_player; -- cgit v0.12 From 66b765734585971dd9d248059701fdecebbccd78 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 1 Dec 2009 18:51:45 +0000 Subject: Changed call sequence of seeking in Phonon MMF backend, for streaming Modified the sequence of calls made to the MMF APIs when seeking during ongoing playback. This fixes a bug found during early testing of streaming playback, whereby playback would not resume following the seeking operation. This was due to an interaction between the pause / seek / play operations, and the buffering callbacks received from the MMF, which caused the backend to enter an incorrect state. Task-number: QTBUG-4660 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 14 ++++++++++---- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 16 +--------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 6e7f458..83c534a 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -179,13 +179,20 @@ void MMF::AbstractMediaPlayer::seek(qint64 ms) case PlayingState: case LoadingState: { - const bool positionTimerWasRunning = m_positionTimer->isActive(); - stopPositionTimer(); + bool wasPlaying = false; + if (state() == PlayingState) { + stopPositionTimer(); + doPause(); + wasPlaying = true; + } doSeek(ms); - if (positionTimerWasRunning) + if(wasPlaying && state() != ErrorState) { + doPlay(); startPositionTimer(); + } + break; } case BufferingState: @@ -370,7 +377,6 @@ void MMF::AbstractMediaPlayer::doVolumeChanged() } } - //----------------------------------------------------------------------------- // Protected functions //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 4a70d58..dab7505 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -142,24 +142,10 @@ void MMF::VideoPlayer::doSeek(qint64 ms) { TRACE_CONTEXT(VideoPlayer::doSeek, EVideoApi); - bool wasPlaying = false; - if (state() == PlayingState) { - // The call to SetPositionL does not have any effect if playback is - // ongoing, so we pause before seeking. - doPause(); - wasPlaying = true; - } - TRAPD(err, m_player->SetPositionL(TTimeIntervalMicroSeconds(ms * 1000))); - if (KErrNone == err) { - if (wasPlaying) - doPlay(); - } - else { - TRACE("SetPositionL error %d", err); + if(KErrNone != err) setError(tr("Seek failed"), err); - } } int MMF::VideoPlayer::setDeviceVolume(int mmfVolume) -- cgit v0.12 From 946dede337f0a43ccb394c10aa2045bc9ef59301 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 2 Dec 2009 16:11:29 +0000 Subject: Mediaplayer: enqueue all entries from .ram file before starting playback This ensures that Phonon::MediaObject::setNextSource is called before the first clip finishes playback, and therefore that the next clip is played once the first finishes. Reviewed-by: Frans Englich --- demos/qmediaplayer/mediaplayer.cpp | 16 +++++++++++----- demos/qmediaplayer/mediaplayer.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/demos/qmediaplayer/mediaplayer.cpp b/demos/qmediaplayer/mediaplayer.cpp index 8f6848f..8471ebd 100644 --- a/demos/qmediaplayer/mediaplayer.cpp +++ b/demos/qmediaplayer/mediaplayer.cpp @@ -673,6 +673,13 @@ void MediaPlayer::setFile(const QString &fileName) m_MediaObject.play(); } +void MediaPlayer::setLocation(const QString& location) +{ + setWindowTitle(location.right(location.length() - location.lastIndexOf('/') - 1)); + m_MediaObject.setCurrentSource(Phonon::MediaSource(QUrl::fromEncoded(location.toUtf8()))); + m_MediaObject.play(); +} + bool MediaPlayer::playPauseForDialog() { // If we're running on a small screen, we want to pause the video when @@ -850,9 +857,7 @@ void MediaPlayer::openUrl() bool ok = false; sourceURL = QInputDialog::getText(this, tr("Open Location"), tr("Please enter a valid address here:"), QLineEdit::Normal, sourceURL, &ok); if (ok && !sourceURL.isEmpty()) { - setWindowTitle(sourceURL.right(sourceURL.length() - sourceURL.lastIndexOf('/') - 1)); - m_MediaObject.setCurrentSource(Phonon::MediaSource(QUrl::fromEncoded(sourceURL.toUtf8()))); - m_MediaObject.play(); + setLocation(sourceURL); settings.setValue("location", sourceURL); } } @@ -892,10 +897,11 @@ void MediaPlayer::openRamFile() } if (!list.isEmpty()) { - m_MediaObject.setCurrentSource(Phonon::MediaSource(list[0])); - m_MediaObject.play(); + m_MediaObject.clearQueue(); + setLocation(list[0].toString()); for (int i = 1; i < list.count(); i++) m_MediaObject.enqueue(Phonon::MediaSource(list[i])); + m_MediaObject.play(); } forwardButton->setEnabled(!m_MediaObject.queue().isEmpty()); diff --git a/demos/qmediaplayer/mediaplayer.h b/demos/qmediaplayer/mediaplayer.h index 14ed4ac..fc1bd90 100644 --- a/demos/qmediaplayer/mediaplayer.h +++ b/demos/qmediaplayer/mediaplayer.h @@ -112,6 +112,7 @@ public: void dropEvent(QDropEvent *e); void handleDrop(QDropEvent *e); void setFile(const QString &text); + void setLocation(const QString &location); void initVideoWindow(); void initSettingsDialog(); -- cgit v0.12 From 89e1e7fcbcbe93d8096afe0f7c240fe706cc9069 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 2 Dec 2009 16:20:00 +0000 Subject: Implemented support for playlist handling in Phonon MMF backend The main changes are: 1. MediaObject emits prefinishMark at the appropriate instant 2. MediaObject emits aboutToFinish at the appropriate instant 3. MediaObject switches to next source when playback completes Task-number: QTBUG-6214 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 84 ++++++++++++++----------- src/3rdparty/phonon/mmf/abstractmediaplayer.h | 17 ++--- src/3rdparty/phonon/mmf/abstractplayer.cpp | 22 +++---- src/3rdparty/phonon/mmf/abstractplayer.h | 13 ++-- src/3rdparty/phonon/mmf/audioplayer.cpp | 41 +++--------- src/3rdparty/phonon/mmf/audioplayer.h | 5 +- src/3rdparty/phonon/mmf/dummyplayer.cpp | 19 +----- src/3rdparty/phonon/mmf/dummyplayer.h | 8 +-- src/3rdparty/phonon/mmf/mediaobject.cpp | 54 +++++++++------- src/3rdparty/phonon/mmf/mediaobject.h | 11 +++- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 22 ++----- src/3rdparty/phonon/mmf/mmf_videoplayer.h | 3 +- 12 files changed, 129 insertions(+), 170 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 83c534a..18f96cc 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -20,6 +20,7 @@ along with this library. If not, see . #include "abstractmediaplayer.h" #include "defs.h" +#include "mediaobject.h" #include "utils.h" QT_BEGIN_NAMESPACE @@ -43,22 +44,16 @@ const int BufferStatusTimerInterval = 100; // ms // Constructor / destructor //----------------------------------------------------------------------------- -MMF::AbstractMediaPlayer::AbstractMediaPlayer() : - m_playPending(false) - , m_positionTimer(new QTimer(this)) - , m_bufferStatusTimer(new QTimer(this)) - , m_mmfMaxVolume(NullMaxVolume) -{ - connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); - connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); -} - -MMF::AbstractMediaPlayer::AbstractMediaPlayer(const AbstractPlayer& player) : - AbstractPlayer(player) +MMF::AbstractMediaPlayer::AbstractMediaPlayer + (MediaObject *parent, const AbstractPlayer *player) + : AbstractPlayer(player) + , m_parent(parent) , m_playPending(false) , m_positionTimer(new QTimer(this)) , m_bufferStatusTimer(new QTimer(this)) , m_mmfMaxVolume(NullMaxVolume) + , m_prefinishMarkSent(false) + , m_aboutToFinishSent(false) { connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); @@ -220,12 +215,7 @@ void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval) TRACE_EXIT_0(); } -MediaSource MMF::AbstractMediaPlayer::source() const -{ - return m_source; -} - -void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& file) +void MMF::AbstractMediaPlayer::open(const MediaSource &source, RFile& file) { TRACE_CONTEXT(AbstractMediaPlayer::setFileSource, EAudioApi); TRACE_ENTRY("state %d source.type %d", privateState(), source.type()); @@ -233,14 +223,10 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f close(); changeState(GroundState); - // TODO: is it correct to assign even if the media type is not supported in - // the switch statement below? - m_source = source; - TInt symbianErr = KErrNone; QString errorMessage; - switch (m_source.type()) { + switch (source.type()) { case MediaSource::LocalFile: { symbianErr = openFile(file); if (KErrNone != symbianErr) @@ -293,20 +279,6 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f TRACE_EXIT_0(); } -void MMF::AbstractMediaPlayer::setNextSource(const MediaSource &source) -{ - TRACE_CONTEXT(AbstractMediaPlayer::setNextSource, EAudioApi); - TRACE_ENTRY("state %d", privateState()); - - // TODO: handle 'next source' - - m_nextSource = source; - Q_UNUSED(source); - - TRACE_EXIT_0(); -} - - void MMF::AbstractMediaPlayer::volumeChanged(qreal volume) { TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal); @@ -402,6 +374,23 @@ void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume) doVolumeChanged(); } +void MMF::AbstractMediaPlayer::playbackComplete(int error) +{ + stopTimers(); + + if (KErrNone == error) { + changeState(StoppedState); + + // MediaObject::switchToNextSource deletes the current player, so we + // call it via delayed slot invokation to ensure that this object does + // not get deleted during execution of a member function. + QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection); + } + else { + setError(tr("Playback complete"), error); + } +} + qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in) { return in.Int64() / 1000; @@ -413,7 +402,26 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds void MMF::AbstractMediaPlayer::positionTick() { - emit MMF::AbstractPlayer::tick(currentTime()); + const qint64 current = currentTime(); + const qint64 total = totalTime(); + const qint64 remaining = total - current; + + if (prefinishMark() && !m_prefinishMarkSent) { + if (remaining < (prefinishMark() + tickInterval()/2)) { + m_prefinishMarkSent = true; + emit prefinishMarkReached(remaining); + } + } + + if (!m_aboutToFinishSent) { + if (remaining < tickInterval()) { + m_aboutToFinishSent = true; + emit aboutToFinish(); + } + } + + // For the MWC compiler, we need to qualify the base class. + emit MMF::AbstractPlayer::tick(current); } void MMF::AbstractMediaPlayer::bufferStatusTick() diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index 7c11ec7..24fa228 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -33,6 +33,7 @@ namespace Phonon namespace MMF { class AudioOutput; +class MediaObject; /** * Interface via which MMF client APIs for both audio and video can be @@ -43,19 +44,17 @@ class AbstractMediaPlayer : public AbstractPlayer Q_OBJECT protected: - AbstractMediaPlayer(); - explicit AbstractMediaPlayer(const AbstractPlayer& player); + AbstractMediaPlayer(MediaObject *parent, const AbstractPlayer *player); public: + virtual void open(const Phonon::MediaSource&, RFile&); + // MediaObjectInterface virtual void play(); virtual void pause(); virtual void stop(); virtual void seek(qint64 milliseconds); virtual bool isSeekable() const; - virtual MediaSource source() const; - virtual void setFileSource(const Phonon::MediaSource&, RFile&); - virtual void setNextSource(const MediaSource &source); virtual void volumeChanged(qreal volume); protected: @@ -81,6 +80,8 @@ protected: void bufferingStarted(); void bufferingComplete(); void maxVolumeChanged(int maxVolume); + void playbackComplete(int error); + static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &); private: @@ -96,6 +97,8 @@ private Q_SLOTS: void bufferStatusTick(); private: + MediaObject *const m_parent; + /** * This flag is set to true if play is called when the object is * in a Loading state. Once loading is complete, playback will @@ -110,8 +113,8 @@ private: int m_mmfMaxVolume; - MediaSource m_source; - MediaSource m_nextSource; + bool m_prefinishMarkSent; + bool m_aboutToFinishSent; QMultiMap m_metaData; diff --git a/src/3rdparty/phonon/mmf/abstractplayer.cpp b/src/3rdparty/phonon/mmf/abstractplayer.cpp index 13ff5fb..53973eb 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractplayer.cpp @@ -33,7 +33,7 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::AbstractPlayer::AbstractPlayer() +MMF::AbstractPlayer::AbstractPlayer(const AbstractPlayer *player) : m_videoOutput(0) , m_volume(InitialVolume) , m_state(GroundState) @@ -42,19 +42,13 @@ MMF::AbstractPlayer::AbstractPlayer() , m_transitionTime(0) , m_prefinishMark(0) { - -} - -MMF::AbstractPlayer::AbstractPlayer(const AbstractPlayer& player) - : m_videoOutput(player.m_videoOutput) - , m_volume(player.m_volume) - , m_state(GroundState) - , m_error(NoError) - , m_tickInterval(player.tickInterval()) - , m_transitionTime(player.transitionTime()) - , m_prefinishMark(player.prefinishMark()) -{ - + if(player) { + m_videoOutput = player->m_videoOutput; + m_volume = player->m_volume; + m_tickInterval = player->m_tickInterval; + m_transitionTime = player->m_transitionTime; + m_prefinishMark = player->m_prefinishMark; + } } //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h index 5aaae3c..40ad7f8 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.h +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -53,8 +53,9 @@ class AbstractPlayer : public QObject Q_OBJECT public: - AbstractPlayer(); - explicit AbstractPlayer(const AbstractPlayer& player); + AbstractPlayer(const AbstractPlayer *player); + + virtual void open(const Phonon::MediaSource&, RFile&) = 0; // MediaObjectInterface (implemented) qint32 tickInterval() const; @@ -75,12 +76,6 @@ public: virtual Phonon::ErrorType errorType() const; virtual QString errorString() const; virtual qint64 totalTime() const = 0; - virtual Phonon::MediaSource source() const = 0; - // This is a temporary hack to work around KErrInUse from MMF - // client utility OpenFileL calls - //virtual void setSource(const Phonon::MediaSource &) = 0; - virtual void setFileSource(const Phonon::MediaSource&, RFile&) = 0; - virtual void setNextSource(const Phonon::MediaSource &) = 0; virtual void volumeChanged(qreal volume); @@ -114,6 +109,8 @@ Q_SIGNALS: void stateChanged(Phonon::State oldState, Phonon::State newState); void metaDataChanged(const QMultiMap& metaData); + void aboutToFinish(); + void prefinishMarkReached(qint32 remaining); protected: /** diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 0967a27..77488f4 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -34,13 +34,9 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::AudioPlayer::AudioPlayer() -{ - construct(); -} - -MMF::AudioPlayer::AudioPlayer(const AbstractPlayer& player) - : AbstractMediaPlayer(player) +MMF::AudioPlayer::AudioPlayer(MediaObject *parent, const AbstractPlayer *player) + : AbstractMediaPlayer(parent, player) + , m_totalTime(0) { construct(); } @@ -177,7 +173,7 @@ qint64 MMF::AudioPlayer::currentTime() const qint64 MMF::AudioPlayer::totalTime() const { - return toMilliSeconds(m_player->Duration()); + return m_totalTime; } @@ -200,7 +196,8 @@ void MMF::AudioPlayer::MapcInitComplete(TInt aError, if (KErrNone == aError) { maxVolumeChanged(m_player->MaxVolume()); - emit totalTimeChanged(totalTime()); + m_totalTime = toMilliSeconds(m_player->Duration()); + emit totalTimeChanged(m_totalTime); updateMetaData(); changeState(StoppedState); } else { @@ -219,29 +216,9 @@ void MMF::AudioPlayer::MapcPlayComplete(TInt aError) TRACE_CONTEXT(AudioPlayer::MapcPlayComplete, EAudioInternal); TRACE_ENTRY("state %d error %d", state(), aError); - if (KErrNone == aError) { - changeState(StoppedState); - // TODO: move on to m_nextSource - } else { - setError(tr("Playback complete"), aError); - } - - /* - if (aError == KErrNone) { - if (m_nextSource.type() == MediaSource::Empty) { - emit finished(); - } else { - setSource(m_nextSource); - m_nextSource = MediaSource(); - } - - changeState(StoppedState); - } - else { - m_error = NormalError; - changeState(ErrorState); - } - */ + // Call base class function which handles end of playback for both + // audio and video clips. + playbackComplete(aError); TRACE_EXIT_0(); } diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index 5c7cfc1..4c4bcd0 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -50,8 +50,7 @@ class AudioPlayer : public AbstractMediaPlayer Q_OBJECT public: - AudioPlayer(); - explicit AudioPlayer(const AbstractPlayer& player); + AudioPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0); virtual ~AudioPlayer(); // AbstractMediaPlayer @@ -105,6 +104,8 @@ private: * CMdaAudioPlayerUtility and CDrmPlayerUtility */ QScopedPointer m_player; + + qint64 m_totalTime; }; } } diff --git a/src/3rdparty/phonon/mmf/dummyplayer.cpp b/src/3rdparty/phonon/mmf/dummyplayer.cpp index e6f3855..6970088 100644 --- a/src/3rdparty/phonon/mmf/dummyplayer.cpp +++ b/src/3rdparty/phonon/mmf/dummyplayer.cpp @@ -31,12 +31,7 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::DummyPlayer::DummyPlayer() -{ - -} - -MMF::DummyPlayer::DummyPlayer(const AbstractPlayer& player) +MMF::DummyPlayer::DummyPlayer(const AbstractPlayer *player) : AbstractPlayer(player) { @@ -97,17 +92,7 @@ qint64 MMF::DummyPlayer::totalTime() const return 0; } -MediaSource MMF::DummyPlayer::source() const -{ - return MediaSource(); -} - -void MMF::DummyPlayer::setFileSource(const Phonon::MediaSource &, RFile &) -{ - -} - -void MMF::DummyPlayer::setNextSource(const MediaSource &) +void MMF::DummyPlayer::open(const Phonon::MediaSource &, RFile &) { } diff --git a/src/3rdparty/phonon/mmf/dummyplayer.h b/src/3rdparty/phonon/mmf/dummyplayer.h index c6270c9..6841b5d 100644 --- a/src/3rdparty/phonon/mmf/dummyplayer.h +++ b/src/3rdparty/phonon/mmf/dummyplayer.h @@ -42,8 +42,7 @@ class AudioOutput; class DummyPlayer : public AbstractPlayer { public: - DummyPlayer(); - DummyPlayer(const AbstractPlayer& player); + DummyPlayer(const AbstractPlayer *player = 0); // MediaObjectInterface virtual void play(); @@ -56,12 +55,9 @@ public: virtual Phonon::State state() const; virtual Phonon::ErrorType errorType() const; virtual qint64 totalTime() const; - virtual MediaSource source() const; - // virtual void setSource(const MediaSource &); - virtual void setFileSource(const Phonon::MediaSource&, RFile&); - virtual void setNextSource(const MediaSource &source); // AbstractPlayer + virtual void open(const Phonon::MediaSource&, RFile&); virtual void doSetTickInterval(qint32 interval); }; } diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index bf1f268..a9a012f 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -45,6 +45,7 @@ using namespace Phonon::MMF; MMF::MediaObject::MediaObject(QObject *parent) : MMF::MediaNode::MediaNode(parent) , m_recognizerOpened(false) + , m_nextSourceSet(false) { m_player.reset(new DummyPlayer()); @@ -211,18 +212,20 @@ qint64 MMF::MediaObject::totalTime() const MediaSource MMF::MediaObject::source() const { - return m_player->source(); + return m_source; } void MMF::MediaObject::setSource(const MediaSource &source) { - createPlayer(source); - - // This is a hack to work around KErrInUse from MMF client utility - // OpenFileL calls - m_player->setFileSource(source, m_file); + switchToSource(source); +} - emit currentSourceChanged(source); +void MMF::MediaObject::switchToSource(const MediaSource &source) +{ + createPlayer(source); + m_source = source; + m_player->open(m_source, m_file); + emit currentSourceChanged(m_source); } void MMF::MediaObject::createPlayer(const MediaSource &source) @@ -281,29 +284,16 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) switch (mediaType) { case MediaTypeUnknown: TRACE_0("Media type could not be determined"); - if (oldPlayer) { - newPlayer = new DummyPlayer(*oldPlayer); - } else { - newPlayer = new DummyPlayer(); - } - + newPlayer = new DummyPlayer(oldPlayer); errorMessage = tr("Error opening source: media type could not be determined"); break; case MediaTypeAudio: - if (oldPlayer) { - newPlayer = new AudioPlayer(*oldPlayer); - } else { - newPlayer = new AudioPlayer(); - } + newPlayer = new AudioPlayer(this, oldPlayer); break; case MediaTypeVideo: - if (oldPlayer) { - newPlayer = new VideoPlayer(*oldPlayer); - } else { - newPlayer = new VideoPlayer(); - } + newPlayer = new VideoPlayer(this, oldPlayer); break; } @@ -323,6 +313,8 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) connect(m_player.data(), SIGNAL(tick(qint64)), SIGNAL(tick(qint64))); connect(m_player.data(), SIGNAL(bufferStatus(int)), SIGNAL(bufferStatus(int))); connect(m_player.data(), SIGNAL(metaDataChanged(QMultiMap)), SIGNAL(metaDataChanged(QMultiMap))); + connect(m_player.data(), SIGNAL(aboutToFinish()), SIGNAL(aboutToFinish())); + connect(m_player.data(), SIGNAL(prefinishMarkReached(qint32)), SIGNAL(tick(qint32))); // We need to call setError() after doing the connects, otherwise the // error won't be received. @@ -336,7 +328,8 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) void MMF::MediaObject::setNextSource(const MediaSource &source) { - m_player->setNextSource(source); + m_nextSource = source; + m_nextSourceSet = true; } qint32 MMF::MediaObject::prefinishMark() const @@ -385,5 +378,18 @@ bool MMF::MediaObject::activateOnMediaObject(MediaObject *) return true; } +//----------------------------------------------------------------------------- +// Playlist support +//----------------------------------------------------------------------------- + +void MMF::MediaObject::switchToNextSource() +{ + if (m_nextSourceSet) { + m_nextSourceSet = false; + switchToSource(m_nextSource); + play(); + } +} + QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index 07baad0..7c39598 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -87,16 +87,16 @@ public: public Q_SLOTS: void volumeChanged(qreal volume); + void switchToNextSource(); Q_SIGNALS: void totalTimeChanged(qint64 length); void hasVideoChanged(bool hasVideo); void seekableChanged(bool seekable); void bufferStatus(int); - // TODO: emit aboutToFinish from MediaObject void aboutToFinish(); - // TODO: emit prefinishMarkReached from MediaObject - void prefinishMarkReached(qint32); + void prefinishMarkReached(qint32 remaining); + // TODO: emit metaDataChanged from MediaObject void metaDataChanged(const QMultiMap& metaData); void currentSourceChanged(const MediaSource& source); void stateChanged(Phonon::State oldState, @@ -105,6 +105,7 @@ Q_SIGNALS: void tick(qint64 time); private: + void switchToSource(const MediaSource &source); void createPlayer(const MediaSource &source); bool openRecognizer(); @@ -121,6 +122,10 @@ private: RApaLsSession m_recognizer; RFs m_fileServer; + MediaSource m_source; + MediaSource m_nextSource; + bool m_nextSourceSet; + // Storing the file handle here to work around KErrInUse error // from MMF player utility OpenFileL functions RFile m_file; diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index dab7505..877dfb3 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -44,20 +44,8 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::VideoPlayer::VideoPlayer() - : m_wsSession(CCoeEnv::Static()->WsSession()) - , m_screenDevice(*CCoeEnv::Static()->ScreenDevice()) - , m_window(0) - , m_totalTime(0) - , m_pendingChanges(false) - , m_dsaActive(false) - , m_dsaWasActive(false) -{ - construct(); -} - -MMF::VideoPlayer::VideoPlayer(const AbstractPlayer& player) - : AbstractMediaPlayer(player) +MMF::VideoPlayer::VideoPlayer(MediaObject *parent, const AbstractPlayer *player) + : AbstractMediaPlayer(parent, player) , m_wsSession(CCoeEnv::Static()->WsSession()) , m_screenDevice(*CCoeEnv::Static()->ScreenDevice()) , m_window(0) @@ -287,9 +275,9 @@ void MMF::VideoPlayer::MvpuoPlayComplete(TInt aError) TRACE_CONTEXT(VideoPlayer::MvpuoPlayComplete, EVideoApi) TRACE_ENTRY("state %d error %d", state(), aError); - // TODO: handle aError - Q_UNUSED(aError); - changeState(StoppedState); + // Call base class function which handles end of playback for both + // audio and video clips. + playbackComplete(aError); TRACE_EXIT_0(); } diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h index 3ece19c..6200e39 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.h +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h @@ -44,8 +44,7 @@ class VideoPlayer : public AbstractMediaPlayer Q_OBJECT public: - VideoPlayer(); - explicit VideoPlayer(const AbstractPlayer& player); + VideoPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0); virtual ~VideoPlayer(); // AbstractPlayer -- cgit v0.12 From fe5b275bfab1605da3ee95b6eb1d976aecb0a8a8 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 8 Dec 2009 10:31:26 +0000 Subject: Re-emit prefinishMarkReached and aboutToFinish if rewound back past mark. Task-number: QTBUG-6214 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 25 +++++++++++++++++++++++-- src/3rdparty/phonon/mmf/abstractmediaplayer.h | 2 ++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 18f96cc..344413d 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -182,6 +182,7 @@ void MMF::AbstractMediaPlayer::seek(qint64 ms) } doSeek(ms); + resetMarksIfRewound(); if(wasPlaying && state() != ErrorState) { doPlay(); @@ -402,6 +403,14 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds void MMF::AbstractMediaPlayer::positionTick() { + emitMarksIfReached(); + + const qint64 current = currentTime(); + emit MMF::AbstractPlayer::tick(current); +} + +void MMF::AbstractMediaPlayer::emitMarksIfReached() +{ const qint64 current = currentTime(); const qint64 total = totalTime(); const qint64 remaining = total - current; @@ -419,9 +428,21 @@ void MMF::AbstractMediaPlayer::positionTick() emit aboutToFinish(); } } +} - // For the MWC compiler, we need to qualify the base class. - emit MMF::AbstractPlayer::tick(current); +void MMF::AbstractMediaPlayer::resetMarksIfRewound() +{ + const qint64 current = currentTime(); + const qint64 total = totalTime(); + const qint64 remaining = total - current; + + if (prefinishMark() && m_prefinishMarkSent) + if (remaining >= (prefinishMark() + tickInterval()/2)) + m_prefinishMarkSent = false; + + if (m_aboutToFinishSent) + if (remaining >= tickInterval()) + m_aboutToFinishSent = false; } void MMF::AbstractMediaPlayer::bufferStatusTick() diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index 24fa228..abd6bff 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -91,6 +91,8 @@ private: void stopBufferStatusTimer(); void stopTimers(); void doVolumeChanged(); + void emitMarksIfReached(); + void resetMarksIfRewound(); private Q_SLOTS: void positionTick(); -- cgit v0.12 From 8e21fc62fe40c8e393007516958c216ad8dbd629 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 2 Dec 2009 17:03:48 +0000 Subject: Removed dead code from Phonon MMF backend The following source types are handled in MediaObject::createPlayer Invalid, Disc, Stream, Empty The code removed in this patch is therefore never executed. Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 344413d..544762a 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -251,19 +251,9 @@ void MMF::AbstractMediaPlayer::open(const MediaSource &source, RFile& file) break; } - case MediaSource::Invalid: - case MediaSource::Disc: - case MediaSource::Stream: - TRACE_0("Error opening source: type not supported"); - errorMessage = tr("Error opening source: type not supported"); - break; - - case MediaSource::Empty: - TRACE_0("Empty source - doing nothing"); - TRACE_EXIT_0(); - return; + // Other source types are handled in MediaObject::createPlayer - // Protection against adding new media types and forgetting to update this switch + // Protection against adding new media types and forgetting to update this switch default: TRACE_PANIC(InvalidMediaTypePanic); } -- cgit v0.12 From 3f648dc075689e2ffedda2769cc76b4a56fb1073 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Fri, 4 Dec 2009 11:49:12 +0000 Subject: Implemented node disconnection in Phonon MMF backend Task-number: QTBUG-4663 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractaudioeffect.cpp | 58 ++++++--- src/3rdparty/phonon/mmf/abstractaudioeffect.h | 27 +++-- src/3rdparty/phonon/mmf/audioequalizer.cpp | 38 +++++- src/3rdparty/phonon/mmf/audioequalizer.h | 13 +- src/3rdparty/phonon/mmf/audiooutput.cpp | 13 +- src/3rdparty/phonon/mmf/audiooutput.h | 4 +- src/3rdparty/phonon/mmf/audioplayer.cpp | 15 ++- src/3rdparty/phonon/mmf/audioplayer.h | 21 ++-- src/3rdparty/phonon/mmf/backend.cpp | 29 +++-- src/3rdparty/phonon/mmf/bassboost.cpp | 22 +++- src/3rdparty/phonon/mmf/bassboost.h | 12 +- src/3rdparty/phonon/mmf/effectfactory.cpp | 2 +- src/3rdparty/phonon/mmf/mediaobject.cpp | 25 +++- src/3rdparty/phonon/mmf/mediaobject.h | 6 +- src/3rdparty/phonon/mmf/mmf_medianode.cpp | 153 ++++++++++++++---------- src/3rdparty/phonon/mmf/mmf_medianode.h | 76 ++++++------ src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 5 + src/3rdparty/phonon/mmf/mmf_videoplayer.h | 5 +- src/3rdparty/phonon/mmf/videowidget.cpp | 14 ++- src/3rdparty/phonon/mmf/videowidget.h | 4 +- 20 files changed, 348 insertions(+), 194 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp index a559249..8c73027 100644 --- a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp +++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp @@ -19,6 +19,8 @@ along with this library. If not, see . #include "mediaobject.h" #include "abstractaudioeffect.h" +#include "audioplayer.h" +#include "mmf_videoplayer.h" QT_BEGIN_NAMESPACE @@ -34,18 +36,13 @@ using namespace Phonon::MMF; */ AbstractAudioEffect::AbstractAudioEffect(QObject *parent, - const QList ¶ms) : MediaNode::MediaNode(parent) - , m_params(params) + const QList ¶ms) + : MediaNode::MediaNode(parent) + , m_player(0) + , m_params(params) { } -bool AbstractAudioEffect::disconnectMediaNode(MediaNode *target) -{ - MediaNode::disconnectMediaNode(target); - m_effect.reset(); - return true; -} - QList AbstractAudioEffect::parameters() const { return m_params; @@ -61,21 +58,44 @@ QVariant AbstractAudioEffect::parameterValue(const EffectParameter &queriedParam return val; } -bool AbstractAudioEffect::activateOnMediaObject(MediaObject *mo) -{ - AudioPlayer *const ap = qobject_cast(mo->abstractPlayer()); - - if (ap) - return activateOn(ap->player()); - else - return true; -} - void AbstractAudioEffect::setParameterValue(const EffectParameter ¶m, const QVariant &newValue) { m_values.insert(param.id(), newValue); parameterChanged(param.id(), newValue); + // TODO: handle audio effect errors + TRAP_IGNORE(m_effect->ApplyL()); +} + +void AbstractAudioEffect::connectMediaObject(MediaObject *mediaObject) +{ + Q_ASSERT_X(!m_player, Q_FUNC_INFO, "Player already connected"); + Q_ASSERT_X(!m_effect.data(), Q_FUNC_INFO, "Effect already created"); + + AbstractMediaPlayer *const player = + qobject_cast(mediaObject->abstractPlayer()); + + if (player) { + m_player = player; + + if (AudioPlayer *audioPlayer = qobject_cast(player)) { + connectAudioPlayer(audioPlayer->nativePlayer()); + } else { + VideoPlayer *videoPlayer = qobject_cast(player); + Q_ASSERT_X(videoPlayer, Q_FUNC_INFO, "Player type not recognised"); + connectVideoPlayer(videoPlayer->nativePlayer()); + } + + applyParameters(); + // TODO: handle audio effect errors + TRAP_IGNORE(m_effect->EnableL()); + } +} + +void AbstractAudioEffect::disconnectMediaObject(MediaObject * /*mediaObject*/) +{ + m_player = 0; + m_effect.reset(); } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.h b/src/3rdparty/phonon/mmf/abstractaudioeffect.h index 01542c9..10578af 100644 --- a/src/3rdparty/phonon/mmf/abstractaudioeffect.h +++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.h @@ -19,15 +19,16 @@ along with this library. If not, see . #ifndef PHONON_MMF_ABSTRACTEFFECT_H #define PHONON_MMF_ABSTRACTEFFECT_H -#include "mmf_medianode.h" - #include #include #include #include + #include "audioplayer.h" +#include "mmf_medianode.h" +#include "mmf_videoplayer.h" QT_BEGIN_NAMESPACE @@ -35,6 +36,7 @@ namespace Phonon { namespace MMF { +class AbstractMediaPlayer; /** * @short Base class for all effects for MMF. @@ -66,8 +68,6 @@ public: virtual void setParameterValue(const EffectParameter &, const QVariant &newValue); - virtual bool disconnectMediaNode(MediaNode *target); - enum Type { EffectAudioEqualizer = 1, @@ -81,21 +81,26 @@ public: }; protected: - virtual bool activateOn(CPlayerType *player) = 0; + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); + + virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player) = 0; + virtual void connectVideoPlayer(VideoPlayer::NativePlayer *player) = 0; + virtual void applyParameters() = 0; + virtual void parameterChanged(const int id, const QVariant &value) = 0; - /** - * Part of the implementation of AbstractAudioEffect. Forwards the call to - * activateOn(), essentially. - */ - virtual bool activateOnMediaObject(MediaObject *mo); - +protected: QScopedPointer m_effect; + private: + AbstractMediaPlayer * m_player; const QList m_params; QHash m_values; }; + } } diff --git a/src/3rdparty/phonon/mmf/audioequalizer.cpp b/src/3rdparty/phonon/mmf/audioequalizer.cpp index 7cc9bc7..51f1c32 100644 --- a/src/3rdparty/phonon/mmf/audioequalizer.cpp +++ b/src/3rdparty/phonon/mmf/audioequalizer.cpp @@ -16,6 +16,7 @@ along with this library. If not, see . */ +#include #include "audioequalizer.h" QT_BEGIN_NAMESPACE @@ -34,18 +35,43 @@ AudioEqualizer::AudioEqualizer(QObject *parent) : AbstractAudioEffect::AbstractA void AudioEqualizer::parameterChanged(const int pid, const QVariant &value) { - // There is no way to return an error from this function, so we just - // have to trap and ignore exceptions. - TRAP_IGNORE(static_cast(m_effect.data())->SetBandLevelL(pid, value.toInt())); + if (m_effect.data()) { + const int band = pid; + const int level = value.toInt(); + setBandLevel(band, level); + } } -bool AudioEqualizer::activateOn(CPlayerType *player) +void AudioEqualizer::connectAudioPlayer(AudioPlayer::NativePlayer *player) { CAudioEqualizer *ptr = 0; QT_TRAP_THROWING(ptr = CAudioEqualizer::NewL(*player)); m_effect.reset(ptr); +} - return true; +void AudioEqualizer::connectVideoPlayer(VideoPlayer::NativePlayer *player) +{ + CAudioEqualizer *ptr = 0; + QT_TRAP_THROWING(ptr = CAudioEqualizer::NewL(*player)); + m_effect.reset(ptr); +} + +void AudioEqualizer::applyParameters() +{ + Q_ASSERT_X(m_effect.data(), Q_FUNC_INFO, "Effect not created"); + EffectParameter param; + foreach (param, parameters()) { + const int band = param.id(); + const int level = parameterValue(param).toInt(); + setBandLevel(band, level); + } +} + +void AudioEqualizer::setBandLevel(int band, int level) +{ + CAudioEqualizer *const effect = static_cast(m_effect.data()); + // TODO: handle audio effect errors + TRAP_IGNORE(effect->SetBandLevelL(band, level)); } QList AudioEqualizer::createParams() @@ -57,7 +83,7 @@ QList AudioEqualizer::createParams() AudioPlayer dummyPlayer; CAudioEqualizer *eqPtr = 0; - QT_TRAP_THROWING(eqPtr = CAudioEqualizer::NewL(*dummyPlayer.player());) + QT_TRAP_THROWING(eqPtr = CAudioEqualizer::NewL(*dummyPlayer.nativePlayer())); QScopedPointer e(eqPtr); TInt32 dbMin; diff --git a/src/3rdparty/phonon/mmf/audioequalizer.h b/src/3rdparty/phonon/mmf/audioequalizer.h index d4c8165..9910ea4 100644 --- a/src/3rdparty/phonon/mmf/audioequalizer.h +++ b/src/3rdparty/phonon/mmf/audioequalizer.h @@ -19,7 +19,6 @@ along with this library. If not, see . #ifndef PHONON_MMF_AUDIOEQUALIZER_H #define PHONON_MMF_AUDIOEQUALIZER_H -#include #include "abstractaudioeffect.h" QT_BEGIN_NAMESPACE @@ -43,14 +42,18 @@ public: AudioEqualizer(QObject *parent); protected: - virtual void parameterChanged(const int id, - const QVariant &value); + // AbstractAudioEffect + virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player); + virtual void connectVideoPlayer(VideoPlayer::NativePlayer *player); + virtual void applyParameters(); + virtual void parameterChanged(const int id, const QVariant &value); - virtual bool activateOn(CPlayerType *player); +private: + void setBandLevel(int band, int level); private: static QList createParams(); - QScopedPointer m_bassBoost; + }; } } diff --git a/src/3rdparty/phonon/mmf/audiooutput.cpp b/src/3rdparty/phonon/mmf/audiooutput.cpp index d6e0c13..c6be20b 100644 --- a/src/3rdparty/phonon/mmf/audiooutput.cpp +++ b/src/3rdparty/phonon/mmf/audiooutput.cpp @@ -81,13 +81,18 @@ bool MMF::AudioOutput::setOutputDevice(int index) return true; } -bool MMF::AudioOutput::activateOnMediaObject(MediaObject *mo) +void MMF::AudioOutput::connectMediaObject(MediaObject *mediaObject) { // Ensure that the MediaObject has the correct initial volume - mo->volumeChanged(m_volume); + mediaObject->volumeChanged(m_volume); // Connect MediaObject to receive future volume changes - connect(this, SIGNAL(volumeChanged(qreal)), mo, SLOT(volumeChanged(qreal))); - return true; + connect(this, SIGNAL(volumeChanged(qreal)), mediaObject, SLOT(volumeChanged(qreal))); +} + +void MMF::AudioOutput::disconnectMediaObject(MediaObject *mediaObject) +{ + // Disconnect all signal-slot connections + disconnect(this, 0, mediaObject, 0); } QHash MMF::AudioOutput::audioOutputDescription(int index) diff --git a/src/3rdparty/phonon/mmf/audiooutput.h b/src/3rdparty/phonon/mmf/audiooutput.h index 1e1e134..67aaa38 100644 --- a/src/3rdparty/phonon/mmf/audiooutput.h +++ b/src/3rdparty/phonon/mmf/audiooutput.h @@ -74,7 +74,9 @@ public: }; protected: - virtual bool activateOnMediaObject(MediaObject *mo); + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); Q_SIGNALS: void volumeChanged(qreal volume); diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 77488f4..ee07229 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -46,8 +46,8 @@ void MMF::AudioPlayer::construct() TRACE_CONTEXT(AudioPlayer::AudioPlayer, EAudioApi); TRACE_ENTRY_0(); - CPlayerType *player = 0; - QT_TRAP_THROWING(player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone)); + NativePlayer *player = 0; + QT_TRAP_THROWING(player = NativePlayer::NewL(*this, 0, EMdaPriorityPreferenceNone)); m_player.reset(player); m_player->RegisterForAudioLoadingNotification(*this); @@ -62,6 +62,11 @@ MMF::AudioPlayer::~AudioPlayer() TRACE_EXIT_0(); } +MMF::AudioPlayer::NativePlayer *MMF::AudioPlayer::nativePlayer() const +{ + return m_player.data(); +} + //----------------------------------------------------------------------------- // Public API //----------------------------------------------------------------------------- @@ -223,12 +228,6 @@ void MMF::AudioPlayer::MapcPlayComplete(TInt aError) TRACE_EXIT_0(); } -CPlayerType *MMF::AudioPlayer::player() const -{ - return m_player.data(); -} - - #ifdef QT_PHONON_MMF_AUDIO_DRM void MMF::AudioPlayer::MaloLoadingStarted() { diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index 4c4bcd0..0eb8bb7 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -26,12 +26,10 @@ class TTimeIntervalMicroSeconds; #ifdef QT_PHONON_MMF_AUDIO_DRM #include -typedef CDrmPlayerUtility CPlayerType; -typedef MDrmAudioPlayerCallback MPlayerObserverType; +typedef MDrmAudioPlayerCallback NativePlayerObserver; #else #include -typedef CMdaAudioPlayerUtility CPlayerType; -typedef MMdaAudioPlayerCallback MPlayerObserverType; +typedef MMdaAudioPlayerCallback NativePlayerObserver; #endif QT_BEGIN_NAMESPACE @@ -44,7 +42,7 @@ namespace MMF * @short Wrapper over MMF audio client utility */ class AudioPlayer : public AbstractMediaPlayer - , public MPlayerObserverType // typedef + , public NativePlayerObserver , public MAudioLoadingObserver { Q_OBJECT @@ -53,6 +51,14 @@ public: AudioPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0); virtual ~AudioPlayer(); +#ifdef QT_PHONON_MMF_AUDIO_DRM +typedef CDrmPlayerUtility NativePlayer; +#else +typedef CMdaAudioPlayerUtility NativePlayer; +#endif + + NativePlayer *nativePlayer() const; + // AbstractMediaPlayer virtual void doPlay(); virtual void doPause(); @@ -76,7 +82,7 @@ public: /** * This class owns the pointer. */ - CPlayerType *player() const; + NativePlayer *player() const; private: void construct(); @@ -103,9 +109,10 @@ private: * Using CPlayerType typedef in order to be able to easily switch between * CMdaAudioPlayerUtility and CDrmPlayerUtility */ - QScopedPointer m_player; + QScopedPointer m_player; qint64 m_totalTime; + }; } } diff --git a/src/3rdparty/phonon/mmf/backend.cpp b/src/3rdparty/phonon/mmf/backend.cpp index 7e3a67f..0c07f66 100644 --- a/src/3rdparty/phonon/mmf/backend.cpp +++ b/src/3rdparty/phonon/mmf/backend.cpp @@ -139,29 +139,32 @@ bool Backend::startConnectionChange(QSet) return true; } -bool Backend::connectNodes(QObject *source, QObject *target) +bool Backend::connectNodes(QObject *sourceObject, QObject *targetObject) { TRACE_CONTEXT(Backend::connectNodes, EBackend); - TRACE_ENTRY("source 0x%08x target 0x%08x", source, target); - Q_ASSERT(qobject_cast(source)); - Q_ASSERT(qobject_cast(target)); + TRACE_ENTRY("source 0x%08x target 0x%08x", sourceObject, targetObject); - MediaNode *const mediaSource = static_cast(source); - MediaNode *const mediaTarget = static_cast(target); + MediaNode *const source = qobject_cast(sourceObject); + MediaNode *const target = qobject_cast(targetObject); - return mediaSource->connectMediaNode(mediaTarget); + Q_ASSERT_X(source, Q_FUNC_INFO, "source is not a MediaNode"); + Q_ASSERT_X(target, Q_FUNC_INFO, "target is not a MediaNode"); + + return source->connectOutput(target); } -bool Backend::disconnectNodes(QObject *source, QObject *target) +bool Backend::disconnectNodes(QObject *sourceObject, QObject *targetObject) { TRACE_CONTEXT(Backend::disconnectNodes, EBackend); - TRACE_ENTRY("source 0x%08x target 0x%08x", source, target); - Q_ASSERT(qobject_cast(source)); - Q_ASSERT(qobject_cast(target)); + TRACE_ENTRY("source 0x%08x target 0x%08x", sourceObject, targetObject); + + MediaNode *const source = qobject_cast(sourceObject); + MediaNode *const target = qobject_cast(targetObject); - const bool result = static_cast(source)->disconnectMediaNode(static_cast(target)); + Q_ASSERT_X(source, Q_FUNC_INFO, "source is not a MediaNode"); + Q_ASSERT_X(target, Q_FUNC_INFO, "target is not a MediaNode"); - TRACE_RETURN("%d", result); + return source->disconnectOutput(target); } bool Backend::endConnectionChange(QSet) diff --git a/src/3rdparty/phonon/mmf/bassboost.cpp b/src/3rdparty/phonon/mmf/bassboost.cpp index e34f9e7..36069fb 100644 --- a/src/3rdparty/phonon/mmf/bassboost.cpp +++ b/src/3rdparty/phonon/mmf/bassboost.cpp @@ -16,6 +16,7 @@ along with this library. If not, see . */ +#include #include "bassboost.h" QT_BEGIN_NAMESPACE @@ -35,13 +36,26 @@ BassBoost::BassBoost(QObject *parent) : AbstractAudioEffect::AbstractAudioEffect void BassBoost::parameterChanged(const int, const QVariant &) { - // We should never be called, because we have no parameters. + Q_ASSERT_X(false, Q_FUNC_INFO, "BassBoost has not parameters"); } -bool BassBoost::activateOn(CPlayerType *player) +void BassBoost::connectAudioPlayer(AudioPlayer::NativePlayer *player) { - m_effect.reset(CBassBoost::NewL(*player, true)); - return true; + CBassBoost *ptr = 0; + QT_TRAP_THROWING(ptr = CBassBoost::NewL(*player)); + m_effect.reset(ptr); +} + +void BassBoost::connectVideoPlayer(VideoPlayer::NativePlayer *player) +{ + CBassBoost *ptr = 0; + QT_TRAP_THROWING(ptr = CBassBoost::NewL(*player)); + m_effect.reset(ptr); +} + +void BassBoost::applyParameters() +{ + // No parameters to apply } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/bassboost.h b/src/3rdparty/phonon/mmf/bassboost.h index c16393a..1b893db 100644 --- a/src/3rdparty/phonon/mmf/bassboost.h +++ b/src/3rdparty/phonon/mmf/bassboost.h @@ -19,7 +19,6 @@ along with this library. If not, see . #ifndef PHONON_MMF_BASSBOOST_H #define PHONON_MMF_BASSBOOST_H -#include #include "abstractaudioeffect.h" QT_BEGIN_NAMESPACE @@ -41,13 +40,12 @@ public: BassBoost(QObject *parent); protected: - virtual void parameterChanged(const int id, - const QVariant &value); + // AbstractAudioEffect + virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player); + virtual void connectVideoPlayer(VideoPlayer::NativePlayer *player); + virtual void applyParameters(); + virtual void parameterChanged(const int id, const QVariant &value); - virtual bool activateOn(CPlayerType *player); - -private: - QScopedPointer m_bassBoost; }; } } diff --git a/src/3rdparty/phonon/mmf/effectfactory.cpp b/src/3rdparty/phonon/mmf/effectfactory.cpp index e9c5e27..cc94367 100644 --- a/src/3rdparty/phonon/mmf/effectfactory.cpp +++ b/src/3rdparty/phonon/mmf/effectfactory.cpp @@ -113,7 +113,7 @@ bool isEffectSupported() AudioPlayer audioPlayer; QScopedPointer eff; - TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.player()))); + TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.nativePlayer()))); return errorCode != KErrNone; } diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index a9a012f..4653fee 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -358,6 +358,25 @@ void MMF::MediaObject::volumeChanged(qreal volume) } //----------------------------------------------------------------------------- +// MediaNode +//----------------------------------------------------------------------------- + +void MMF::MediaObject::connectMediaObject(MediaObject * /*mediaObject*/) +{ + // This function should never be called - see MediaNode::setMediaObject() + Q_ASSERT_X(false, Q_FUNC_INFO, + "Connection of MediaObject to MediaObject"); +} + +void MMF::MediaObject::disconnectMediaObject(MediaObject * /*mediaObject*/) +{ + // This function should never be called - see MediaNode::setMediaObject() + Q_ASSERT_X(false, Q_FUNC_INFO, + "Disconnection of MediaObject from MediaObject"); +} + + +//----------------------------------------------------------------------------- // Video output //----------------------------------------------------------------------------- @@ -372,12 +391,6 @@ AbstractPlayer *MMF::MediaObject::abstractPlayer() const return m_player.data(); } -bool MMF::MediaObject::activateOnMediaObject(MediaObject *) -{ - // Guess what, we do nothing. - return true; -} - //----------------------------------------------------------------------------- // Playlist support //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index 7c39598..668b953 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -75,6 +75,10 @@ public: virtual qint32 transitionTime() const; virtual void setTransitionTime(qint32); + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); + /** * This class owns the AbstractPlayer, and will delete it upon * destruction. @@ -83,8 +87,6 @@ public: void setVideoOutput(VideoOutput* videoOutput); - virtual bool activateOnMediaObject(MediaObject *); - public Q_SLOTS: void volumeChanged(qreal volume); void switchToNextSource(); diff --git a/src/3rdparty/phonon/mmf/mmf_medianode.cpp b/src/3rdparty/phonon/mmf/mmf_medianode.cpp index 253c5e7..ca413d9 100644 --- a/src/3rdparty/phonon/mmf/mmf_medianode.cpp +++ b/src/3rdparty/phonon/mmf/mmf_medianode.cpp @@ -29,92 +29,123 @@ using namespace Phonon::MMF; \internal */ -MMF::MediaNode::MediaNode(QObject *parent) : QObject::QObject(parent) - , m_source(0) - , m_target(0) - , m_isApplied(false) +MMF::MediaNode::MediaNode(QObject *parent) + : QObject(parent) + , m_mediaObject(qobject_cast(this)) + , m_input(0) { -} - -bool MMF::MediaNode::connectMediaNode(MediaNode *target) -{ - m_target = target; - m_target->setSource(this); - return applyNodesOnMediaObject(target); } -bool MMF::MediaNode::disconnectMediaNode(MediaNode *target) +MMF::MediaNode::~MediaNode() { - Q_UNUSED(target); - m_target = 0; - m_isApplied = false; - return true; + // Phonon framework ensures nodes are disconnected before being destroyed. + Q_ASSERT_X(!m_mediaObject, Q_FUNC_INFO, + "Media node not disconnected before destruction"); } -void MMF::MediaNode::setSource(MediaNode *source) +bool MMF::MediaNode::connectOutput(MediaNode *output) { - m_source = source; + Q_ASSERT_X(output, Q_FUNC_INFO, "Null output pointer"); + + bool connected = false; + + // Check that this connection will not result in a graph which + // containing more than one MediaObject + const bool mediaObjectMisMatch = + m_mediaObject + && output->m_mediaObject + && m_mediaObject != output->m_mediaObject; + + const bool canConnect = + !output->isMediaObject() + && !output->m_input + && !m_outputs.contains(output); + + if (canConnect && !mediaObjectMisMatch) { + output->m_input = this; + m_outputs += output; + updateMediaObject(); + connected = true; + } + + return connected; } -MMF::MediaNode *MMF::MediaNode::source() const +bool MMF::MediaNode::disconnectOutput(MediaNode *output) { - return m_source; + Q_ASSERT_X(output, Q_FUNC_INFO, "Null output pointer"); + + bool disconnected = false; + + if (m_outputs.contains(output) && this == output->m_input) { + output->m_input = 0; + const bool removed = m_outputs.removeOne(output); + Q_ASSERT_X(removed, Q_FUNC_INFO, "Output removal failed"); + + Q_ASSERT_X(!m_outputs.contains(output), Q_FUNC_INFO, + "Output list contains duplicate entries"); + + // Perform traversal across each of the two graphs separately + updateMediaObject(); + output->updateMediaObject(); + + disconnected = true; + } + + return disconnected; } -MMF::MediaNode *MMF::MediaNode::target() const +bool MMF::MediaNode::isMediaObject() const { - return m_target; + return (qobject_cast(this) != 0); } -bool MMF::MediaNode::applyNodesOnMediaObject(MediaNode *) +void MMF::MediaNode::updateMediaObject() { - // Algorithmically, this can be expressed in a more efficient way by - // exercising available assumptions, but it complicates code for input - // data(length of the graph) which typically is very small. - - // First, we go to the very beginning of the graph. - MMF::MediaNode *current = this; - do { - MediaNode *const candidate = current->source(); - if (candidate) - current = candidate; - else - break; - } - while (current); - - // Now we do two things, while walking to the other end: - // 1. Find the MediaObject, if present - // 2. Collect a list of all unapplied MediaNodes - - QList unapplied; - MMF::MediaObject *mo = 0; + QList nodes; + MediaObject *mediaObject = 0; - do { - if (!current->m_isApplied) - unapplied.append(current); + // Traverse the graph, collecting a list of nodes, and locating + // the MediaObject node, if present + visit(nodes, mediaObject); - if (!mo) - mo = qobject_cast(current); + MediaNode *node = 0; + foreach(node, nodes) + node->setMediaObject(mediaObject); +} - current = current->target(); +void MMF::MediaNode::setMediaObject(MediaObject *mediaObject) +{ + if(!isMediaObject() && m_mediaObject != mediaObject) { + if (!mediaObject) + disconnectMediaObject(m_mediaObject); + else { + Q_ASSERT_X(!m_mediaObject, Q_FUNC_INFO, "MediaObject already set"); + connectMediaObject(mediaObject); + } + m_mediaObject = mediaObject; } - while (current); +} - // Now, lets activate all the objects, if we found the MediaObject. +void MMF::MediaNode::visit(QList& visited, MediaObject*& mediaObject) +{ + if (isMediaObject()) { + // There can never be more than one MediaObject per graph, due to the + // mediaObjectMisMatch test in connectOutput(). + Q_ASSERT_X(!mediaObject, Q_FUNC_INFO, "MediaObject already found"); + mediaObject = static_cast(this); + } - if (mo) { - for (int i = 0; i < unapplied.count(); ++i) { - MediaNode *const at = unapplied.at(i); + visited += this; - // We don't want to apply MediaObject on itself. - if (at != mo) - at->activateOnMediaObject(mo); - } - } + if (m_input && !visited.contains(m_input)) + m_input->visit(visited, mediaObject); - return true; + MediaNode *output = 0; + foreach (output, m_outputs) + if (!visited.contains(output)) + output->visit(visited, mediaObject); } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/mmf_medianode.h b/src/3rdparty/phonon/mmf/mmf_medianode.h index 4616ff1..0ed21c4 100644 --- a/src/3rdparty/phonon/mmf/mmf_medianode.h +++ b/src/3rdparty/phonon/mmf/mmf_medianode.h @@ -43,54 +43,62 @@ class MediaObject; /** * @short Base class for all nodes in the MMF backend. * - * MediaNode is the base class for all nodes in the chain for MMF. Currently - * they are: + * MediaNode is the base class for all nodes created by the MMF + * backend. * - * - MediaObject: a source of media - * - AbstractEffect: supplying audio effects - * - AudioOutput: pretty much a dummy interface, but is also MediaNode in order - * to simplify connection/disconnection. + * These nodes may be one of the following types: * - * MediaNode provides spectatability into the chain, and also allows the - * connection code to be written in a polymorphic manner, instead of putting it - * all in the Backend class. Due to that MMF has no concept of chaining, the - * order of the nodes in the graph has no meaning. + * - MediaObject + * This represents the source of media data. It encapsulates the + * appropriate MMF client API for playing audio or video. + * - AudioOutput + * This represents the audio output device. Since the MMF client API + * does not expose the output device directly, this backend node + * simply forwards volume control commands to the MediaObject. + * - VideoWidget + * A native widget on which video will be rendered. + * - An audio effect, derived form AbstractAudioEffect + * + * Because the MMF API does not support the concept of a media filter graph, + * this class must ensure the following: + * + * - Each media graph contains at most one MediaObject instance. + * - Every non-MediaObject node holds a reference to the MediaObject. This + * allows commands to be sent through the graph to the encapsulated MMF client + * API. */ class MediaNode : public QObject { Q_OBJECT public: MediaNode(QObject *parent); + ~MediaNode(); + + bool connectOutput(MediaNode *output); + bool disconnectOutput(MediaNode *output); + + virtual void connectMediaObject(MediaObject *mediaObject) = 0; + virtual void disconnectMediaObject(MediaObject *mediaObject) = 0; - virtual bool connectMediaNode(MediaNode *target); - virtual bool disconnectMediaNode(MediaNode *target); - void setSource(MediaNode *source); +private: + bool isMediaObject() const; - MediaNode *source() const; - MediaNode *target() const; + void updateMediaObject(); + void setMediaObject(MediaObject *mediaObject); -protected: - /** - * When connectMediaNode() is called and a MediaObject is part of - * the its graph, this function will be called for each MediaNode in the - * graph for which it hasn't been called yet. - * - * The caller guarantees that @p mo is always non-null. - */ - virtual bool activateOnMediaObject(MediaObject *mo) = 0; + typedef QList NodeList; + void visit(QList& visited, MediaObject*& mediaObject); private: - /** - * Finds a MediaObject anywhere in the graph @p target is apart of, and - * calls activateOnMediaObject() for all MediaNodes in the graph for which - * it hasn't been applied to already. - */ - bool applyNodesOnMediaObject(MediaNode *target); - - MediaNode * m_source; - MediaNode * m_target; - bool m_isApplied; + MediaObject * m_mediaObject; + + // All nodes except MediaObject may have an input + MediaNode * m_input; + + // Only MediaObject can have more than one output + QList m_outputs; }; + } } diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 877dfb3..127edb4 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -97,6 +97,11 @@ MMF::VideoPlayer::~VideoPlayer() TRACE_EXIT_0(); } +CVideoPlayerUtility* MMF::VideoPlayer::nativePlayer() const +{ + return m_player.data(); +} + //----------------------------------------------------------------------------- // Public API //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h index 6200e39..0253ab9 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.h +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h @@ -47,6 +47,9 @@ public: VideoPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0); virtual ~VideoPlayer(); + typedef CVideoPlayerUtility NativePlayer; + NativePlayer *nativePlayer() const; + // AbstractPlayer virtual void doPlay(); virtual void doPause(); @@ -105,7 +108,7 @@ private: virtual void MvloLoadingComplete(); private: - QScopedPointer m_player; + QScopedPointer m_player; // Not owned RWsSession& m_wsSession; diff --git a/src/3rdparty/phonon/mmf/videowidget.cpp b/src/3rdparty/phonon/mmf/videowidget.cpp index bd22307..bc9acfd 100644 --- a/src/3rdparty/phonon/mmf/videowidget.cpp +++ b/src/3rdparty/phonon/mmf/videowidget.cpp @@ -157,10 +157,18 @@ QWidget* MMF::VideoWidget::widget() return m_videoOutput.data(); } -bool MMF::VideoWidget::activateOnMediaObject(MediaObject *mo) +//----------------------------------------------------------------------------- +// MediaNode +//----------------------------------------------------------------------------- + +void MMF::VideoWidget::connectMediaObject(MediaObject *mediaObject) +{ + mediaObject->setVideoOutput(m_videoOutput.data()); +} + +void MMF::VideoWidget::disconnectMediaObject(MediaObject *mediaObject) { - mo->setVideoOutput(m_videoOutput.data()); - return true; + mediaObject->setVideoOutput(0); } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/videowidget.h b/src/3rdparty/phonon/mmf/videowidget.h index 2f0978b..a876748 100644 --- a/src/3rdparty/phonon/mmf/videowidget.h +++ b/src/3rdparty/phonon/mmf/videowidget.h @@ -61,7 +61,9 @@ public: virtual QWidget *widget(); protected: - virtual bool activateOnMediaObject(MediaObject *mo); + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); private: QScopedPointer m_videoOutput; -- cgit v0.12 From 60d27f4b9fd2dbed204260334b817ce41788cb3e Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 7 Jan 2010 13:42:05 +0200 Subject: Added UIDs and icons to some webkit examples Reviewed-by: TrustMe --- examples/webkit/domtraversal/domtraversal.pro | 5 +++++ examples/webkit/fancybrowser/fancybrowser.pro | 5 ++++- examples/webkit/googlechat/googlechat.pro | 5 ++++- examples/webkit/simpleselector/simpleselector.pro | 5 +++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/examples/webkit/domtraversal/domtraversal.pro b/examples/webkit/domtraversal/domtraversal.pro index 49400de..ba5f2d8 100644 --- a/examples/webkit/domtraversal/domtraversal.pro +++ b/examples/webkit/domtraversal/domtraversal.pro @@ -9,3 +9,8 @@ target.path = $$[QT_INSTALL_EXAMPLES]/webkit/domtraversal sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/domtraversal INSTALLS += target sources + +symbian { + TARGET.UID3 = 0xA000D7CB + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) +} diff --git a/examples/webkit/fancybrowser/fancybrowser.pro b/examples/webkit/fancybrowser/fancybrowser.pro index e496241..3786d9c 100644 --- a/examples/webkit/fancybrowser/fancybrowser.pro +++ b/examples/webkit/fancybrowser/fancybrowser.pro @@ -10,4 +10,7 @@ sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/fancybrowser INSTALLS += target sources -symbian:TARGET.UID3 = 0xA000CF6C +symbian { + TARGET.UID3 = 0xA000CF6C + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) +} diff --git a/examples/webkit/googlechat/googlechat.pro b/examples/webkit/googlechat/googlechat.pro index 8e4f9a6..3d32c1b 100644 --- a/examples/webkit/googlechat/googlechat.pro +++ b/examples/webkit/googlechat/googlechat.pro @@ -10,4 +10,7 @@ sources.files = $$SOURCES $$HEADERS $$FORMS *.pro sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/googlechat INSTALLS += target sources -symbian:TARGET.UID3 = 0xA000CF6E +symbian { + TARGET.UID3 = 0xA000CF6E + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) +} diff --git a/examples/webkit/simpleselector/simpleselector.pro b/examples/webkit/simpleselector/simpleselector.pro index 3f3037f..acd0ae7 100644 --- a/examples/webkit/simpleselector/simpleselector.pro +++ b/examples/webkit/simpleselector/simpleselector.pro @@ -9,3 +9,8 @@ target.path = $$[QT_INSTALL_EXAMPLES]/webkit/simpleselector sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/simpleselector INSTALLS += target sources + +symbian { + TARGET.UID3 = 0xA000D7CC + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) +} -- cgit v0.12 From e2f2765b52508515874edea7015c01eb95ff89be Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 7 Jan 2010 15:10:07 +0200 Subject: Separated "make run" and "make runonphone" targets Reviewed-by: axis --- doc/src/platforms/symbian-introduction.qdoc | 28 ++++++++++++++++++++++------ qmake/generators/symbian/symmake.cpp | 7 +------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/doc/src/platforms/symbian-introduction.qdoc b/doc/src/platforms/symbian-introduction.qdoc index 477e629..4d06bbc 100644 --- a/doc/src/platforms/symbian-introduction.qdoc +++ b/doc/src/platforms/symbian-introduction.qdoc @@ -124,12 +124,8 @@ \row \o \c release-gcce \o Build release binaries for hardware using GCCE. \row \o \c debug-armv5 \o Build debug binaries for hardware using RVCT. \row \o \c release-armv5 \o Build release binaries for hardware using RVCT. - \row \o \c run \o Run the application. Environment variable - \c QT_SIS_TARGET (see below) can be used to specify which - build target is run. By default it is the last build target. - Note that running the application on real device - using this command requires \c TRK application to be running - on the device. + \row \o \c run \o Run the application on the emulator. + \row \o \c runonphone \o Run the application on a device. \row \o \c sis \o Create signed \c .sis file for project. \endtable @@ -199,4 +195,24 @@ with the \c QT_SIS_OPTIONS=-i, like this: \snippet doc/src/snippets/code/doc_src_symbian-introduction.qdoc 5 + + \section1 Running applications from command line + + The application can be launched on the emulator using \c{make run} command. + + The application can be launched on a device using \c{make runonphone} command. + When this command is invoked, a \c .sis file is first created as if \c{make sis} + command was invoked (see above for details). + \bold{Note:} Running the application on a device using this command requires + \c TRK application to be running on the device. + + Additional environment variables that can be utilized with these commands are: + \table + \row \o \c QT_RUN_OPTIONS \o Any command line parameters you wish to pass + to your application. + \row \o \c QT_RUN_ON_PHONE_OPTIONS \o Options for runonphone application. + Execute \c runonphone from command line for + more information about available options. + \c{make runonphone} only. + \endtable */ diff --git a/qmake/generators/symbian/symmake.cpp b/qmake/generators/symbian/symmake.cpp index b2709d1..81f2d15 100644 --- a/qmake/generators/symbian/symmake.cpp +++ b/qmake/generators/symbian/symmake.cpp @@ -1857,16 +1857,11 @@ void SymbianMakefileGenerator::generateExecutionTargets(QTextStream& t, const QS // create execution targets if (targetType == TypeExe) { if (platforms.contains("winscw")) { - t << "ifeq (\"DEBUG-winscw\", \"$(QT_SIS_TARGET)\")" << endl; t << "run:" << endl; t << "\t-call " << epocRoot() << "epoc32/release/winscw/udeb/" << fixedTarget << ".exe " << "$(QT_RUN_OPTIONS)" << endl; - t << "else" << endl; } - t << "run: sis" << endl; + t << "runonphone: sis" << endl; t << "\trunonphone $(QT_RUN_ON_PHONE_OPTIONS) --sis " << fixedTarget << "_$(QT_SIS_TARGET).sis " << fixedTarget << ".exe " << "$(QT_RUN_OPTIONS)" << endl; - if (platforms.contains("winscw")) { - t << "endif" << endl; - } t << endl; } } -- cgit v0.12 From 784374ac949ecf2fdc6895908e1e4dfe938931b8 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 7 Jan 2010 17:25:13 +0200 Subject: Deploy sqlite3.sis instead of sqlite3.dll in Symbian Task-number: QTBUG-4879 Reviewed-by: Shane Kearns --- src/s60installs/s60installs.pro | 7 +++---- src/s60installs/sqlite3.sis | Bin 0 -> 286192 bytes 2 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 src/s60installs/sqlite3.sis diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro index e024396..eb35419 100644 --- a/src/s60installs/s60installs.pro +++ b/src/s60installs/s60installs.pro @@ -35,10 +35,8 @@ symbian: { qtlibraries.pkg_postrules += qts60plugindeployment sqlitedeployment = \ - "; Deploy sqlite onto phone that does not have it (this should be replaced with embedded sis file when available)" \ - "IF NOT package(0x2002533b) " \ - "\"$${EPOCROOT}epoc32/release/$(PLATFORM)/$(TARGET)/sqlite3.dll\" - \"c:\\sys\\bin\\sqlite3.dll\"" \ - "ENDIF" + "; Deploy sqlite onto phone that does not have it already" \ + "@\"sqlite3.sis\", (0x2002af5f)" qtlibraries.pkg_postrules += sqlitedeployment qtlibraries.path = c:/sys/bin @@ -61,6 +59,7 @@ symbian: { contains(CONFIG, stl) { qtlibraries.pkg_prerules += "(0x2000F866), 1, 0, 0, {\"Standard C++ Library Common\"}" } + qtlibraries.pkg_prerules += "(0x2002af5f), 0, 5, 0, {\"sqlite3\"}" !contains(QT_CONFIG, no-jpeg): imageformats_plugins.sources += qjpeg.dll !contains(QT_CONFIG, no-gif): imageformats_plugins.sources += qgif.dll diff --git a/src/s60installs/sqlite3.sis b/src/s60installs/sqlite3.sis new file mode 100644 index 0000000..1785365 Binary files /dev/null and b/src/s60installs/sqlite3.sis differ -- cgit v0.12 From 785767e1f965a904765bab5dbfff1a21240dcc88 Mon Sep 17 00:00:00 2001 From: Pierre Rossi Date: Thu, 7 Jan 2010 20:15:14 +0100 Subject: Fix a painter warning when using a treewidget with animations in a splitter and the tree is collapsed, and then select an item in the tree that requires expanding, it might end up trying to paint to an invalid pixmap Reviewed-by: Gabi --- src/gui/itemviews/qtreeview.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index bcf9cfb..bf88a75 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -3064,6 +3064,8 @@ QPixmap QTreeViewPrivate::renderTreeToPixmapForAnimation(const QRect &rect) cons { Q_Q(const QTreeView); QPixmap pixmap(rect.size()); + if (rect.size().isEmpty()) + return pixmap; pixmap.fill(Qt::transparent); //the base might not be opaque, and we don't want uninitialized pixels. QPainter painter(&pixmap); painter.fillRect(QRect(QPoint(0,0), rect.size()), q->palette().base()); -- cgit v0.12 From 4378b168ad289e1acbde9580b750ce04b51260c3 Mon Sep 17 00:00:00 2001 From: Jani Hautakangas Date: Fri, 8 Jan 2010 09:54:48 +0200 Subject: Fix for QTBUG-5870 QGraphicsProxyWidget does not show children on Symbian. QS60PaintEngine returned wrong device in QPaintEngine::paintDevice(). Task-number: QTBUG-5870 Reviewed-by: Jason Barron --- src/gui/painting/qpaintengine_s60.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qpaintengine_s60.cpp b/src/gui/painting/qpaintengine_s60.cpp index 6f4f398..c5840f1 100644 --- a/src/gui/painting/qpaintengine_s60.cpp +++ b/src/gui/painting/qpaintengine_s60.cpp @@ -47,18 +47,25 @@ QT_BEGIN_NAMESPACE class QS60PaintEnginePrivate : public QRasterPaintEnginePrivate { public: - QS60PaintEnginePrivate(QS60PaintEngine *engine) { Q_UNUSED(engine); } + QS60PaintEnginePrivate() {} }; QS60PaintEngine::QS60PaintEngine(QPaintDevice *device, QS60PixmapData *data) - : QRasterPaintEngine(*(new QS60PaintEnginePrivate(this)), device), pixmapData(data) + : QRasterPaintEngine(*(new QS60PaintEnginePrivate), device), pixmapData(data) { } bool QS60PaintEngine::begin(QPaintDevice *device) { + Q_D(QS60PaintEngine); + pixmapData->beginDataAccess(); - return QRasterPaintEngine::begin(device); + bool ret = QRasterPaintEngine::begin(device); + // Make sure QPaintEngine::paintDevice() returns the proper device. + // QRasterPaintEngine changes pdev to QImage in case of RasterClass QPixmapData + // which is incorrect in Symbian. + d->pdev = device; + return ret; } bool QS60PaintEngine::end() -- cgit v0.12 From 1484008e831a6b18272babb17992c4de686da045 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Fri, 8 Jan 2010 10:57:43 +0100 Subject: Make sure the rect in QPixmap::copy() doesn't exceed the boundingRect. Task: http://bugreports.qt.nokia.com/browse/QTBUG-6303 Reviewed-by: Samuel --- src/gui/image/qpixmap.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 7e4597e..7b522f5 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -357,7 +357,9 @@ QPixmap QPixmap::copy(const QRect &rect) const if (isNull()) return QPixmap(); - const QRect r = rect.isEmpty() ? QRect(0, 0, width(), height()) : rect; + QRect r(0, 0, width(), height()); + if (!rect.isEmpty()) + r = r.intersected(rect); QPixmapData *d = data->createCompatiblePixmapData(); d->copy(data.data(), r); -- cgit v0.12 From 1f8fa41e78b4174ab64953dd80a1d562b0afc5aa Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 8 Jan 2010 12:30:43 +0200 Subject: Added mention of Symbian binary packages to INSTALL file Task-number: QTBUG-6162 Reviewed-by: TrustMe --- dist/README | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dist/README b/dist/README index e7dfb19..73c8be1 100644 --- a/dist/README +++ b/dist/README @@ -26,6 +26,10 @@ For Mac OS X Cocoa, the binary package requires Mac OS X 10.5 (Leopard) or later and GCC 4.0.1 to develop applications. Its applications will run on Mac OS X 10.5 and above. +If you want to install the precompiled binary package for Symbian, +follow these instructions: +http://qt.nokia.com/doc/%SHORTVERSION%/install-symbian-installer.html + DEMOS AND EXAMPLES -- cgit v0.12 From 32419380bdd11e7db401fd37a840e0ec4f5b6845 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 7 Jan 2010 17:46:16 +0000 Subject: Enable building with MSVC2008 Removed the alternate implementation of the registry reading, although the new API is simpler, the old XP method is not deprecated. Added an extra library that is needed according to API documentation, but is omittable on MinGW. Also gave a better error message when serial port detection fails. Reviewed-by: Miikka Heikkinen --- tools/runonphone/main.cpp | 4 ++++ tools/runonphone/runonphone.pro | 3 ++- tools/runonphone/serenum_win.cpp | 11 +---------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/tools/runonphone/main.cpp b/tools/runonphone/main.cpp index e2f6758..6081e67 100644 --- a/tools/runonphone/main.cpp +++ b/tools/runonphone/main.cpp @@ -155,6 +155,10 @@ int main(int argc, char *argv[]) serialPortName = id.portName; } } + if(serialPortName.isEmpty()) { + errstream << "No phone found, ensure USB cable is connected or specify manually with -p" << endl; + return 1; + } } QScopedPointer launcher; diff --git a/tools/runonphone/runonphone.pro b/tools/runonphone/runonphone.pro index d243121..cf0c055 100644 --- a/tools/runonphone/runonphone.pro +++ b/tools/runonphone/runonphone.pro @@ -15,5 +15,6 @@ HEADERS += trksignalhandler.h \ windows { SOURCES += serenum_win.cpp LIBS += -lsetupapi \ - -luuid + -luuid \ + -ladvapi32 } diff --git a/tools/runonphone/serenum_win.cpp b/tools/runonphone/serenum_win.cpp index ec11c3c..23e3862 100644 --- a/tools/runonphone/serenum_win.cpp +++ b/tools/runonphone/serenum_win.cpp @@ -77,8 +77,7 @@ QList enumerateSerialPorts() } HKEY key = SetupDiOpenDevRegKey(infoset, &info, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); if(key != INVALID_HANDLE_VALUE) { -#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600 - //RegGetValue not supported on XP, SHRegGetValue not supported by mingw :( + //RegGetValue not supported on XP, SHRegGetValue not supported by mingw, so use the old method of enumerating all the values for (DWORD dwi=0;;dwi++) { DWORD vsize = valueName.size(); if (ERROR_SUCCESS == RegEnumValue(key, dwi, (WCHAR*)(valueName.data()), &vsize, 0, 0, 0, &size)) { @@ -93,14 +92,6 @@ QList enumerateSerialPorts() break; } } -#else - if (ERROR_SUCCESS == SHRegGetValue(key, 0, "PortName", SRRF_RT_REG_SZ, 0, &size)) { - QByteArray ba(size, 0); - if (ERROR_SUCCESS == RegGetValue(key, 0, "PortName", SRRF_RT_REG_SZ, (BYTE*)(ba.data()), &size)) { - portName = QString((const QChar*)(ba.constData()), ba.size() / 2 - 1); - } - } -#endif RegCloseKey(key); } SerialPortId id; -- cgit v0.12 From bdef1a949ea32c5fe0bd2926171b813cff0cee2a Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Fri, 8 Jan 2010 12:30:14 +0100 Subject: Update changes file Task-number: QTBUG-6580 --- dist/changes-4.6.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dist/changes-4.6.1 b/dist/changes-4.6.1 index 2397228..145e09e 100644 --- a/dist/changes-4.6.1 +++ b/dist/changes-4.6.1 @@ -51,6 +51,8 @@ QtGui in the DDS, ETC1, PVRTC2, and PVRTC4 formats if the OpenGL graphics system is active and the appropriate extensions are present in the GL implementation. + - QGraphicsObject + * 'id' property was removed. Use the 'objectName' property instead. QtDBus ------ -- cgit v0.12 From bf4ed81813518abd9da23aec632a2d5ecc4d186d Mon Sep 17 00:00:00 2001 From: Stefano Pironato Date: Fri, 8 Jan 2010 14:22:50 +0200 Subject: Add texture glyph width cache default. For maemo6 need to increase the cache width to 1024 to avoid text corruption using SGX 1.4. Reviewed-by: Tom Cooksey Reviewed-by: Harald Fernengel --- src/gui/painting/qtextureglyphcache.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 46fbaa9..27dbcf9 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -47,6 +47,10 @@ #include "private/qnativeimage_p.h" #include "private/qfontengine_ft_p.h" +#ifndef QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH +#define QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH 256 +#endif + QT_BEGIN_NAMESPACE // #define CACHE_DEBUG @@ -112,7 +116,7 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti, rowHeight += margin * 2; if (isNull()) - createCache(256, rowHeight); + createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, rowHeight); // now actually use the coords and paint the wanted glyps into cache. QHash::iterator iter = listItemCoordinates.begin(); -- cgit v0.12 From cfc1020453de7dd93760a7e94ca6d8461e6dc203 Mon Sep 17 00:00:00 2001 From: Thomas Zander Date: Fri, 8 Jan 2010 13:14:09 +0100 Subject: Add new benchmark for some qtext features. I test loading some html into a qtextdocument and doing of shaping on an unformatted text of different scripts and bidiness. --- tests/benchmarks/benchmarks.pro | 1 + tests/benchmarks/qtext/bidi.txt | 4 ++ tests/benchmarks/qtext/main.cpp | 125 +++++++++++++++++++++++++++++++++++++++ tests/benchmarks/qtext/qtext.pro | 7 +++ 4 files changed, 137 insertions(+) create mode 100644 tests/benchmarks/qtext/bidi.txt create mode 100644 tests/benchmarks/qtext/main.cpp create mode 100644 tests/benchmarks/qtext/qtext.pro diff --git a/tests/benchmarks/benchmarks.pro b/tests/benchmarks/benchmarks.pro index 7bb4bb1..1c78f1f 100644 --- a/tests/benchmarks/benchmarks.pro +++ b/tests/benchmarks/benchmarks.pro @@ -8,6 +8,7 @@ SUBDIRS = containers-associative \ qhostinfo \ qpainter \ qtestlib-simple events \ + qtext \ qiodevice \ qpixmap \ blendbench \ diff --git a/tests/benchmarks/qtext/bidi.txt b/tests/benchmarks/qtext/bidi.txt new file mode 100644 index 0000000..7c74cb4 --- /dev/null +++ b/tests/benchmarks/qtext/bidi.txt @@ -0,0 +1,4 @@ +chinese +欧洲,软件+互联网 
 用统一码 (Unicode) 走遍世界
将于1997年 3 月10日-12日在德国 Mainz 市举行的第十届统一码国际研讨会现在开始注册。 本次会议将汇集各方面的专家。 涉及的领域包括: 国际互联网和统一码 ,国际化和本地化 ,统一码在操作系统和应用软件中的实现 ,字型 ,文本格式以及多文种计算等。 
当世界需要沟通时,请用Unicode! +hebrew-bidi +אײראָפּע: פּראָגראַמװאַרג און די װעלטנעץ: אוניקאָד איבער דער גאָרער װעלט פֿאַרשרײַבט זיך שױן אױף דער צענטער אינטערנאַציאָנאַלער אוניקאָד-קאָנפֿערענץ, װאָס װעט פֿאָרקומען דעם 10טן ביזן 12טן מאַרץ, 1997, אין מײַנץ, דײַטשלאַנד. די קאָנפֿערענץ װעט צוזאַמענברענגן מבֿינים פֿון װעלטנעץ, אוניקאָד, אי אַלװעלטלעכן אי סבֿיבֿהדיקן פּראָגראַמװאַרג, אַרײַנשטעלן אוניקאָד אין אָפּעריר-סיסטעמען און אָנװענדונגען, שריפֿטן, טעקסט-אױסשטעל, און מערשפּראַכיקע קאָמפּיוטערײַ. diff --git a/tests/benchmarks/qtext/main.cpp b/tests/benchmarks/qtext/main.cpp new file mode 100644 index 0000000..3c973b6 --- /dev/null +++ b/tests/benchmarks/qtext/main.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +class tst_QText: public QObject +{ + Q_OBJECT +private slots: + void loadHtml_data(); + void loadHtml(); + + void shaping_data(); + void shaping(); +}; + +void tst_QText::loadHtml_data() +{ + QTest::addColumn("source"); + QTest::newRow("empty") << QString(); + QTest::newRow("simple") << QString::fromLatin1("Foo"); + QTest::newRow("simple2") << QString::fromLatin1("Foo"); + + QString parag = QString::fromLatin1("

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.

"); + QString header = QString::fromLatin1("test"); + QTest::newRow("long") << QString::fromLatin1("test") + parag + parag + parag + + parag + parag + parag + parag + parag + parag + parag + parag + parag + parag + parag + parag + parag + parag + + QString::fromLatin1(""); + QTest::newRow("table") << header + QLatin1String("
xx
") + + parag + QLatin1String("
xx") + + parag; +} + +void tst_QText::loadHtml() +{ + QFETCH(QString, source); + QTextDocument doc; + QBENCHMARK { + doc.setHtml(source); + } +} + +void tst_QText::shaping_data() +{ + QTest::addColumn("parag"); + QTest::newRow("empty") << QString(); + QTest::newRow("lorem") << QString::fromLatin1("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi."); + QTest::newRow("short") << QString::fromLatin1("Lorem ipsum dolor sit amet"); + + QFile file(QString::fromLatin1(SRCDIR) + QLatin1String("/bidi.txt")); + QVERIFY(file.open(QFile::ReadOnly)); + QByteArray data = file.readAll(); + QVERIFY(data.count() > 1000); + QStringList list = QString::fromUtf8(data.data()).split(QLatin1Char('\n'), QString::SkipEmptyParts); + QVERIFY(list.count() %2 == 0); // even amount as we have title and then content. + for (int i=0; i < list.count(); i+=2) { + QTest::newRow(list.at(i).toLatin1()) << list.at(i+1); + } +} + +void tst_QText::shaping() +{ + QFETCH(QString, parag); + + QTextLayout lay(parag); + lay.setCacheEnabled(false); + + // do one run to make sure any fonts are loaded. + lay.beginLayout(); + lay.createLine(); + lay.endLayout(); + + QBENCHMARK { + lay.beginLayout(); + lay.createLine(); + lay.endLayout(); + } +} + +QTEST_MAIN(tst_QText) + +#include "main.moc" diff --git a/tests/benchmarks/qtext/qtext.pro b/tests/benchmarks/qtext/qtext.pro new file mode 100644 index 0000000..ce4f604 --- /dev/null +++ b/tests/benchmarks/qtext/qtext.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_QText + +SOURCES += main.cpp + +DEFINES += SRCDIR=\\\"$$PWD/\\\" -- cgit v0.12 From 583b3f55ad12846a25598cb0b9442294cabafd96 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 8 Jan 2010 11:22:14 +0100 Subject: Fix passing of arguments to syncqt Escape the arguments variable properly. Reviewed-by: Thiago --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 612a3da..81872f9 100755 --- a/configure +++ b/configure @@ -2257,7 +2257,7 @@ if [ "$OPT_SHADOW" = "yes" ]; then mkdir -p "$outpath/bin" echo "#!/bin/sh" >"$outpath/bin/syncqt" echo "QTDIR=\"$relpath\"; export QTDIR" >>"$outpath/bin/syncqt" - echo "perl \"$relpath/bin/syncqt\" -outdir \"$outpath\" $*" >>"$outpath/bin/syncqt" + echo "perl \"$relpath/bin/syncqt\" -outdir \"$outpath\" \"\$@\"" >>"$outpath/bin/syncqt" chmod 755 "$outpath/bin/syncqt" fi -- cgit v0.12 From 5f27c542e3d471427e77f1ab6a4a689a8ad2f813 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Fri, 8 Jan 2010 12:44:00 +0100 Subject: added CONFIG += console to qlalr.pro Otherwise we don't see any console output on Windows. Reviewed-by: Roberto Raggi --- util/qlalr/qlalr.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/util/qlalr/qlalr.pro b/util/qlalr/qlalr.pro index 881a36a..1994a73 100644 --- a/util/qlalr/qlalr.pro +++ b/util/qlalr/qlalr.pro @@ -1,6 +1,7 @@ TEMPLATE = app QT = core +CONFIG += console TARGET = qlalr mac:CONFIG -= app_bundle -- cgit v0.12 From 7fb78e7f60ea72e9e471d6cbc4403d490581df17 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 8 Jan 2010 15:10:31 +0100 Subject: Added new functions to QTextCodec that accept ConversionFlags. In some cases the user might want to pass initial conversion flags that should be used by the QTextEncoder and QTextDecoder, so added convenience QTextCodec::makeDecoder and makeEncoder functions that accept those flags as an argument. Task-number: QTBUG-7180 Reviewed-by: Thiago --- src/corelib/codecs/qtextcodec.cpp | 49 +++++++++++++++++++++++++++++++++++++++ src/corelib/codecs/qtextcodec.h | 11 ++++++--- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index 698ca9e..86845c7 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -1163,6 +1163,19 @@ QTextDecoder* QTextCodec::makeDecoder() const return new QTextDecoder(this); } +/*! + Creates a QTextDecoder with a specified \a flags to decode chunks + of \c{char *} data to create chunks of Unicode data. + + The caller is responsible for deleting the returned object. + + \since 4.7 +*/ +QTextDecoder* QTextCodec::makeDecoder(QTextCodec::ConversionFlags flags) const +{ + return new QTextDecoder(this, flags); +} + /*! Creates a QTextEncoder which stores enough state to encode chunks @@ -1176,6 +1189,19 @@ QTextEncoder* QTextCodec::makeEncoder() const } /*! + Creates a QTextEncoder with a specified \a flags to encode chunks + of Unicode data as \c{char *} data. + + The caller is responsible for deleting the returned object. + + \since 4.7 +*/ +QTextEncoder* QTextCodec::makeEncoder(QTextCodec::ConversionFlags flags) const +{ + return new QTextEncoder(this, flags); +} + +/*! \fn QByteArray QTextCodec::fromUnicode(const QChar *input, int number, ConverterState *state) const @@ -1316,6 +1342,17 @@ QString QTextCodec::toUnicode(const char *chars) const */ /*! + Constructs a text encoder for the given \a codec and conversion \a flags. + + \since 4.7 +*/ +QTextEncoder::QTextEncoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags) + : c(codec), state() +{ + state.flags = flags; +} + +/*! Destroys the encoder. */ QTextEncoder::~QTextEncoder() @@ -1392,6 +1429,18 @@ QByteArray QTextEncoder::fromUnicode(const QString& uc, int& lenInOut) */ /*! + Constructs a text decoder for the given \a codec and conversion \a flags. + + \since 4.7 +*/ + +QTextDecoder::QTextDecoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags) + : c(codec), state() +{ + state.flags = flags; +} + +/*! Destroys the decoder. */ QTextDecoder::~QTextDecoder() diff --git a/src/corelib/codecs/qtextcodec.h b/src/corelib/codecs/qtextcodec.h index a099dd9..5012b42 100644 --- a/src/corelib/codecs/qtextcodec.h +++ b/src/corelib/codecs/qtextcodec.h @@ -85,9 +85,6 @@ public: static QTextCodec *codecForUtfText(const QByteArray &ba); static QTextCodec *codecForUtfText(const QByteArray &ba, QTextCodec *defaultCodec); - QTextDecoder* makeDecoder() const; - QTextEncoder* makeEncoder() const; - bool canEncode(QChar) const; bool canEncode(const QString&) const; @@ -120,6 +117,12 @@ public: QByteArray fromUnicode(const QChar *in, int length, ConverterState *state = 0) const { return convertFromUnicode(in, length, state); } + // ### Qt 5: merge these functions. + QTextDecoder* makeDecoder() const; + QTextDecoder* makeDecoder(ConversionFlags flags) const; + QTextEncoder* makeEncoder() const; + QTextEncoder* makeEncoder(ConversionFlags flags) const; + virtual QByteArray name() const = 0; virtual QList aliases() const; virtual int mibEnum() const = 0; @@ -157,6 +160,7 @@ class Q_CORE_EXPORT QTextEncoder { Q_DISABLE_COPY(QTextEncoder) public: explicit QTextEncoder(const QTextCodec *codec) : c(codec), state() {} + QTextEncoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags); ~QTextEncoder(); QByteArray fromUnicode(const QString& str); QByteArray fromUnicode(const QChar *uc, int len); @@ -178,6 +182,7 @@ class Q_CORE_EXPORT QTextDecoder { Q_DISABLE_COPY(QTextDecoder) public: explicit QTextDecoder(const QTextCodec *codec) : c(codec), state() {} + QTextDecoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags); ~QTextDecoder(); QString toUnicode(const char* chars, int len); QString toUnicode(const QByteArray &ba); -- cgit v0.12 From fdac6df6d46e6d4f00763365de5a4437ad06ba39 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 8 Jan 2010 15:15:16 +0100 Subject: Use the new QTextCodec api in the QXmlStreamWriter. Instead of accesing private data, use the QTextCodec::makeEncoder() to pass the initial conversion flags to the codec. Also improved the behavior - we shouldn't add BOM in the middle of the data when dumping xml in all encodings, not only for utf8. Task-number: QTBUG-7180 Reviewed-by: Thiago --- src/corelib/codecs/qtextcodec.h | 5 ----- src/corelib/xml/qxmlstream.cpp | 7 ++----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/corelib/codecs/qtextcodec.h b/src/corelib/codecs/qtextcodec.h index 5012b42..e37527d 100644 --- a/src/corelib/codecs/qtextcodec.h +++ b/src/corelib/codecs/qtextcodec.h @@ -171,11 +171,6 @@ public: private: const QTextCodec *c; QTextCodec::ConverterState state; - - friend class QXmlStreamWriter; - friend class QXmlStreamWriterPrivate; - friend class QCoreXmlStreamWriter; - friend class QCoreXmlStreamWriterPrivate; }; class Q_CORE_EXPORT QTextDecoder { diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 5717ca2..1bf00b8 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -3003,8 +3003,7 @@ QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q) deleteDevice = false; #ifndef QT_NO_TEXTCODEC codec = QTextCodec::codecForMib(106); // utf8 - encoder = codec->makeEncoder(); - encoder->state.flags |= QTextCodec::IgnoreHeader; // no byte order mark for utf8 + encoder = codec->makeEncoder(QTextCodec::IgnoreHeader); // no byte order mark for utf8 #endif inStartElement = inEmptyElement = false; wroteSomething = false; @@ -3278,9 +3277,7 @@ void QXmlStreamWriter::setCodec(QTextCodec *codec) if (codec) { d->codec = codec; delete d->encoder; - d->encoder = codec->makeEncoder(); - if (codec->mibEnum() == 106) - d->encoder->state.flags |= QTextCodec::IgnoreHeader; // no byte order mark for utf8 + d->encoder = codec->makeEncoder(QTextCodec::IgnoreHeader); // no byte order mark for utf8 } } -- cgit v0.12 From 3b62b3384e0008ab1dba210f55b70d666924d06e Mon Sep 17 00:00:00 2001 From: axis Date: Thu, 7 Jan 2010 14:45:59 +0100 Subject: Fixed a doc error. The extra line would make qdoc treat the next text as a separate paragraph, but it should be part of the description for the previous value. --- src/corelib/global/qnamespace.qdoc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 7ee7a76..70ca507 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -134,7 +134,6 @@ \value AA_DontShowIconsInMenus Actions with the Icon property won't be shown in any menus unless specifically set by the QAction::iconVisibleInMenu property. - Menus that are currently open or menus already created in the native Mac OS X menubar \e{may not} pick up a change in this attribute. Changes in the QAction::iconVisibleInMenu property will always be picked up. -- cgit v0.12 From 07b484b7c4685cfc2187be840a01e15f0fe08ff5 Mon Sep 17 00:00:00 2001 From: axis Date: Fri, 8 Jan 2010 15:50:03 +0100 Subject: Fixed QDesktopWidget autotest. The error would happen because Qt would attempt to do focus handling on the desktop widget which eventually resulted in an assert on the Created status of the widget. RevBy: Jani Hautakangas AutoTest: Passed --- src/gui/kernel/qapplication_s60.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 27f2644..aee4324 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -930,7 +930,7 @@ void QSymbianControl::PositionChanged() void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */) { - if (m_ignoreFocusChanged) + if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop) return; // Popups never get focused, but still receive the FocusChanged when they are hidden. -- cgit v0.12 From 4a84b272459160780529f654e6aee3abf8569b51 Mon Sep 17 00:00:00 2001 From: axis Date: Thu, 7 Jan 2010 16:01:58 +0100 Subject: Added a flag to avoid construction of application panes. This is purely an optimization for fullscreen-only apps. Task: QTBUG-6098 RevBy: Jason Barron RevBy: mread AutoTest: Included --- src/corelib/global/qnamespace.h | 1 + src/corelib/global/qnamespace.qdoc | 6 ++ src/gui/dialogs/qdialog.cpp | 9 ++- src/gui/kernel/qsoftkeymanager.cpp | 3 +- src/gui/s60framework/qs60mainappui.cpp | 12 +++- tests/auto/qapplication/heart.svg | 55 +++++++++++++++++ tests/auto/qapplication/test/test.pro | 4 +- tests/auto/qapplication/tst_qapplication.cpp | 88 ++++++++++++++++++++++++++++ 8 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 tests/auto/qapplication/heart.svg diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 0ee9cd2..c40308c 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -511,6 +511,7 @@ public: AA_MacPluginApplication = 5, AA_DontUseNativeMenuBar = 6, AA_MacDontSwapCtrlAndMeta = 7, + AA_S60DontConstructApplicationPanes = 8, // Add new attributes before this line AA_AttributeCount diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 70ca507..5a80d56 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -163,6 +163,12 @@ Command+C on the keyboard regardless of the value set, though what is output for QKeySequence::toString(QKeySequence::PortableText) will be different). + \value AA_S60DontConstructApplicationPanes Stops Qt from initializing the S60 status + pane and softkey pane on Symbian. This is useful to save memory and reduce + startup time for applications that will run in fullscreen mode during their + whole lifetime. This attribute must be set before QApplication is + constructed. + \omitvalue AA_AttributeCount */ diff --git a/src/gui/dialogs/qdialog.cpp b/src/gui/dialogs/qdialog.cpp index ed2d676..d7653e5 100644 --- a/src/gui/dialogs/qdialog.cpp +++ b/src/gui/dialogs/qdialog.cpp @@ -888,7 +888,14 @@ bool QDialog::s60AdjustedPosition() if (doS60Positioning) { // naive way to deduce screen orientation if (S60->screenHeightInPixels > S60->screenWidthInPixels) { - p.setY(S60->screenHeightInPixels-height()-qt_TSize2QSize(S60->buttonGroupContainer()->Size()).height()); + int cbaHeight; + const CEikButtonGroupContainer* bgContainer = S60->buttonGroupContainer(); + if (!bgContainer) { + cbaHeight = 0; + } else { + cbaHeight = qt_TSize2QSize(bgContainer->Size()).height(); + } + p.setY(S60->screenHeightInPixels-height()-cbaHeight); p.setX(0); } else { const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent); diff --git a/src/gui/kernel/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp index 0e98f39..b09ab8f 100644 --- a/src/gui/kernel/qsoftkeymanager.cpp +++ b/src/gui/kernel/qsoftkeymanager.cpp @@ -211,7 +211,8 @@ bool QSoftKeyManager::event(QEvent *e) void QSoftKeyManagerPrivate::updateSoftKeys_sys(const QList &softkeys) { // lets not update softkeys if s60 native dialog or menu is shown - if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog()) + if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes) + || CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog()) return; CEikButtonGroupContainer* nativeContainer = S60->buttonGroupContainer(); diff --git a/src/gui/s60framework/qs60mainappui.cpp b/src/gui/s60framework/qs60mainappui.cpp index 4c4c994..4813fb2 100644 --- a/src/gui/s60framework/qs60mainappui.cpp +++ b/src/gui/s60framework/qs60mainappui.cpp @@ -104,10 +104,16 @@ void QS60MainAppUi::ConstructL() // ENoAppResourceFile and ENonStandardResourceFile makes UI to work without // resource files in most SDKs. S60 3rd FP1 public seems to require resource file // even these flags are defined - BaseConstructL(CAknAppUi::EAknEnableSkin); + TInt flags = CAknAppUi::EAknEnableSkin; + if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)) { + flags |= CAknAppUi::ENoScreenFurniture | CAknAppUi::ENonStandardResourceFile; + } + BaseConstructL(flags); - CEikButtonGroupContainer* nativeContainer = Cba(); - nativeContainer->SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY_WITH_IDS); + if (!QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)) { + CEikButtonGroupContainer* nativeContainer = Cba(); + nativeContainer->SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY_WITH_IDS); + } } /*! diff --git a/tests/auto/qapplication/heart.svg b/tests/auto/qapplication/heart.svg new file mode 100644 index 0000000..8c982cd --- /dev/null +++ b/tests/auto/qapplication/heart.svg @@ -0,0 +1,55 @@ + + + + + +Heart Left-Highlight +This is a normal valentines day heart. + + +holiday +valentines + +valentine +hash(0x8a091c0) +hash(0x8a0916c) +signs_and_symbols +hash(0x8a091f0) +day + + + + +Jon Phillips + + + + +Jon Phillips + + + + +Jon Phillips + + + +image/svg+xml + + +en + + + + + + + + + + + + + + + diff --git a/tests/auto/qapplication/test/test.pro b/tests/auto/qapplication/test/test.pro index 7c3de3c..e68af26 100644 --- a/tests/auto/qapplication/test/test.pro +++ b/tests/auto/qapplication/test/test.pro @@ -16,7 +16,9 @@ symbian*: { additional.path = desktopsettingsaware someTest.sources = test.pro someTest.path = test - DEPLOYMENT = additional deploy someTest + windowIcon.sources = ../heart.svg + DEPLOYMENT = additional deploy someTest windowIcon + LIBS += -lcone -lavkon } win32 { diff --git a/tests/auto/qapplication/tst_qapplication.cpp b/tests/auto/qapplication/tst_qapplication.cpp index 5888866..ed614e15 100644 --- a/tests/auto/qapplication/tst_qapplication.cpp +++ b/tests/auto/qapplication/tst_qapplication.cpp @@ -53,6 +53,9 @@ #ifdef Q_OS_WINCE #include #endif +#ifdef Q_OS_SYMBIAN +#include +#endif //TESTED_CLASS= //TESTED_FILES= @@ -138,6 +141,8 @@ private slots: void touchEventPropagation(); + void symbianNoApplicationPanes(); + void symbianNeedForTraps(); void symbianLeaveThroughMain(); }; @@ -2036,6 +2041,89 @@ void tst_QApplication::touchEventPropagation() } } +void tst_QApplication::symbianNoApplicationPanes() +{ +#ifndef Q_OS_SYMBIAN + QSKIP("This is a Symbian only test", SkipAll); +#else + QApplication::setAttribute(Qt::AA_S60DontConstructApplicationPanes); + + // Run in a block so that QApplication is destroyed before resetting the attribute. + { + // Actually I wasn't able to get the forced orientation change to work properly, + // but I'll leave the code here for the future in case we manage to test that + // later. If someone knows how to force an orientation switch in an autotest, do + // feel free to fix this testcase. + int argc = 0; + QApplication app(argc, 0); + QWidget *w; + + w = new QWidget; + w->show(); + QT_TRAP_THROWING(static_cast(CCoeEnv::Static()->AppUi()) + ->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape)); + app.processEvents(); + delete w; + + w = new QWidget; + w->show(); + QT_TRAP_THROWING(static_cast(CCoeEnv::Static()->AppUi()) + ->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait)); + app.processEvents(); + delete w; + + w = new QWidget; + w->showMaximized(); + QT_TRAP_THROWING(static_cast(CCoeEnv::Static()->AppUi()) + ->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape)); + app.processEvents(); + delete w; + + w = new QWidget; + w->showMaximized(); + QT_TRAP_THROWING(static_cast(CCoeEnv::Static()->AppUi()) + ->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait)); + app.processEvents(); + delete w; + + w = new QWidget; + w->showFullScreen(); + QT_TRAP_THROWING(static_cast(CCoeEnv::Static()->AppUi()) + ->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape)); + app.processEvents(); + delete w; + + w = new QWidget; + w->showFullScreen(); + QT_TRAP_THROWING(static_cast(CCoeEnv::Static()->AppUi()) + ->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait)); + app.processEvents(); + delete w; + + // These will have no effect, since there is no status pane, but they shouldn't + // crash either. + w = new QWidget; + w->show(); + w->setWindowTitle("Testing title"); + app.processEvents(); + delete w; + + w = new QWidget; + w->show(); + w->setWindowIcon(QIcon(QPixmap("heart.svg"))); + app.processEvents(); + delete w; + + QDesktopWidget desktop; + QCOMPARE(desktop.availableGeometry(), desktop.screenGeometry()); + } + + QApplication::setAttribute(Qt::AA_S60DontConstructApplicationPanes, false); + + // No other error condition. Program will crash if unsuccessful. +#endif +} + #ifdef Q_OS_SYMBIAN class CBaseDummy : public CBase { -- cgit v0.12 From f0d2a0d7a9ed0500a1423bbf1362b234525f8be7 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 8 Jan 2010 16:13:28 +0100 Subject: Reverted two commits that were pushed to the wrong branch. Revert "Use the new QTextCodec api in the QXmlStreamWriter." This reverts commit fdac6df6d46e6d4f00763365de5a4437ad06ba39. Revert "Added new functions to QTextCodec that accept ConversionFlags." This reverts commit 7fb78e7f60ea72e9e471d6cbc4403d490581df17. --- src/corelib/codecs/qtextcodec.cpp | 49 --------------------------------------- src/corelib/codecs/qtextcodec.h | 16 ++++++------- src/corelib/xml/qxmlstream.cpp | 7 ++++-- 3 files changed, 13 insertions(+), 59 deletions(-) diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index 86845c7..698ca9e 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -1163,19 +1163,6 @@ QTextDecoder* QTextCodec::makeDecoder() const return new QTextDecoder(this); } -/*! - Creates a QTextDecoder with a specified \a flags to decode chunks - of \c{char *} data to create chunks of Unicode data. - - The caller is responsible for deleting the returned object. - - \since 4.7 -*/ -QTextDecoder* QTextCodec::makeDecoder(QTextCodec::ConversionFlags flags) const -{ - return new QTextDecoder(this, flags); -} - /*! Creates a QTextEncoder which stores enough state to encode chunks @@ -1189,19 +1176,6 @@ QTextEncoder* QTextCodec::makeEncoder() const } /*! - Creates a QTextEncoder with a specified \a flags to encode chunks - of Unicode data as \c{char *} data. - - The caller is responsible for deleting the returned object. - - \since 4.7 -*/ -QTextEncoder* QTextCodec::makeEncoder(QTextCodec::ConversionFlags flags) const -{ - return new QTextEncoder(this, flags); -} - -/*! \fn QByteArray QTextCodec::fromUnicode(const QChar *input, int number, ConverterState *state) const @@ -1342,17 +1316,6 @@ QString QTextCodec::toUnicode(const char *chars) const */ /*! - Constructs a text encoder for the given \a codec and conversion \a flags. - - \since 4.7 -*/ -QTextEncoder::QTextEncoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags) - : c(codec), state() -{ - state.flags = flags; -} - -/*! Destroys the encoder. */ QTextEncoder::~QTextEncoder() @@ -1429,18 +1392,6 @@ QByteArray QTextEncoder::fromUnicode(const QString& uc, int& lenInOut) */ /*! - Constructs a text decoder for the given \a codec and conversion \a flags. - - \since 4.7 -*/ - -QTextDecoder::QTextDecoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags) - : c(codec), state() -{ - state.flags = flags; -} - -/*! Destroys the decoder. */ QTextDecoder::~QTextDecoder() diff --git a/src/corelib/codecs/qtextcodec.h b/src/corelib/codecs/qtextcodec.h index e37527d..a099dd9 100644 --- a/src/corelib/codecs/qtextcodec.h +++ b/src/corelib/codecs/qtextcodec.h @@ -85,6 +85,9 @@ public: static QTextCodec *codecForUtfText(const QByteArray &ba); static QTextCodec *codecForUtfText(const QByteArray &ba, QTextCodec *defaultCodec); + QTextDecoder* makeDecoder() const; + QTextEncoder* makeEncoder() const; + bool canEncode(QChar) const; bool canEncode(const QString&) const; @@ -117,12 +120,6 @@ public: QByteArray fromUnicode(const QChar *in, int length, ConverterState *state = 0) const { return convertFromUnicode(in, length, state); } - // ### Qt 5: merge these functions. - QTextDecoder* makeDecoder() const; - QTextDecoder* makeDecoder(ConversionFlags flags) const; - QTextEncoder* makeEncoder() const; - QTextEncoder* makeEncoder(ConversionFlags flags) const; - virtual QByteArray name() const = 0; virtual QList aliases() const; virtual int mibEnum() const = 0; @@ -160,7 +157,6 @@ class Q_CORE_EXPORT QTextEncoder { Q_DISABLE_COPY(QTextEncoder) public: explicit QTextEncoder(const QTextCodec *codec) : c(codec), state() {} - QTextEncoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags); ~QTextEncoder(); QByteArray fromUnicode(const QString& str); QByteArray fromUnicode(const QChar *uc, int len); @@ -171,13 +167,17 @@ public: private: const QTextCodec *c; QTextCodec::ConverterState state; + + friend class QXmlStreamWriter; + friend class QXmlStreamWriterPrivate; + friend class QCoreXmlStreamWriter; + friend class QCoreXmlStreamWriterPrivate; }; class Q_CORE_EXPORT QTextDecoder { Q_DISABLE_COPY(QTextDecoder) public: explicit QTextDecoder(const QTextCodec *codec) : c(codec), state() {} - QTextDecoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags); ~QTextDecoder(); QString toUnicode(const char* chars, int len); QString toUnicode(const QByteArray &ba); diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 1bf00b8..5717ca2 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -3003,7 +3003,8 @@ QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q) deleteDevice = false; #ifndef QT_NO_TEXTCODEC codec = QTextCodec::codecForMib(106); // utf8 - encoder = codec->makeEncoder(QTextCodec::IgnoreHeader); // no byte order mark for utf8 + encoder = codec->makeEncoder(); + encoder->state.flags |= QTextCodec::IgnoreHeader; // no byte order mark for utf8 #endif inStartElement = inEmptyElement = false; wroteSomething = false; @@ -3277,7 +3278,9 @@ void QXmlStreamWriter::setCodec(QTextCodec *codec) if (codec) { d->codec = codec; delete d->encoder; - d->encoder = codec->makeEncoder(QTextCodec::IgnoreHeader); // no byte order mark for utf8 + d->encoder = codec->makeEncoder(); + if (codec->mibEnum() == 106) + d->encoder->state.flags |= QTextCodec::IgnoreHeader; // no byte order mark for utf8 } } -- cgit v0.12 From a3e6a04448979aaa6ada7aa434de3137f6cf0563 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Fri, 8 Jan 2010 15:07:36 +0000 Subject: Fixed build breakage on S60 3.1 due to audio effects changes Removed calls to the video overload of the audio effect constructors, e.g. CAudioEqualizer::NewL(VideoPlayerUtility&) Task-number: QTBUG-7223 Reviewed-by: trustme --- src/3rdparty/phonon/mmf/abstractaudioeffect.cpp | 11 +++-------- src/3rdparty/phonon/mmf/abstractaudioeffect.h | 1 - src/3rdparty/phonon/mmf/audioequalizer.cpp | 20 +++++++------------- src/3rdparty/phonon/mmf/audioequalizer.h | 1 - src/3rdparty/phonon/mmf/bassboost.cpp | 7 ------- src/3rdparty/phonon/mmf/bassboost.h | 1 - 6 files changed, 10 insertions(+), 31 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp index 8c73027..e7ef9b2 100644 --- a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp +++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp @@ -80,15 +80,10 @@ void AbstractAudioEffect::connectMediaObject(MediaObject *mediaObject) if (AudioPlayer *audioPlayer = qobject_cast(player)) { connectAudioPlayer(audioPlayer->nativePlayer()); - } else { - VideoPlayer *videoPlayer = qobject_cast(player); - Q_ASSERT_X(videoPlayer, Q_FUNC_INFO, "Player type not recognised"); - connectVideoPlayer(videoPlayer->nativePlayer()); + applyParameters(); + // TODO: handle audio effect errors + TRAP_IGNORE(m_effect->EnableL()); } - - applyParameters(); - // TODO: handle audio effect errors - TRAP_IGNORE(m_effect->EnableL()); } } diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.h b/src/3rdparty/phonon/mmf/abstractaudioeffect.h index 10578af..6f74a73 100644 --- a/src/3rdparty/phonon/mmf/abstractaudioeffect.h +++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.h @@ -86,7 +86,6 @@ protected: void disconnectMediaObject(MediaObject *mediaObject); virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player) = 0; - virtual void connectVideoPlayer(VideoPlayer::NativePlayer *player) = 0; virtual void applyParameters() = 0; virtual void parameterChanged(const int id, diff --git a/src/3rdparty/phonon/mmf/audioequalizer.cpp b/src/3rdparty/phonon/mmf/audioequalizer.cpp index 51f1c32..c2936c5 100644 --- a/src/3rdparty/phonon/mmf/audioequalizer.cpp +++ b/src/3rdparty/phonon/mmf/audioequalizer.cpp @@ -49,21 +49,15 @@ void AudioEqualizer::connectAudioPlayer(AudioPlayer::NativePlayer *player) m_effect.reset(ptr); } -void AudioEqualizer::connectVideoPlayer(VideoPlayer::NativePlayer *player) -{ - CAudioEqualizer *ptr = 0; - QT_TRAP_THROWING(ptr = CAudioEqualizer::NewL(*player)); - m_effect.reset(ptr); -} - void AudioEqualizer::applyParameters() { - Q_ASSERT_X(m_effect.data(), Q_FUNC_INFO, "Effect not created"); - EffectParameter param; - foreach (param, parameters()) { - const int band = param.id(); - const int level = parameterValue(param).toInt(); - setBandLevel(band, level); + if (m_effect.data()) { + EffectParameter param; + foreach (param, parameters()) { + const int band = param.id(); + const int level = parameterValue(param).toInt(); + setBandLevel(band, level); + } } } diff --git a/src/3rdparty/phonon/mmf/audioequalizer.h b/src/3rdparty/phonon/mmf/audioequalizer.h index 9910ea4..10fe9ad 100644 --- a/src/3rdparty/phonon/mmf/audioequalizer.h +++ b/src/3rdparty/phonon/mmf/audioequalizer.h @@ -44,7 +44,6 @@ public: protected: // AbstractAudioEffect virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player); - virtual void connectVideoPlayer(VideoPlayer::NativePlayer *player); virtual void applyParameters(); virtual void parameterChanged(const int id, const QVariant &value); diff --git a/src/3rdparty/phonon/mmf/bassboost.cpp b/src/3rdparty/phonon/mmf/bassboost.cpp index 36069fb..ae96b45 100644 --- a/src/3rdparty/phonon/mmf/bassboost.cpp +++ b/src/3rdparty/phonon/mmf/bassboost.cpp @@ -46,13 +46,6 @@ void BassBoost::connectAudioPlayer(AudioPlayer::NativePlayer *player) m_effect.reset(ptr); } -void BassBoost::connectVideoPlayer(VideoPlayer::NativePlayer *player) -{ - CBassBoost *ptr = 0; - QT_TRAP_THROWING(ptr = CBassBoost::NewL(*player)); - m_effect.reset(ptr); -} - void BassBoost::applyParameters() { // No parameters to apply diff --git a/src/3rdparty/phonon/mmf/bassboost.h b/src/3rdparty/phonon/mmf/bassboost.h index 1b893db..4ad0a6c 100644 --- a/src/3rdparty/phonon/mmf/bassboost.h +++ b/src/3rdparty/phonon/mmf/bassboost.h @@ -42,7 +42,6 @@ public: protected: // AbstractAudioEffect virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player); - virtual void connectVideoPlayer(VideoPlayer::NativePlayer *player); virtual void applyParameters(); virtual void parameterChanged(const int id, const QVariant &value); -- cgit v0.12 From 48cce37f6faa2aae9b15edc9543f0e7e08236bb1 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 8 Jan 2010 17:59:22 +0100 Subject: Doc: the QTextDecoder need to be destroyed, reflect that in the example Reviewed-by: Denis --- doc/src/snippets/code/src_corelib_codecs_qtextcodec.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/snippets/code/src_corelib_codecs_qtextcodec.cpp b/doc/src/snippets/code/src_corelib_codecs_qtextcodec.cpp index 4e77e04..2fd723e 100644 --- a/doc/src/snippets/code/src_corelib_codecs_qtextcodec.cpp +++ b/doc/src/snippets/code/src_corelib_codecs_qtextcodec.cpp @@ -62,6 +62,7 @@ while (new_data_available()) { QByteArray chunk = get_new_data(); string += decoder->toUnicode(chunk); } +delete decoder; //! [2] -- cgit v0.12 From 9a820c4219c67aa401f0ac99d7bcc966c249d637 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 11 Jan 2010 10:26:34 +0100 Subject: Fix regression introduced in e49aee9f: set If-Modified-Since. I moved the code above the other tests because it's more complex. But, of course, that's wrong because it returns without setting the necessary headers. Reviewed-by: Peter Hartmann --- src/network/access/qnetworkaccesshttpbackend.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index 12b10f9..5a2cce4 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -385,6 +385,14 @@ void QNetworkAccessHttpBackend::validateCache(QHttpNetworkRequest &httpRequest, QNetworkHeadersPrivate::RawHeadersList::ConstIterator it; cacheHeaders.setAllRawHeaders(metaData.rawHeaders()); + it = cacheHeaders.findRawHeader("etag"); + if (it != cacheHeaders.rawHeaders.constEnd()) + httpRequest.setHeaderField("If-None-Match", it->second); + + QDateTime lastModified = metaData.lastModified(); + if (lastModified.isValid()) + httpRequest.setHeaderField("If-Modified-Since", QNetworkHeadersPrivate::toHttpDate(lastModified)); + if (CacheLoadControlAttribute == QNetworkRequest::PreferNetwork) { it = cacheHeaders.findRawHeader("Cache-Control"); if (it != cacheHeaders.rawHeaders.constEnd()) { @@ -394,14 +402,6 @@ void QNetworkAccessHttpBackend::validateCache(QHttpNetworkRequest &httpRequest, } } - it = cacheHeaders.findRawHeader("etag"); - if (it != cacheHeaders.rawHeaders.constEnd()) - httpRequest.setHeaderField("If-None-Match", it->second); - - QDateTime lastModified = metaData.lastModified(); - if (lastModified.isValid()) - httpRequest.setHeaderField("If-Modified-Since", QNetworkHeadersPrivate::toHttpDate(lastModified)); - QDateTime currentDateTime = QDateTime::currentDateTime(); QDateTime expirationDate = metaData.expirationDate(); -- cgit v0.12 From ef5a985cf47c32bac0ddd3bae1edb7e922e7ec69 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 11 Jan 2010 10:27:48 +0100 Subject: Autotest: the cache code no longer returns expired pages. Returning expired changes is wrong. The documentation says we never do that. Now we really never return expired pages. Reviewed-by: Peter Hartmann --- tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp b/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp index 7fd994d..e5646c1 100644 --- a/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp +++ b/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp @@ -136,7 +136,7 @@ void tst_QAbstractNetworkCache::expires_data() QTest::newRow("200-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_expires200.cgi" << AlwaysFalse; QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_expires200.cgi" << false; QTest::newRow("200-2") << QNetworkRequest::AlwaysCache << "httpcachetest_expires200.cgi" << AlwaysTrue; - QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_expires200.cgi" << true; + QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_expires200.cgi" << false; } void tst_QAbstractNetworkCache::expires() @@ -158,7 +158,7 @@ void tst_QAbstractNetworkCache::lastModified_data() QTest::newRow("200-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_lastModified200.cgi" << AlwaysFalse; QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_lastModified200.cgi" << false; QTest::newRow("200-2") << QNetworkRequest::AlwaysCache << "httpcachetest_lastModified200.cgi" << AlwaysTrue; - QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_lastModified200.cgi" << true; + QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_lastModified200.cgi" << false; } void tst_QAbstractNetworkCache::lastModified() @@ -180,7 +180,7 @@ void tst_QAbstractNetworkCache::etag_data() QTest::newRow("200-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_etag200.cgi" << AlwaysFalse; QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_etag200.cgi" << false; QTest::newRow("200-2") << QNetworkRequest::AlwaysCache << "httpcachetest_etag200.cgi" << AlwaysTrue; - QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_etag200.cgi" << true; + QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_etag200.cgi" << false; } void tst_QAbstractNetworkCache::etag() -- cgit v0.12 From 145fecc833926c307819752912e6833169799a53 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Tue, 15 Dec 2009 10:52:52 +0100 Subject: network internals: start HTTP GET requests right away when called on the code path from QNetworkAccessManager::get() to QTcpSocket::write() there were two calls involved that were invoked via a QueuedConnection, which would in some occasions delay writing the data to the socket. This patch makes sure the data is written to the socket immediately, without returning to the event loop (only the HTTP backend was changed for that event, the other backends were not changed) Reviewed-by: Thiago Macieira Reviewed-by: Markus Goetz --- src/network/access/qhttpnetworkconnection.cpp | 8 ++++---- src/network/access/qhttpnetworkconnectionchannel.cpp | 12 +++++++----- src/network/access/qhttpnetworkconnectionchannel_p.h | 2 +- src/network/access/qnetworkaccesshttpbackend.cpp | 7 ++++--- src/network/access/qnetworkaccesshttpbackend_p.h | 2 +- src/network/access/qnetworkaccessmanager.cpp | 4 ++-- src/network/access/qnetworkreplyimpl.cpp | 13 +++++++++++-- 7 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 44a0a79..2c56524 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -415,14 +415,13 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor lowPriorityQueue.prepend(pair); break; } - QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); + // this used to be called via invokeMethod and a QueuedConnection + _q_startNextRequest(); return reply; } void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair) { - Q_Q(QHttpNetworkConnection); - QHttpNetworkRequest request = pair.first; switch (request.priority()) { case QHttpNetworkRequest::HighPriority: @@ -433,7 +432,8 @@ void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair) lowPriorityQueue.prepend(pair); break; } - QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); + // this used to be called via invokeMethod and a QueuedConnection + _q_startNextRequest(); } void QHttpNetworkConnectionPrivate::dequeueAndSendRequest(QAbstractSocket *socket) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 1a68e97..7cf632f 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -166,6 +166,8 @@ bool QHttpNetworkConnectionChannel::sendRequest() QByteArray header = QHttpNetworkRequestPrivate::header(request, false); #endif socket->write(header); + // flushing is dangerous (QSslSocket calls transmit which might read or error) +// socket->flush(); QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice(); if (uploadByteDevice) { // connect the signals so this function gets called again @@ -258,7 +260,7 @@ bool QHttpNetworkConnectionChannel::sendRequest() // ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called // this is needed if the sends an reply before we have finished sending the request. In that // case receiveReply had been called before but ignored the server reply - receiveReply(); + QMetaObject::invokeMethod(connection, "_q_receiveReply", Qt::QueuedConnection); break; } case QHttpNetworkConnectionChannel::ReadingState: @@ -272,7 +274,7 @@ bool QHttpNetworkConnectionChannel::sendRequest() } -void QHttpNetworkConnectionChannel::receiveReply() +void QHttpNetworkConnectionChannel::_q_receiveReply() { Q_ASSERT(socket); @@ -567,7 +569,7 @@ void QHttpNetworkConnectionChannel::allDone() connection->d_func()->fillPipeline(socket); // continue reading - receiveReply(); + _q_receiveReply(); } } else if (alreadyPipelinedRequests.isEmpty() && socket->bytesAvailable() > 0) { eatWhitespace(); @@ -739,7 +741,7 @@ void QHttpNetworkConnectionChannel::_q_readyRead() if (isSocketWaiting() || isSocketReading()) { state = QHttpNetworkConnectionChannel::ReadingState; if (reply) - receiveReply(); + _q_receiveReply(); } } @@ -758,7 +760,7 @@ void QHttpNetworkConnectionChannel::_q_disconnected() if (isSocketWaiting() || isSocketReading()) { state = QHttpNetworkConnectionChannel::ReadingState; if (reply) - receiveReply(); + _q_receiveReply(); } else if (state == QHttpNetworkConnectionChannel::IdleState && resendCurrent) { // re-sending request because the socket was in ClosingState QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index bbe43cd..c30c236 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -144,7 +144,6 @@ public: void close(); bool sendRequest(); - void receiveReply(); bool ensureConnection(); @@ -166,6 +165,7 @@ public: bool isSocketReading() const; protected slots: + void _q_receiveReply(); void _q_bytesWritten(qint64 bytes); // proceed sending void _q_readyRead(); // pending data to read void _q_disconnected(); // disconnected from host diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index 5a2cce4..ada00df 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -594,9 +594,10 @@ void QNetworkAccessHttpBackend::open() if (transparentProxy.type() == QNetworkProxy::DefaultProxy && cacheProxy.type() == QNetworkProxy::DefaultProxy) { // unsuitable proxies - error(QNetworkReply::ProxyNotFoundError, - tr("No suitable proxy found")); - finished(); + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError), + Q_ARG(QString, QCoreApplication::translate("QNetworkAccessHttpBackend", "No suitable proxy found"))); + QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); return; } #endif diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h index bc3980d..705323d 100644 --- a/src/network/access/qnetworkaccesshttpbackend_p.h +++ b/src/network/access/qnetworkaccesshttpbackend_p.h @@ -104,6 +104,7 @@ private slots: void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth); void httpError(QNetworkReply::NetworkError error, const QString &errorString); bool sendCacheContents(const QNetworkCacheMetaData &metaData); + void finished(); // override private: QHttpNetworkReply *httpReply; @@ -118,7 +119,6 @@ private: #endif void disconnectFromHttp(); - void finished(); // override void setupConnection(); void validateCache(QHttpNetworkRequest &httpRequest, bool &loadedFromCache); void invalidateCache(); diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 2f57fee..d27fbe7 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -723,8 +723,6 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera // third step: find a backend priv->backend = d->findBackend(op, request); - // fourth step: setup the reply - priv->setup(op, request, outgoingData); #ifndef QT_NO_NETWORKPROXY QList proxyList = d->queryProxy(QNetworkProxyQuery(request.url())); priv->proxyList = proxyList; @@ -733,6 +731,8 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera priv->backend->setParent(reply); priv->backend->reply = priv; } + // fourth step: setup the reply + priv->setup(op, request, outgoingData); #ifndef QT_NO_OPENSSL reply->setSslConfiguration(request.sslConfiguration()); diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 42e802f..285864d 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -72,6 +72,9 @@ void QNetworkReplyImplPrivate::_q_startOperation() } state = Working; + // note: if that method is called directly, it cannot happen that the backend is 0, + // because we just checked via a qobject_cast that we got a http backend (see + // QNetworkReplyImplPrivate::setup()) if (!backend) { error(QNetworkReplyImpl::ProtocolUnknownError, QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown").arg(url.scheme())); // not really true!; @@ -203,7 +206,6 @@ void QNetworkReplyImplPrivate::_q_bufferOutgoingData() } } - void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *data) { @@ -246,7 +248,14 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const // No outgoing data (e.g. HTTP GET request) // or no backend // if no backend, _q_startOperation will handle the error of this - QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); + + // for HTTP, we want to send out the request as fast as possible to the network, without + // invoking methods in a QueuedConnection + if (qobject_cast(backend)) { + _q_startOperation(); + } else { + QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); + } } q->QIODevice::open(QIODevice::ReadOnly); -- cgit v0.12 From b3ffbdc0334c24d5d90ca3227a765fbd1e09bbc3 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 8 Jan 2010 13:59:52 +0100 Subject: [syncqt] Make it possible to override the base directory This removes the need to set the QTDIR environment variable and makes it possible to call syncqt conveniently when creating webkit packages. Reviewed-by: Thiago --- bin/syncqt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bin/syncqt b/bin/syncqt index 6c1a438..be0a019 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -15,6 +15,13 @@ use Cwd; use Config; use strict; +for (my $i = 0; $i < $#ARGV; $i++) { + if ($ARGV[$i] eq "-base-dir" && $i < $#ARGV - 1) { + $ENV{"QTDIR"} = $ARGV[$i + 1]; + last; + } +} + die "syncqt: QTDIR not defined" if ! $ENV{"QTDIR"}; # sanity check # global variables @@ -579,6 +586,10 @@ while ( @ARGV ) { } elsif("$arg" eq "-show") { $var = "showonly"; $val = "yes"; + } elsif("$arg" eq "-base-dir") { + # skip, it's been dealt with at the top of the file + shift @ARGV; + next; } elsif("$arg" eq '*') { # workaround for windows 9x where "%*" expands to "*" $var = 1; -- cgit v0.12 From 64ce2950db4e140d1e65da632acbc812cabc6e03 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 8 Jan 2010 14:30:18 +0100 Subject: [syncqt] Make it possible to synchronize headers for a separate module Added a -separate-module commandline option to syncqt that allows calling syncqt from outside of Qt to create header files. For WebKit package we call syncqt with -separate-module QtWebKit:WebKit/qt/Api to generate headers for the "QtWebKit" module for the headers in WebKit/qt/Api/*.h Reviewed-by: Thiago --- bin/syncqt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/bin/syncqt b/bin/syncqt index be0a019..3ac70a4 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -68,6 +68,8 @@ my $force_win = 0; my $force_relative = 0; my $check_includes = 0; my $copy_headers = 0; +my $create_uic_class_map = 1; +my $create_private_headers = 1; my @modules_to_sync ; $force_relative = 1 if ( -d "/System/Library/Frameworks" ); my $out_basedir = $basedir; @@ -91,6 +93,7 @@ sub showUsage print " -windows Force platform to Windows (default: " . ($force_win ? "yes" : "no") . ")\n"; print " -showonly Show action but not perform (default: " . ($showonly ? "yes" : "no") . ")\n"; print " -outdir Specify output directory for sync (default: $out_basedir)\n"; + print " -separate-module : Create headers for with original headers in \n"; print " -help This help\n"; exit 0; } @@ -583,6 +586,9 @@ while ( @ARGV ) { } elsif("$arg" eq "-module") { $var = "module"; $val = shift @ARGV; + } elsif("$arg" eq "-separate-module") { + $var = "separate-module"; + $val = shift @ARGV; } elsif("$arg" eq "-show") { $var = "showonly"; $val = "yes"; @@ -639,6 +645,13 @@ while ( @ARGV ) { print "module :$val:\n"; die "No such module: $val" unless(defined $modules{$val}); push @modules_to_sync, $val; + } elsif ("$var" eq "separate-module") { + my ($module, $srcdir) = split(/:/, $val); + $modules{$module} = $srcdir; + push @modules_to_sync, $module; + delete $moduleheaders{$module} if ($moduleheaders{$module}); + $create_uic_class_map = 0; + $create_private_headers = 0; } elsif ("$var" eq "output") { my $outdir = $val; if(checkRelative($outdir)) { @@ -824,7 +837,7 @@ foreach (@modules_to_sync) { $header_copies++ if (syncHeader("$out_basedir/include/phonon_compat/Phonon/$class", "$out_basedir/include/$lib/$header", 0)); } } - } else { + } elsif ($create_private_headers) { @headers = ( "$out_basedir/include/$lib/private/$header" ); push @headers, "$out_basedir/include/Qt/private/$header" if ("$lib" ne "phonon"); @@ -920,7 +933,7 @@ foreach (@modules_to_sync) { } } } -unless($showonly) { +unless($showonly || !$create_uic_class_map) { my $class_lib_map = "$out_basedir/src/tools/uic/qclass_lib_map.h"; if(-e "$class_lib_map") { open CLASS_LIB_MAP, "<$class_lib_map"; -- cgit v0.12 From 039387d498f4ca0125938c7c79c5aff29dab5361 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 11 Jan 2010 12:51:15 +0100 Subject: Add a way to access the normalised URL in QUrl. This is private API for now. For 4.7, decide whether to have a public method for this. Also investigate whether to provide a qHash function. Adding one to Qt would break source- and binary-compatibility with code that already has that (like Soprano). Patch-By: Warwick Allison Reviewed-by: Thiago Macieira --- src/corelib/io/qurl.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 1ba5e3f..74e5f74 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -350,8 +350,8 @@ public: }; int stateFlags; - QByteArray encodedNormalized; - const QByteArray & normalized(); + mutable QByteArray encodedNormalized; + const QByteArray & normalized() const; mutable QUrlErrorInfo errorInfo; QString createErrorString(); @@ -3850,6 +3850,9 @@ QByteArray QUrlPrivate::toEncoded(QUrl::FormattingOptions options) const if (!QURL_HASFLAG(stateFlags, Parsed)) parse(); else ensureEncodedParts(); + if (options==0x100) // private - see qHash(QUrl) + return normalized(); + QByteArray url; if (!(options & QUrl::RemoveScheme) && !scheme.isEmpty()) { @@ -3920,12 +3923,13 @@ QByteArray QUrlPrivate::toEncoded(QUrl::FormattingOptions options) const #define qToLower(ch) (((ch|32) >= 'a' && (ch|32) <= 'z') ? (ch|32) : ch) -const QByteArray &QUrlPrivate::normalized() +const QByteArray &QUrlPrivate::normalized() const { if (QURL_HASFLAG(stateFlags, QUrlPrivate::Normalized)) return encodedNormalized; - QURL_SETFLAG(stateFlags, QUrlPrivate::Normalized); + QUrlPrivate *that = const_cast(this); + QURL_SETFLAG(that->stateFlags, QUrlPrivate::Normalized); QUrlPrivate tmp = *this; tmp.scheme = tmp.scheme.toLower(); -- cgit v0.12