diff options
33 files changed, 502 insertions, 47 deletions
diff --git a/demos/qmediaplayer/mediaplayer.cpp b/demos/qmediaplayer/mediaplayer.cpp index 126031e..68752a0 100644 --- a/demos/qmediaplayer/mediaplayer.cpp +++ b/demos/qmediaplayer/mediaplayer.cpp @@ -46,6 +46,11 @@ #include "mediaplayer.h" #include "ui_settings.h" +#ifdef Q_OS_SYMBIAN +#include <cdbcols.h> +#include <cdblen.h> +#include <commdb.h> +#endif MediaVideoWidget::MediaVideoWidget(MediaPlayer *player, QWidget *parent) : Phonon::VideoWidget(parent), m_player(player), m_action(this) @@ -269,6 +274,10 @@ MediaPlayer::MediaPlayer() : fileMenu = new QMenu(this); QAction *openFileAction = fileMenu->addAction(tr("Open &File...")); QAction *openUrlAction = fileMenu->addAction(tr("Open &Location...")); +#ifdef Q_OS_SYMBIAN + QAction *selectIAPAction = fileMenu->addAction(tr("Select &IAP...")); + connect(selectIAPAction, SIGNAL(triggered(bool)), this, SLOT(selectIAP())); +#endif QAction *const openLinkAction = fileMenu->addAction(tr("Open &RAM File...")); connect(openLinkAction, SIGNAL(triggered(bool)), this, SLOT(openRamFile())); @@ -949,3 +958,37 @@ void MediaPlayer::hasVideoChanged(bool bHasVideo) m_videoWindow.setVisible(bHasVideo); m_fullScreenAction->setEnabled(bHasVideo); } + +#ifdef Q_OS_SYMBIAN +void MediaPlayer::selectIAP() +{ + TRAPD(err, selectIAPL()); + if (KErrNone != err) + QMessageBox::warning(this, "Phonon Mediaplayer", "Error selecting IAP", QMessageBox::Close); +} + +void MediaPlayer::selectIAPL() +{ + QVariant currentIAPValue = m_MediaObject.property("InternetAccessPointName"); + QString currentIAPString = currentIAPValue.toString(); + bool ok = false; + CCommsDatabase *commsDb = CCommsDatabase::NewL(EDatabaseTypeIAP); + CleanupStack::PushL(commsDb); + commsDb->ShowHiddenRecords(); + CCommsDbTableView* view = commsDb->OpenTableLC(TPtrC(IAP)); + QStringList items; + TInt currentIAP = 0; + for (TInt l = view->GotoFirstRecord(), i = 0; l != KErrNotFound; l = view->GotoNextRecord(), i++) { + TBuf<KCommsDbSvrMaxColumnNameLength> iapName; + view->ReadTextL(TPtrC(COMMDB_NAME), iapName); + QString iapString = QString::fromUtf16(iapName.Ptr(), iapName.Length()); + items << iapString; + if (iapString == currentIAPString) + currentIAP = i; + } + currentIAPString = QInputDialog::getItem(this, tr("Select Access Point"), tr("Select Access Point"), items, currentIAP, false, &ok); + if (ok) + m_MediaObject.setProperty("InternetAccessPointName", currentIAPString); + CleanupStack::PopAndDestroy(2); //commsDB, view +} +#endif diff --git a/demos/qmediaplayer/mediaplayer.h b/demos/qmediaplayer/mediaplayer.h index 7803321..7ddb7ae 100644 --- a/demos/qmediaplayer/mediaplayer.h +++ b/demos/qmediaplayer/mediaplayer.h @@ -141,12 +141,18 @@ private slots: void showContextMenu(const QPoint& point); void bufferStatus(int percent); void openUrl(); +#ifdef Q_OS_SYMBIAN + void selectIAP(); +#endif void openRamFile(); void configureEffect(); void hasVideoChanged(bool); private: bool playPauseForDialog(); +#ifdef Q_OS_SYMBIAN + void selectIAPL(); +#endif QIcon playIcon; QIcon pauseIcon; diff --git a/demos/qmediaplayer/qmediaplayer.pro b/demos/qmediaplayer/qmediaplayer.pro index 9407a81..d283ec8 100644 --- a/demos/qmediaplayer/qmediaplayer.pro +++ b/demos/qmediaplayer/qmediaplayer.pro @@ -33,5 +33,7 @@ symbian { include($$QT_SOURCE_TREE/demos/symbianpkgrules.pri) + LIBS += -lCommDb + TARGET.CAPABILITY="NetworkServices" } diff --git a/dist/changes-4.7.2 b/dist/changes-4.7.2 index a18a237..d443d88 100644 --- a/dist/changes-4.7.2 +++ b/dist/changes-4.7.2 @@ -126,6 +126,13 @@ Qt for Mac OS X - +Qt for Symbian +-------------- + + - Phonon MMF backend + * [QTBUG-11436] Added a MediaObject property which allows the client to + specify which Internet Access Point should be used for streaming. + Qt for Embedded Linux --------------------- diff --git a/doc/src/declarative/anchor-layout.qdoc b/doc/src/declarative/anchor-layout.qdoc index f03d9ee..941acfe 100644 --- a/doc/src/declarative/anchor-layout.qdoc +++ b/doc/src/declarative/anchor-layout.qdoc @@ -78,6 +78,9 @@ Rectangle { id: rect3; x: 150; ... } \image edge4.png +There are also some convenience anchors. anchors.fill is a convenience that is the same as setting the left,right,top and bottom anchors +to the left,right,top and bottom of the target item. anchors.centerIn is another convenience anchor, and is the same as setting the verticalCenter +and horizontalCenter anchors to the verticalCenter and horizontalCenter of the target item. \section1 Anchor Margins and Offsets diff --git a/doc/src/declarative/qtbinding.qdoc b/doc/src/declarative/qtbinding.qdoc index 4213f66..03290aa 100644 --- a/doc/src/declarative/qtbinding.qdoc +++ b/doc/src/declarative/qtbinding.qdoc @@ -235,6 +235,10 @@ defined by C++ classes; in fact, many of the core \l {QML Elements} are implemen C++ classes. When you create a QML object using one of these elements, you are simply creating an instance of a QObject-based C++ class and setting its properties. +To create a visual item that fits in with the Qt Quick elements, base your class off \l QDeclarativeItem instead of QObject directly. +You can then implement your own painting and functionality like any other QGraphicsObject. Note that QGraphicsItem::ItemHasNoContents is set by default on QDeclarativeItem because +it does not paint anything; you will need to clear this if your item is supposed to paint anything (as opposed to being solely for input handling or logical grouping). + For example, here is an \c ImageViewer class with an \c image URL property: \snippet doc/src/snippets/declarative/qtbinding/newelements/imageviewer.h 0 @@ -249,6 +253,11 @@ Then, any QML code loaded by your C++ application or \l{QDeclarativeExtensionPlu \snippet doc/src/snippets/declarative/qtbinding/newelements/standalone.qml 0 + +It is advised that you avoid using QGraphicsItem functionality beyond the properties documented in QDeclarativeItem. +This is because the GraphicsView backend is intended to be an implementation detail for QML, so the QtQuick items can be moved to faster backends as they become available with no change from a QML perspective. +To minimize any porting requirements for custom visual items, try to stick to the documented properties in QDeclarativeItem where possible. Properties QDeclarativeItem inherits but doesn't document are classed as implementation details; they are not officially supported and may disappear between releases. + Note that custom C++ types do not have to inherit from QDeclarativeItem; this is only necessary if it is a displayable item. If the item is not displayable, it can simply inherit from QObject. diff --git a/doc/src/snippets/declarative/codingconventions/photo.qml b/doc/src/snippets/declarative/codingconventions/photo.qml index 61e7eb7..78c5068 100644 --- a/doc/src/snippets/declarative/codingconventions/photo.qml +++ b/doc/src/snippets/declarative/codingconventions/photo.qml @@ -49,12 +49,20 @@ Rectangle { signal clicked // signal declarations - function doSomething(x) { // javascript functions + function doSomething(x) // javascript functions + { return x + photoImage.width } - x: 20; y: 20; width: 200; height: 150 // object properties - color: "gray" // try to group related properties together + color: "gray" // object properties + x: 20; y: 20; height: 150 // try to group related properties together + width: { // large bindings + if(photoImage.width > 200){ + photoImage.width; + }else{ + 200; + } + } Rectangle { // child objects id: border diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index 00cf0d7..ab94cfb 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -66,8 +66,8 @@ QMAKE_LINK_OBJECT_MAX = QMAKE_LINK_OBJECT_SCRIPT= QMAKE_LIBS = -llibc -llibm -leuser -llibdl -QMAKE_LIBS_CORE = $$QMAKE_LIBS -lefsrv -lhal -lbafl -QMAKE_LIBS_GUI = $$QMAKE_LIBS_CORE -lfbscli -lbitgdi -lgdi -lws32 -lapgrfx -lcone -leikcore -lmediaclientaudio -lapparc -lcentralrepository +QMAKE_LIBS_CORE = $$QMAKE_LIBS -lefsrv -lhal -lbafl -lapparc +QMAKE_LIBS_GUI = $$QMAKE_LIBS_CORE -lfbscli -lbitgdi -lgdi -lws32 -lapgrfx -lcone -leikcore -lmediaclientaudio -lcentralrepository QMAKE_LIBS_NETWORK = QMAKE_LIBS_EGL = -llibEGL QMAKE_LIBS_OPENGL = -llibGLESv2 diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index dfc5840..4f7caff 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -23,6 +23,9 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include "defs.h" #include "mediaobject.h" #include "utils.h" +#include <cdbcols.h> +#include <cdblen.h> +#include <commdb.h> QT_BEGIN_NAMESPACE @@ -267,11 +270,15 @@ void MMF::AbstractMediaPlayer::open() this, SLOT(downloadLengthChanged(qint64))); connect(m_download, SIGNAL(stateChanged(Download::State)), this, SLOT(downloadStateChanged(Download::State))); - m_download->start(); + int iap = m_parent->currentIAP(); + TRACE("HTTP Url: Using IAP %d", iap); + m_download->start(iap); } #endif else { - symbianErr = openUrl(url.toString()); + int iap = m_parent->currentIAP(); + TRACE("Using IAP %d", iap); + symbianErr = openUrl(url.toString(), iap); if (KErrNone != symbianErr) errorMessage = tr("Error opening URL"); } diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index c3b4528..df0a42f 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -75,7 +75,7 @@ protected: virtual int setDeviceVolume(int mmfVolume) = 0; virtual int openFile(const QString &fileName) = 0; virtual int openFile(RFile& file) = 0; - virtual int openUrl(const QString& url) = 0; + virtual int openUrl(const QString& url, int iap) = 0; virtual int openDescriptor(const TDesC8 &des) = 0; virtual int bufferStatus() const = 0; virtual void doClose() = 0; diff --git a/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp b/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp index 1ab5bae..ad4ee83 100644 --- a/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp @@ -146,9 +146,9 @@ int MMF::AbstractVideoPlayer::openFile(RFile &file) return err; } -int MMF::AbstractVideoPlayer::openUrl(const QString &url) +int MMF::AbstractVideoPlayer::openUrl(const QString &url, int iap) { - TRAPD(err, m_player->OpenUrlL(qt_QString2TPtrC(url))); + TRAPD(err, m_player->OpenUrlL(qt_QString2TPtrC(url), iap)); return err; } diff --git a/src/3rdparty/phonon/mmf/abstractvideoplayer.h b/src/3rdparty/phonon/mmf/abstractvideoplayer.h index 3bc5c7c..21446d2 100644 --- a/src/3rdparty/phonon/mmf/abstractvideoplayer.h +++ b/src/3rdparty/phonon/mmf/abstractvideoplayer.h @@ -66,7 +66,7 @@ public: virtual int setDeviceVolume(int mmfVolume); virtual int openFile(const QString &fileName); virtual int openFile(RFile &file); - virtual int openUrl(const QString &url); + virtual int openUrl(const QString &url, int iap); virtual int openDescriptor(const TDesC8 &des); virtual int bufferStatus() const; virtual void doClose(); diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index dc5c800..2ae6a3d 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -134,7 +134,7 @@ int MMF::AudioPlayer::openFile(RFile& file) return err; } -int MMF::AudioPlayer::openUrl(const QString& /*url*/) +int MMF::AudioPlayer::openUrl(const QString& /*url*/, int /*iap*/) { // Streaming playback is generally not supported by the implementation // of the audio player API, so we use CVideoPlayerUtility for both diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index cf4f6d5..e963c26 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -67,7 +67,7 @@ typedef CMdaAudioPlayerUtility NativePlayer; virtual int setDeviceVolume(int mmfVolume); virtual int openFile(const QString &fileName); virtual int openFile(RFile& file); - virtual int openUrl(const QString& url); + virtual int openUrl(const QString& url, int iap); virtual int openDescriptor(const TDesC8 &des); virtual int bufferStatus() const; virtual void doClose(); diff --git a/src/3rdparty/phonon/mmf/download.cpp b/src/3rdparty/phonon/mmf/download.cpp index 7b80e4a..f074d7f 100644 --- a/src/3rdparty/phonon/mmf/download.cpp +++ b/src/3rdparty/phonon/mmf/download.cpp @@ -20,6 +20,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include "utils.h" #include <QtCore/QDir> #include <QtCore/private/qcore_symbian_p.h> +#include <mmf/common/mmfcontrollerframeworkbase.h> QT_BEGIN_NAMESPACE @@ -39,11 +40,13 @@ DownloadPrivate::DownloadPrivate(Download *parent) DownloadPrivate::~DownloadPrivate() { + if (m_download) + m_download->Delete(); m_downloadManager.Disconnect(); m_downloadManager.Close(); } -bool DownloadPrivate::start() +bool DownloadPrivate::start(int iap) { TRACE_CONTEXT(DownloadPrivate::start, EVideoApi); Q_ASSERT(!m_download); @@ -54,6 +57,8 @@ bool DownloadPrivate::start() TRACE("connect err %d", err); if (KErrNone == err) { // Start download + if (KUseDefaultIap != iap) + m_downloadManager.SetIntAttribute(EDlMgrIap, iap); QHBufC url(m_parent->sourceUrl().toString()); TPtr8 url8 = url->Des().Collapse(); TRAP(err, m_download = &m_downloadManager.CreateDownloadL(url8)); @@ -140,12 +145,12 @@ const QString &Download::targetFileName() const return m_targetFileName; } -void Download::start() +void Download::start(int iap) { TRACE_CONTEXT(Download::start, EVideoApi); TRACE_ENTRY_0(); Q_ASSERT(Idle == m_state); - const bool ok = m_private->start(); + const bool ok = m_private->start(iap); setState(ok ? Initializing : Error); TRACE_EXIT_0(); } diff --git a/src/3rdparty/phonon/mmf/download.h b/src/3rdparty/phonon/mmf/download.h index bda7963..2ce54a8 100644 --- a/src/3rdparty/phonon/mmf/download.h +++ b/src/3rdparty/phonon/mmf/download.h @@ -43,7 +43,7 @@ class DownloadPrivate : public QObject public: DownloadPrivate(Download *parent); ~DownloadPrivate(); - bool start(); + bool start(int iap); void resume(); signals: void error(); @@ -69,7 +69,7 @@ public: ~Download(); const QUrl &sourceUrl() const; const QString &targetFileName() const; - void start(); + void start(int iap); void resume(); enum State { diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index 2c7a7ef..9da94ee 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -36,6 +36,10 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include <QDir> #include <QResource> #include <QUrl> +#include <cdbcols.h> +#include <cdblen.h> +#include <commdb.h> +#include <mmf/common/mmfcontrollerframeworkbase.h> QT_BEGIN_NAMESPACE @@ -64,7 +68,8 @@ MMF::MediaObject::MediaObject(QObject *parent) : MMF::MediaNode::MediaNode(paren const int err = m_fileServer.Connect(); QT_TRAP_THROWING(User::LeaveIfError(err)); - Q_UNUSED(parent); + parent->installEventFilter(this); + m_iap = KUseDefaultIap; TRACE_EXIT_0(); } @@ -74,6 +79,7 @@ MMF::MediaObject::~MediaObject() TRACE_CONTEXT(MediaObject::~MediaObject, EAudioApi); TRACE_ENTRY_0(); + parent()->removeEventFilter(this); delete m_resource; if (m_file) @@ -493,6 +499,55 @@ void MMF::MediaObject::switchToNextSource() } //----------------------------------------------------------------------------- +// IAP support +//----------------------------------------------------------------------------- + +int MMF::MediaObject::currentIAP() const +{ + return m_iap; +} + +bool MMF::MediaObject::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::DynamicPropertyChange ) { + QDynamicPropertyChangeEvent* dynamicEvent = static_cast<QDynamicPropertyChangeEvent*>(event); + if (dynamicEvent->propertyName() == "InternetAccessPointName") { + QVariant value = watched->property("InternetAccessPointName"); + if (value.isValid()) { + QString iapName = value.toString(); + TRAPD(err, setIAPIdFromNameL(iapName)); + if (err) + m_player->setError(tr("Failed to set requested IAP"), err); + } + } + } + return false; +} + +void MMF::MediaObject::setIAPIdFromNameL(const QString& iapString) +{ + TRACE_CONTEXT(MediaObject::getIapIdFromName, EVideoInternal); + TBuf<KCommsDbSvrMaxColumnNameLength> iapDes = qt_QString2TPtrC(iapString); + CCommsDatabase *commsDb = CCommsDatabase::NewL(EDatabaseTypeIAP); + CleanupStack::PushL(commsDb); + commsDb->ShowHiddenRecords(); + CCommsDbTableView *view = commsDb->OpenTableLC(TPtrC(IAP)); + for (TInt l = view->GotoFirstRecord(); l != KErrNotFound; l = view->GotoNextRecord()) { + TBuf<KCommsDbSvrMaxColumnNameLength> iapName; + view->ReadTextL(TPtrC(COMMDB_NAME), iapName); + TRACE("found IAP %S", &iapName); + if (iapName.CompareF(iapDes) == 0) { + TUint32 uiap; + view->ReadUintL(TPtrC(COMMDB_ID), uiap); + TRACE("matched IAP %S, setting m_iap %d", &iapName, uiap); + m_iap = uiap; + break; + } + } + CleanupStack::PopAndDestroy(2); // commsDb, view +} + +//----------------------------------------------------------------------------- // Other private functions //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index 5d785fb..0ed70ff 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -23,6 +23,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include <phonon/mediaobjectinterface.h> #include <QScopedPointer> #include <QTimer> +#include <QString> // For recognizer #include <apgcli.h> @@ -92,6 +93,7 @@ public: int openFileHandle(const QString &fileName); RFile* file() const; QResource* resource() const; + int currentIAP() const; public Q_SLOTS: void volumeChanged(qreal volume); @@ -113,6 +115,9 @@ Q_SIGNALS: void finished(); void tick(qint64 time); +protected: + bool eventFilter(QObject *watched, QEvent *event); + private Q_SLOTS: void handlePrefinishMarkReached(qint32); @@ -120,6 +125,7 @@ private: void switchToSource(const MediaSource &source); void createPlayer(const MediaSource &source); bool openRecognizer(); + void setIAPIdFromNameL(const QString& iapString); // Audio / video media type recognition MediaType fileMediaType(const QString& fileName); @@ -143,6 +149,7 @@ private: QResource* m_resource; QScopedPointer<AbstractPlayer> m_player; + int m_iap; }; } diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index b445a50..381be34 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -71,6 +71,7 @@ # include <e32ldr.h> # include "qeventdispatcher_symbian_p.h" # include "private/qcore_symbian_p.h" +# include <apacmdln.h> #elif defined(Q_OS_UNIX) # if !defined(QT_NO_GLIB) # include "qeventdispatcher_glib_p.h" @@ -115,7 +116,58 @@ private: #ifdef Q_OS_SYMBIAN typedef TDriveNumber (*SystemDriveFunc)(RFs&); -static SystemDriveFunc PtrGetSystemDrive=0; +static SystemDriveFunc PtrGetSystemDrive = 0; +static CApaCommandLine* apaCommandLine = 0; +static char *apaTail = 0; +static QVector<char *> *apaArgv = 0; + +static void qt_cleanup_apa_cmd_line() +{ + delete apaCommandLine; + apaCommandLine = 0; + delete apaArgv; + apaArgv = 0; + delete apaTail; + apaTail = 0; +} + +static inline void qt_init_symbian_apa_arguments(int &argc, char **&argv) +{ + // If app is launched via CApaCommandLine::StartApp(), normal arguments only contain + // application name. + if (argc == 1) { + CApaCommandLine* commandLine = QCoreApplicationPrivate::symbianCommandLine(); + if(commandLine) { + TPtrC8 apaCmdLine = commandLine->TailEnd(); + int tailLen = apaCmdLine.Length(); + if (tailLen) { + apaTail = reinterpret_cast<char *>(qMalloc(tailLen + 1)); + qMemCopy(apaTail, reinterpret_cast<const char *>(apaCmdLine.Ptr()), tailLen); + apaTail[tailLen] = '\0'; + apaArgv = new QVector<char *>(8); + // Reuse windows command line parsing + *apaArgv = qWinCmdLine<char>(apaTail, tailLen, argc); + apaArgv->insert(0, argv[0]); + argc++; + argv = apaArgv->data(); + } + } + } +} + +CApaCommandLine* QCoreApplicationPrivate::symbianCommandLine() +{ + // Getting of Apa command line needs to be static as it can only be called successfully + // once per process. + if (!apaCommandLine) { + TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(apaCommandLine); + if (err == KErrNone) { + qAddPostRoutine(qt_cleanup_apa_cmd_line); + } + } + return apaCommandLine; +} + #endif #if defined(Q_WS_WIN) || defined(Q_WS_MAC) @@ -274,6 +326,10 @@ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv) } QCoreApplicationPrivate::is_app_closing = false; +#ifdef Q_OS_SYMBIAN + qt_init_symbian_apa_arguments(argc, argv); +#endif + #ifdef Q_OS_UNIX qt_application_thread_id = QThread::currentThreadId(); #endif @@ -2056,6 +2112,12 @@ char **QCoreApplication::argv() As a result of this, the string given by arguments().at(0) might not be the program name on Windows, depending on how the application was started. + For Symbian applications started with \c RApaLsSession::StartApp one can specify + arguments using \c CApaCommandLine::SetTailEndL function. Such arguments are only + available via this method; they will not be passed to \c main function. Also note + that only 8-bit string data set with \c CApaCommandLine::SetTailEndL is supported + by this function. + \sa applicationFilePath() */ diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index d06fb51..703c825 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -65,8 +65,11 @@ QT_BEGIN_NAMESPACE typedef QList<QTranslator*> QTranslatorList; -#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_SYSTEMLOCALE) +#if defined(Q_OS_SYMBIAN) +# if !defined(QT_NO_SYSTEMLOCALE) class QEnvironmentChangeNotifier; +# endif +class CApaCommandLine; #endif class QAbstractEventDispatcher; @@ -116,9 +119,12 @@ public: bool aboutToQuitEmitted; QString cachedApplicationDirPath; QString cachedApplicationFilePath; -#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_SYSTEMLOCALE) +#if defined(Q_OS_SYMBIAN) +# if !defined(QT_NO_SYSTEMLOCALE) QScopedPointer<QEnvironmentChangeNotifier> environmentChangeNotifier; void symbianInit(); +# endif + static CApaCommandLine* symbianCommandLine(); #endif static bool isTranslatorInstalled(QTranslator *translator); diff --git a/src/corelib/kernel/qcorecmdlineargs_p.h b/src/corelib/kernel/qcorecmdlineargs_p.h index fd1d202..cdde782 100644 --- a/src/corelib/kernel/qcorecmdlineargs_p.h +++ b/src/corelib/kernel/qcorecmdlineargs_p.h @@ -58,11 +58,13 @@ QT_BEGIN_NAMESPACE -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) QT_BEGIN_INCLUDE_NAMESPACE #include "QtCore/qvector.h" -#include "qt_windows.h" +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) +# include "qt_windows.h" +#endif QT_END_INCLUDE_NAMESPACE // template implementation of the parsing algorithm @@ -130,6 +132,7 @@ static QVector<Char*> qWinCmdLine(Char *cmdParam, int length, int &argc) return argv; } +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) static inline QStringList qWinCmdArgs(QString cmdLine) // not const-ref: this might be modified { QStringList args; @@ -150,8 +153,8 @@ static inline QStringList qCmdLineArgs(int argc, char *argv[]) QString cmdLine = QString::fromWCharArray(GetCommandLine()); return qWinCmdArgs(cmdLine); } - -#else // !Q_OS_WIN +#endif +#else // !Q_OS_WIN || !Q_OS_SYMBIAN static inline QStringList qCmdLineArgs(int argc, char *argv[]) { @@ -161,7 +164,7 @@ static inline QStringList qCmdLineArgs(int argc, char *argv[]) return args; } -#endif // Q_OS_WIN +#endif // Q_OS_WIN || Q_OS_SYMBIAN QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp index e7dae98..8210314 100644 --- a/src/declarative/qml/qdeclarativeproperty.cpp +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -665,7 +665,7 @@ QDeclarativePropertyPrivate::binding(QObject *object, int coreIndex, int valueTy static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex)); QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; - if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) + if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1) return 0; // This will either be a value type sub-reference or an alias to a value-type sub-reference not both diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 4793437..789f198 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1431,21 +1431,20 @@ void qt_init(QApplicationPrivate * /* priv */, int) // The S60 framework has not been initialized. We need to do it. TApaApplicationFactory factory(S60->s60ApplicationFactory ? S60->s60ApplicationFactory : newS60Application); - CApaCommandLine* commandLine = 0; - TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine); - // After this construction, CEikonEnv will be available from CEikonEnv::Static(). - // (much like our qApp). - QtEikonEnv* coe = new QtEikonEnv; - //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there. - if(err == KErrNone) - TRAP(err, coe->ConstructAppFromCommandLineL(factory,*commandLine)); - delete commandLine; - if(err != KErrNone) { - qWarning() << "qt_init: Eikon application construct failed (" - << err - << "), maybe missing resource file on S60 3.1?"; - delete coe; - qt_symbian_throwIfError(err); + CApaCommandLine* commandLine = q_check_ptr(QCoreApplicationPrivate::symbianCommandLine()); + if (commandLine) { + // After this construction, CEikonEnv will be available from CEikonEnv::Static(). + // (much like our qApp). + QtEikonEnv* coe = new QtEikonEnv; + //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there. + TRAPD(err, coe->ConstructAppFromCommandLineL(factory, *commandLine)); + if(err != KErrNone) { + qWarning() << "qt_init: Eikon application construct failed (" + << err + << "), maybe missing resource file on S60 3.1?"; + delete coe; + qt_symbian_throwIfError(err); + } } S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler); diff --git a/src/plugins/phonon/mmf/mmf.pro b/src/plugins/phonon/mmf/mmf.pro index 5d7b61d..de00c9e 100644 --- a/src/plugins/phonon/mmf/mmf.pro +++ b/src/plugins/phonon/mmf/mmf.pro @@ -127,6 +127,9 @@ symbian { # These are for effects. LIBS += -lAudioEqualizerEffect -lBassBoostEffect -lDistanceAttenuationEffect -lDopplerbase -lEffectBase -lEnvironmentalReverbEffect -lListenerDopplerEffect -lListenerLocationEffect -lListenerOrientationEffect -lLocationBase -lLoudnessEffect -lOrientationBase -lSourceDopplerEffect -lSourceLocationEffect -lSourceOrientationEffect -lStereoWideningEffect + # This is to allow IAP to be specified + LIBS += -lCommDb + # This is needed for having the .qtplugin file properly created on Symbian. QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/phonon_backend diff --git a/src/s60installs/bwins/QtCoreu.def b/src/s60installs/bwins/QtCoreu.def index 6ecb403..872142d 100644 --- a/src/s60installs/bwins/QtCoreu.def +++ b/src/s60installs/bwins/QtCoreu.def @@ -4486,4 +4486,5 @@ EXPORTS ?objectNameChanged@QAbstractDeclarativeData@@2P6AXPAV1@PAVQObject@@@ZA @ 4485 NONAME ; void (*QAbstractDeclarativeData::objectNameChanged)(class QAbstractDeclarativeData *, class QObject *) ?queueDeferredActiveObjectsCompletion@QEventDispatcherSymbian@@QAEXXZ @ 4486 NONAME ; void QEventDispatcherSymbian::queueDeferredActiveObjectsCompletion(void) ?reactivateDeferredActiveObjects@QEventDispatcherSymbian@@UAEXXZ @ 4487 NONAME ; void QEventDispatcherSymbian::reactivateDeferredActiveObjects(void) + ?symbianCommandLine@QCoreApplicationPrivate@@SAPAVCApaCommandLine@@XZ @ 4488 NONAME ; class CApaCommandLine * QCoreApplicationPrivate::symbianCommandLine(void) diff --git a/src/s60installs/eabi/QtCoreu.def b/src/s60installs/eabi/QtCoreu.def index aefbe1f..5815b28 100644 --- a/src/s60installs/eabi/QtCoreu.def +++ b/src/s60installs/eabi/QtCoreu.def @@ -3714,4 +3714,5 @@ EXPORTS _Z26qt_symbian_SetupThreadHeapiR24SStdEpocThreadCreateInfo @ 3713 NONAME _ZN24QAbstractDeclarativeData17objectNameChangedE @ 3714 NONAME DATA 4 _ZN23QEventDispatcherSymbian36queueDeferredActiveObjectsCompletionEv @ 3715 NONAME + _ZN23QCoreApplicationPrivate18symbianCommandLineEv @ 3716 NONAME diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro index be7ed97..3b705ad 100644 --- a/src/s60installs/s60installs.pro +++ b/src/s60installs/s60installs.pro @@ -16,8 +16,7 @@ symbian: { # It is also expected that devices newer than those based on S60 5.0 all have sqlite3.dll. contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2)|contains(S60_VERSION, 5.0) { BLD_INF_RULES.prj_exports += \ - "sqlite3.sis /epoc32/data/qt/sis/sqlite3.sis" \ - "sqlite3_selfsigned.sis /epoc32/data/qt/sis/sqlite3_selfsigned.sis" + "sqlite3.sis /epoc32/data/qt/sis/sqlite3.sis" symbian-abld|symbian-sbsv2 { sqlitedeployment = \ "; Deploy sqlite onto phone that does not have it already" \ diff --git a/src/s60installs/sqlite3_selfsigned.sis b/src/s60installs/sqlite3_selfsigned.sis Binary files differdeleted file mode 100644 index a025ac5..0000000 --- a/src/s60installs/sqlite3_selfsigned.sis +++ /dev/null diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h index 7724335..6c6ad1f 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h @@ -624,6 +624,8 @@ public: Q_INVOKABLE int method_default(int a, int b = 19) { invoke(20); m_actuals << a << b; return b; } + Q_INVOKABLE void method_QVariant(QVariant a, QVariant b = QVariant()) { invoke(21); m_actuals << a << b; } + private: friend class MyInvokableBaseObject; void invoke(int idx) { if (m_invoked != -1) m_invokedError = true; m_invoked = idx;} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 90006a9..034adf7 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -1786,6 +1786,22 @@ void tst_qdeclarativeecmascript::callQtInvokables() QCOMPARE(o.invoked(), -3); QCOMPARE(o.actuals().count(), 1); QCOMPARE(o.actuals().at(0), QVariant(9)); + + o.reset(); + QCOMPARE(engine->evaluate("object.method_QVariant(9)").isUndefined(), true); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 21); + QCOMPARE(o.actuals().count(), 2); + QCOMPARE(o.actuals().at(0), QVariant(9)); + QCOMPARE(o.actuals().at(1), QVariant()); + + o.reset(); + QCOMPARE(engine->evaluate("object.method_QVariant(\"Hello\", \"World\")").isUndefined(), true); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 21); + QCOMPARE(o.actuals().count(), 2); + QCOMPARE(o.actuals().at(0), QVariant(QString("Hello"))); + QCOMPARE(o.actuals().at(1), QVariant(QString("World"))); } // QTBUG-13047 (check that you can pass registered object types as args) diff --git a/tests/auto/mediaobject/mediaobject.pro b/tests/auto/mediaobject/mediaobject.pro index e887df4..1fc76a2 100755 --- a/tests/auto/mediaobject/mediaobject.pro +++ b/tests/auto/mediaobject/mediaobject.pro @@ -18,5 +18,7 @@ symbian:{ addFiles.sources = media/test.sdp addFiles.path = media DEPLOYMENT += addFiles + LIBS += -lCommDb -lconnmon + TARGET.CAPABILITY += "NetworkServices" } diff --git a/tests/auto/mediaobject/tst_mediaobject.cpp b/tests/auto/mediaobject/tst_mediaobject.cpp index 5decbe2..b29a6db 100644 --- a/tests/auto/mediaobject/tst_mediaobject.cpp +++ b/tests/auto/mediaobject/tst_mediaobject.cpp @@ -101,6 +101,70 @@ const qint64 ALLOWED_TIME_FOR_SEEKING = 1000; // 1s const qint64 SEEKING_TOLERANCE = 0; #endif //Q_OS_WINCE +#ifdef Q_OS_SYMBIAN +#include <cdbcols.h> +#include <cdblen.h> +#include <commdb.h> +#include <rconnmon.h> + +const QString KDefaultIAP = QLatin1String("default"); +const QString KInvalidIAP = QLatin1String("invalid IAP"); + +class CConnectionObserver : public CBase, public MConnectionMonitorObserver +{ +public: + static CConnectionObserver* NewL() + { + CConnectionObserver* self = new (ELeave) CConnectionObserver(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + QString currentIAP() + { + return m_currentIAPName; + } + ~CConnectionObserver() + { + m_connMon.Close(); + } +private: + CConnectionObserver() + { + } + void ConstructL() + { + m_connMon.ConnectL(); + m_connMon.NotifyEventL(*this); + } + void EventL (const CConnMonEventBase &aConnEvent) + { + TInt event = aConnEvent.EventType(); + TUint connId = aConnEvent.ConnectionId(); + TRequestStatus status; + switch (event) { + case EConnMonCreateConnection: { + TBuf<KCommsDbSvrMaxColumnNameLength> iapName; + m_connMon.GetStringAttribute(connId, 0, KIAPName, iapName, status); + User::WaitForRequest(status); + m_currentIAPName = QString(reinterpret_cast<const QChar *>(iapName.Ptr()), iapName.Length()); + qDebug() << "A new connection created using: " << m_currentIAPName; + break; + } + default: + break; + } + } + +private: + RConnectionMonitor m_connMon; + QString m_currentIAPName; +}; + +#endif + + class tst_MediaObject : public QObject { Q_OBJECT @@ -140,6 +204,8 @@ class tst_MediaObject : public QObject void pauseToPlay(); void pauseToStop(); void playSDP(); + void playUrl_data(); + void playUrl(); void testPrefinishMark(); void testSeek(); @@ -161,6 +227,10 @@ class tst_MediaObject : public QObject Phonon::MediaObject *m_media; QSignalSpy *m_stateChangedSignalSpy; QString m_tmpFileName; +#ifdef Q_OS_SYMBIAN + CConnectionObserver *m_iapConnectionObserver; + QString getValidIAPL(); +#endif //Q_OS_SYMBIAN static void copyMediaFile(const QString &original, const QString &name, @@ -451,6 +521,10 @@ void tst_MediaObject::initTestCase() QCOMPARE(m_media->outputPaths().size(), 1); QCOMPARE(audioOutput->inputPaths().size(), 1); +#ifdef Q_OS_SYMBIAN + TRAP_IGNORE(m_iapConnectionObserver = CConnectionObserver::NewL()); +#endif //Q_OS_SYMBIAN + } void tst_MediaObject::checkForDefaults() @@ -586,6 +660,121 @@ void tst_MediaObject::playSDP() #endif } +/*! + Attempt to play from an RTSP link, and, on Symbian, to specify the IAP that + should be used to connect to the network. This test requires the unit under test + to have a default internet connection that will support streaming media, and ideally + one other internet connection that will also support streaming. + */ +void tst_MediaObject::playUrl_data() +{ + QTest::addColumn<QUrl>("url"); +#ifdef Q_OS_SYMBIAN + QTest::addColumn<QString>("iap"); +#endif //Q_OS_SYMBIAN + + QUrl rtspLink("rtsp://v1.cache8.c.youtube.com/CjgLENy73wIaLwnoDBCE7tF7fxMYESARFEIJbXYtZ29vZ2xlSARSB3Jlc3VsdHNgpbWqq7L7je5KDA==/0/0/0/video.3gp"); + QUrl httpLink("http://www.theflute.co.uk/media/BachCPE_SonataAmin_1.wma"); + +#ifdef Q_OS_SYMBIAN + QTest::newRow("default_IAP_rtsp") << rtspLink << KDefaultIAP; + QTest::newRow("invalid_IAP_rtsp") << rtspLink << KInvalidIAP; + //don't test HTTP link with invalid or default IAP as it will prompt the user + //Add tests with a valid IAP if we can get one from CommsDB + QString validIAP; + TRAPD(err, validIAP = getValidIAPL()); + if (KErrNone == err) { + QTest::newRow("valid_IAP_rtsp") << rtspLink << validIAP; + QTest::newRow("valid_IAP_http") << httpLink << validIAP; + } +#else + QTest::newRow("default_IAP_rtsp") << rtspLink; + QTest::newRow("invalid_IAP_rtsp") << rtspLink; +#endif //Q_OS_SYMBIAN +} + +#ifdef Q_OS_SYMBIAN +QString tst_MediaObject::getValidIAPL() +{ + CCommsDatabase* commsDb = CCommsDatabase::NewL(EDatabaseTypeIAP); + CleanupStack::PushL(commsDb); + commsDb->ShowHiddenRecords(); + CCommsDbTableView* view = commsDb->OpenTableLC(TPtrC(IAP)); + QString validIAP; + TBool found = EFalse; + TInt record = view->GotoFirstRecord(); + while (KErrNotFound != record) { + TBuf<KCommsDbSvrMaxColumnNameLength> iapName; + view->ReadTextL(TPtrC(COMMDB_NAME), iapName); + validIAP = QString::fromUtf16(iapName.Ptr(),iapName.Length()); + //We don't want the "Easy WLAN" IAP as it will try and prompt the user + if ("Easy WLAN" != validIAP) { + qDebug() << "playUrl_data() adding a valid IAP test: " << validIAP; + found = ETrue; + break; + } + record = view->GotoNextRecord(); + } + CleanupStack::PopAndDestroy(2); + if (!found) + User::Leave(KErrNotFound); + return validIAP; +} +#endif //Q_OS_SYMBIAN + +void tst_MediaObject::playUrl() +{ + QFETCH(QUrl, url); +#ifdef Q_OS_SYMBIAN + QFETCH(QString, iap); +#endif + MediaObject media(this); + + //Create a proper media path for video and audio + VideoWidget videoOutput; + Path path = createPath(&media, &videoOutput); + QVERIFY(path.isValid()); + AudioOutput audioOutput(Phonon::MusicCategory, this); + path = createPath(&media, &audioOutput); + QVERIFY(path.isValid()); + +#ifdef Q_OS_SYMBIAN + //The Symbian backend allows the IAP used for streaming connections to be specified + //by the application, using the "InternetAccessPointName" property. + if (KDefaultIAP != iap) + media.setProperty("InternetAccessPointName", iap); +#endif //Q_OS_SYMBIAN + media.setCurrentSource(Phonon::MediaSource(url)); + QVERIFY(media.state() != Phonon::ErrorState); + + //we use a long 30s timeout here as it can take a long time for the streaming source to + //be sucessfully prepared depending on the network. + if (media.state() != Phonon::StoppedState) + QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 30000); + QCOMPARE(media.state(), Phonon::StoppedState); + + media.play(); + if (media.state() != Phonon::PlayingState) + QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 15000); + QCOMPARE(media.state(), Phonon::PlayingState); + + //sleep and allow some of the stream to be played + QTest::qSleep(10000); + +#ifdef Q_OS_SYMBIAN + // Verify that the specified IAP is actually being used when we're not doing negative tests + if ((KDefaultIAP == iap || KInvalidIAP == iap) == false) { + if (m_iapConnectionObserver) + QCOMPARE(iap,m_iapConnectionObserver->currentIAP()); + } +#endif //Q_OS_SYMBIAN + + media.stop(); + if (media.state() != Phonon::StoppedState) + QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 15000); + QCOMPARE(media.state(), Phonon::StoppedState); +} + void tst_MediaObject::testPrefinishMark() { const qint32 requestedPrefinishMarkTime = 2000; @@ -937,6 +1126,10 @@ void tst_MediaObject::cleanupTestCase() if (!m_tmpFileName.isNull()) { QVERIFY(QFile::remove(m_tmpFileName)); } +#ifdef Q_OS_SYMBIAN + if (m_iapConnectionObserver) + delete m_iapConnectionObserver; +#endif //Q_OS_SYMBIAN } void tst_MediaObject::_testOneSeek(qint64 seekTo) diff --git a/tests/auto/qglthreads/tst_qglthreads.cpp b/tests/auto/qglthreads/tst_qglthreads.cpp index 50152d1..0bcc4f6 100644 --- a/tests/auto/qglthreads/tst_qglthreads.cpp +++ b/tests/auto/qglthreads/tst_qglthreads.cpp @@ -51,9 +51,13 @@ #ifdef Q_OS_SYMBIAN #include <unistd.h> // for usleep +#define RUNNING_TIME 2000 // save GPU mem by running shorter time. +#else +#define RUNNING_TIME 5000 #endif -#define RUNNING_TIME 5000 + + tst_QGLThreads::tst_QGLThreads(QObject *parent) : QObject(parent) @@ -205,7 +209,15 @@ public: QTime time; time.start(); while (time.elapsed() < RUNNING_TIME) { - QImage image(400, 300, QImage::Format_RGB32); + int width = 400; + int height = 300; +#ifdef Q_OS_SYMBIAN + // GPU mem is very scarce resource on Symbian currently. + // That's why we create only small textures. + width = 50; + height = 20; +#else + QImage image(width, height, QImage::Format_RGB32); QPainter p(&image); p.fillRect(image.rect(), QColor(rand() % 256, rand() % 256, rand() % 256)); p.setPen(Qt::red); @@ -434,6 +446,10 @@ void tst_QGLThreads::renderInThread() QSKIP("OpenGL threading tests are currently disabled on mac as they were causing reboots", SkipAll); #endif +#ifdef Q_OS_SYMBIAN + QSKIP("OpenGL threading tests are disabled on Symbian as accessing RWindow from a secondary thread is not supported", SkipAll); +#endif + QFETCH(bool, resize); QFETCH(bool, update); |