/**************************************************************************** ** ** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the $MODULE$ of the Qt Toolkit. ** ** $TROLLTECH_DUAL_EMBEDDED_LICENSE$ ** ****************************************************************************/ // This flag changes the implementation to use S60 CDcoumentHandler // instead of apparch when opening the files #undef USE_DOCUMENTHANDLER #include #include #include #include #include // KUidMsgTypeSMTP #include // CRichText #include // TDriveUnit etc #include // CEikonEnv #include // RApaLsSession #include // TApaTaskList, TApaTask #include // CSendUi #include // CMessageData #include // PathInfo #ifdef USE_DOCUMENTHANDLER #include // CDocumentHandler #endif QT_BEGIN_NAMESPACE _LIT(KSysBin, "\\Sys\\Bin\\"); _LIT(KTempDir, "\\System\\Temp\\"); _LIT(KBrowserPrefix, "4 " ); _LIT(KFontsDir, "z:\\resource\\Fonts\\"); const TUid KUidBrowser = { 0x10008D39 }; static void handleMailtoSchemeL(const QUrl &url) { QString recipient = url.path(); QString subject = url.queryItemValue("subject"); QString body = url.queryItemValue("body"); QString to = url.queryItemValue("to"); QString cc = url.queryItemValue("cc"); QString bcc = url.queryItemValue("bcc"); // these fields might have comma separated addresses QStringList recipients = recipient.split(","); QStringList tos = to.split(","); QStringList ccs = cc.split(","); QStringList bccs = bcc.split(","); CSendUi* sendUi = CSendUi::NewLC(); // Construct symbian sendUI data holder CMessageData* messageData = CMessageData::NewLC(); // Subject TPtrC subj( qt_QString2TPtrC(subject) ); messageData->SetSubjectL( &subj ); // Body CParaFormatLayer* paraFormat = CParaFormatLayer::NewL(); CleanupStack::PushL( paraFormat ); CCharFormatLayer* charFormat = CCharFormatLayer::NewL(); CleanupStack::PushL( charFormat ); CRichText* bodyRichText = CRichText::NewL( paraFormat, charFormat ); CleanupStack::PushL( bodyRichText ); TPtrC bodyPtr( qt_QString2TPtrC(body) ); if( bodyPtr.Length() ) { bodyRichText->InsertL( 0, bodyPtr ); } else { bodyRichText->InsertL( 0, KNullDesC ); } messageData->SetBodyTextL( bodyRichText ); // To foreach(QString item, recipients) messageData->AppendToAddressL(qt_QString2TPtrC(item)); foreach(QString item, tos) messageData->AppendToAddressL(qt_QString2TPtrC(item)); // Cc foreach(QString item, ccs) messageData->AppendCcAddressL(qt_QString2TPtrC(item)); // Bcc foreach(QString item, bccs) messageData->AppendBccAddressL(qt_QString2TPtrC(item)); sendUi->CreateAndSendMessageL( KUidMsgTypeSMTP, messageData ); CleanupStack::PopAndDestroy( 5 ); // bodyRichText, charFormat, paraFormat, messageData, sendUi } static bool handleMailtoScheme(const QUrl &url) { TRAPD(err, handleMailtoSchemeL(url)); return err ? false : true; } static void handleOtherSchemesL(const TDesC& aUrl) { // Other schemes are at the moment passed to WEB browser HBufC* buf16 = HBufC::NewLC( aUrl.Length() + KBrowserPrefix.iTypeLength ); buf16->Des().Copy( KBrowserPrefix ); // Prefix used to launch correct browser view buf16->Des().Append( aUrl ); TApaTaskList taskList( CEikonEnv::Static()->WsSession() ); TApaTask task = taskList.FindApp( KUidBrowser ); if ( task.Exists() ) { // Switch to existing browser instance HBufC8* param8 = HBufC8::NewLC( buf16->Length() ); param8->Des().Append( buf16->Des() ); task.SendMessage( TUid::Uid( 0 ), *param8 ); // Uid is not used CleanupStack::PopAndDestroy( param8 ); } else { // Start a new browser instance RApaLsSession appArcSession; User::LeaveIfError( appArcSession.Connect() ); CleanupClosePushL( appArcSession ); TThreadId id; appArcSession.StartDocument( *buf16, KUidBrowser , id ); CleanupStack::PopAndDestroy(); // appArcSession } CleanupStack::PopAndDestroy( buf16 ); } static bool handleOtherSchemes(const QUrl &url) { TRAPD( err, handleOtherSchemesL(qt_QString2TPtrC(url.toEncoded()))); return err ? false : true; } static TDriveUnit exeDrive() { RProcess me; TFileName processFileName = me.FileName(); TDriveUnit drive(processFileName); return drive; } static TDriveUnit writableExeDrive() { TDriveUnit drive = exeDrive(); if( drive.operator TInt() == EDriveZ ) return TDriveUnit( EDriveC ); return drive; } static TPtrC writableDataRoot() { TDriveUnit drive = exeDrive(); switch( drive.operator TInt() ){ case EDriveC: return PathInfo::PhoneMemoryRootPath(); break; case EDriveE: return PathInfo::MemoryCardRootPath(); break; case EDriveZ: // It is not possible to write on ROM drive -> // return phone mem root path instead return PathInfo::PhoneMemoryRootPath(); break; default: // TODO: Should we return drive root similar to MemoryCardRootPath return PathInfo::PhoneMemoryRootPath(); break; } } static void openDocumentL(const TDesC& aUrl) { #ifndef USE_DOCUMENTHANDLER // Start app associated to file MIME type by using RApaLsSession // Apparc base method cannot be used to open app in embedded mode, // but seems to be most stable way at the moment RApaLsSession appArcSession; User::LeaveIfError( appArcSession.Connect() ); CleanupClosePushL( appArcSession ); TThreadId id; // ESwitchFiles means do not start another instance // Leaves if file does not exist, leave is trapped in openDocument and false returned to user. User::LeaveIfError( appArcSession.StartDocument( aUrl, id, RApaLsSession::ESwitchFiles ) ); // ELaunchNewApp CleanupStack::PopAndDestroy(); // appArcSession #else // This is an alternative way to launch app associated to MIME type // CDocumentHandler would support opening apps in embedded mode, // but our Qt application window group seems to always get switched on top of embedded one // -> Cannot use menus etc of embedded app -> used CDocumentHandler* docHandler = CDocumentHandler::NewLC(); TDataType temp; //Standalone file opening fails for some file-types at least in S60 3.1 emulator //For example .txt file fails with KErrAlreadyInUse and music files with KERN-EXEC 0 //Workaround is to use OpenFileEmbeddedL //docHandler->OpenFileL(aUrl, temp); // Opening file with CDocumentHandler will leave if file does not exist // Leave is trapped in openDocument and false returned to user. docHandler->OpenFileEmbeddedL(aUrl, temp); CleanupStack::PopAndDestroy(docHandler); #endif } #ifdef USE_SCHEMEHANDLER // The schemehandler component only exist in private SDK. This implementation // exist here just for convenience in case that we need to use it later on // The schemehandle based implementation is not yet tested. // The biggest advantage of schemehandler is that it can handle // wide range of schemes and is extensible by plugins static bool handleUrl(const QUrl &url) { if (!url.isValid()) return false; TRAPD( err, handleUrlL(qt_QString2TPtrC(url.toString()))); return err ? false : true; } static void handleUrlL(const TDesC& aUrl) { CSchemeHandler* schemeHandler = CSchemeHandler::NewL( aUrl ); CleanupStack::PushL( schemeHandler ); schemeHandler->HandleUrlStandaloneL(); // Process the Url in standalone mode CleanupStack::PopAndDestroy(); } static bool launchWebBrowser(const QUrl &url) { return handleUrl(url); } static bool openDocument(const QUrl &file) { return handleUrl(url); } #endif static bool launchWebBrowser(const QUrl &url) { if (!url.isValid()) return false; if (url.scheme() == QLatin1String("mailto")) { return handleMailtoScheme(url); } return handleOtherSchemes( url ); } static bool openDocument(const QUrl &file) { if (!file.isValid()) return false; QString filePath = file.toLocalFile(); filePath = QDir::toNativeSeparators(filePath); TRAPD(err, openDocumentL(qt_QString2TPtrC(filePath))); return err ? false : true; } QString QDesktopServices::storageLocation(StandardLocation type) { TFileName path; switch (type) { case DesktopLocation: qWarning("QDesktopServices::storageLocation %d not implemented", type); break; case DocumentsLocation: path.Append(writableDataRoot()); break; case FontsLocation: path.Append(KFontsDir); break; case ApplicationsLocation: path.Append(exeDrive().Name()); path.Append(KSysBin); break; case MusicLocation: path.Append(writableDataRoot()); path.Append(PathInfo::SoundsPath()); break; case MoviesLocation: path.Append(writableDataRoot()); path.Append(PathInfo::VideosPath()); break; case PicturesLocation: path.Append(writableDataRoot()); path.Append(PathInfo::ImagesPath()); break; case TempLocation: path.Append(writableExeDrive().Name()); path.Append(KTempDir); //return QDir::tempPath(); break; break; case HomeLocation: path.Append(writableDataRoot()); //return QDir::homePath(); break; break; case DataLocation: CEikonEnv::Static()->FsSession().PrivatePath( path ); // TODO: Should we actually return phone mem if data is on ROM? path.Insert( 0, exeDrive().Name() ); break; default: break; } // Convert to cross-platform format and clean the path QString nativePath = QString::fromUtf16(path.Ptr(), path.Length()); QString qtPath = QDir::fromNativeSeparators(nativePath); qtPath = QDir::cleanPath(qtPath); // Note: The storage location returned can be a directory that does not exist; // i.e., it may need to be created by the system or the user. return qtPath; } typedef QString (*LocalizerFunc)(QString&); static QString defaultLocalizedDirectoryName(QString&) { return QString(); } QString QDesktopServices::displayName(StandardLocation type) { static LocalizerFunc ptrLocalizerFunc = NULL; if (!ptrLocalizerFunc) { ptrLocalizerFunc = reinterpret_cast (qt_resolveS60PluginFunc(S60Plugin_LocalizedDirectoryName)); if (!ptrLocalizerFunc) ptrLocalizerFunc = &defaultLocalizedDirectoryName; } QString rawPath = storageLocation(type); return ptrLocalizerFunc(rawPath); } QT_END_NAMESPACE