diff options
Diffstat (limited to 'src/gui/util')
-rw-r--r-- | src/gui/util/qcompleter.cpp | 22 | ||||
-rw-r--r-- | src/gui/util/qcompleter_p.h | 3 | ||||
-rw-r--r-- | src/gui/util/qdesktopservices.cpp | 8 | ||||
-rw-r--r-- | src/gui/util/qdesktopservices_s60.cpp | 440 | ||||
-rw-r--r-- | src/gui/util/util.pri | 5 |
5 files changed, 467 insertions, 11 deletions
diff --git a/src/gui/util/qcompleter.cpp b/src/gui/util/qcompleter.cpp index f4dd87c..29763e2 100644 --- a/src/gui/util/qcompleter.cpp +++ b/src/gui/util/qcompleter.cpp @@ -158,7 +158,7 @@ QT_BEGIN_NAMESPACE QCompletionModel::QCompletionModel(QCompleterPrivate *c, QObject *parent) : QAbstractProxyModel(*new QCompletionModelPrivate, parent), - c(c), engine(0), showAll(false) + c(c), showAll(false) { createEngine(); } @@ -208,11 +208,10 @@ void QCompletionModel::createEngine() break; } - delete engine; if (sortedEngine) - engine = new QSortedModelEngine(c); + engine.reset(new QSortedModelEngine(c)); else - engine = new QUnsortedModelEngine(c); + engine.reset(new QUnsortedModelEngine(c)); } QModelIndex QCompletionModel::mapToSource(const QModelIndex& index) const @@ -482,7 +481,7 @@ QMatchData QCompletionEngine::filterHistory() for (int i = 0; i < source->rowCount(); i++) { QString str = source->index(i, c->column).data().toString(); if (str.startsWith(c->prefix, c->cs) -#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE) +#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN) && (!dirModel || QDir::toNativeSeparators(str) != QDir::separator()) #endif ) @@ -990,7 +989,7 @@ void QCompleter::setModel(QAbstractItemModel *model) delete oldModel; #ifndef QT_NO_DIRMODEL if (qobject_cast<QDirModel *>(model)) { -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) setCaseSensitivity(Qt::CaseInsensitive); #else setCaseSensitivity(Qt::CaseSensitive); @@ -1656,7 +1655,7 @@ QString QCompleter::pathFromIndex(const QModelIndex& index) const idx = parent.sibling(parent.row(), index.column()); } while (idx.isValid()); -#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE) +#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN) if (list.count() == 1) // only the separator or some other text return list[0]; list[0].clear() ; // the join below will provide the separator @@ -1690,7 +1689,10 @@ QStringList QCompleter::splitPath(const QString& path) const QString pathCopy = QDir::toNativeSeparators(path); QString sep = QDir::separator(); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if defined(Q_OS_SYMBIAN) + if (pathCopy == QLatin1String("\\")) + return QStringList(pathCopy); +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (pathCopy == QLatin1String("\\") || pathCopy == QLatin1String("\\\\")) return QStringList(pathCopy); QString doubleSlash(QLatin1String("\\\\")); @@ -1703,7 +1705,9 @@ QStringList QCompleter::splitPath(const QString& path) const QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']')); QStringList parts = pathCopy.split(re); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if defined(Q_OS_SYMBIAN) + // Do nothing +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (!doubleSlash.isEmpty()) parts[0].prepend(doubleSlash); #else diff --git a/src/gui/util/qcompleter_p.h b/src/gui/util/qcompleter_p.h index 288f531..3911b0d 100644 --- a/src/gui/util/qcompleter_p.h +++ b/src/gui/util/qcompleter_p.h @@ -214,7 +214,6 @@ class QCompletionModel : public QAbstractProxyModel public: QCompletionModel(QCompleterPrivate *c, QObject *parent); - ~QCompletionModel() { delete engine; } void createEngine(); void setFiltered(bool); @@ -237,7 +236,7 @@ public: QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; QCompleterPrivate *c; - QCompletionEngine *engine; + QScopedPointer<QCompletionEngine> engine; bool showAll; Q_DECLARE_PRIVATE(QCompletionModel) diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp index 8177fb7..26e10ca 100644 --- a/src/gui/util/qdesktopservices.cpp +++ b/src/gui/util/qdesktopservices.cpp @@ -53,6 +53,8 @@ #include "qdesktopservices_win.cpp" #elif defined(Q_WS_MAC) #include "qdesktopservices_mac.cpp" +#elif defined(Q_OS_SYMBIAN) +#include "qdesktopservices_s60.cpp" #endif #include <qhash.h> @@ -286,6 +288,12 @@ void QDesktopServices::unsetUrlHandler(const QString &scheme) \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. + \note On Symbian OS, ApplicationsLocation always point /sys/bin folder on the same drive + with executable. FontsLocation always points to folder on ROM drive. Symbian OS does not + have desktop concept, DesktopLocation returns same path as DocumentsLocation. + Rest of the standard locations point to folder on same drive with executable, except + that if executable is in ROM the folder from C drive is returned. + \note On Mac OS X, DataLocation does not include QCoreApplication::organizationName. Use code like this to add it: diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp new file mode 100644 index 0000000..09411e1 --- /dev/null +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -0,0 +1,440 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This flag changes the implementation to use S60 CDcoumentHandler +// instead of apparch when opening the files +#undef USE_DOCUMENTHANDLER + +#include <qcoreapplication.h> +#include <qdir.h> +#include <qurl.h> +#include <private/qcore_symbian_p.h> + +#include <miutset.h> // KUidMsgTypeSMTP +#include <txtrich.h> // CRichText +#include <f32file.h> // TDriveUnit etc +#include <eikenv.h> // CEikonEnv +#include <apgcli.h> // RApaLsSession +#include <apgtask.h> // TApaTaskList, TApaTask +#include <rsendas.h> // RSendAs +#include <rsendasmessage.h> // RSendAsMessage + +#ifdef Q_WS_S60 +# include <pathinfo.h> // PathInfo +# ifdef USE_DOCUMENTHANDLER +# include <documenthandler.h> // CDocumentHandler +# endif +#elif defined(USE_DOCUMENTHANDLER) +# error CDocumentHandler requires support for S60 +#endif + +QT_BEGIN_NAMESPACE + +_LIT(KCacheSubDir, "Cache\\"); +_LIT(KSysBin, "\\Sys\\Bin\\"); +_LIT(KTempDir, "\\System\\Temp\\"); +_LIT(KBrowserPrefix, "4 " ); +_LIT(KFontsDir, "z:\\resource\\Fonts\\"); +const TUid KUidBrowser = { 0x10008D39 }; + +template<class R> +class QAutoClose +{ +public: + QAutoClose(R& aObj) : mPtr(&aObj) {} + ~QAutoClose() + { + if (mPtr) + mPtr->Close(); + } + void Forget() + { + mPtr = 0; + } +private: + QAutoClose(const QAutoClose&); + QAutoClose& operator=(const QAutoClose&); +private: + R* mPtr; +}; + +static void handleMailtoSchemeLX(const QUrl &url) +{ + // this function has many intermingled leaves and throws. Qt and Symbian objects do not have + // destructor dependencies, and cleanup object is used to prevent cleanup stack dependency on stack. + 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(",", QString::SkipEmptyParts); + QStringList tos = to.split(",", QString::SkipEmptyParts); + QStringList ccs = cc.split(",", QString::SkipEmptyParts); + QStringList bccs = bcc.split(",", QString::SkipEmptyParts); + + + RSendAs sendAs; + User::LeaveIfError(sendAs.Connect()); + QAutoClose<RSendAs> sendAsCleanup(sendAs); + + + CSendAsAccounts* accounts = CSendAsAccounts::NewL(); + CleanupStack::PushL(accounts); + sendAs.AvailableAccountsL(KUidMsgTypeSMTP, *accounts); + TInt count = accounts->Count(); + CleanupStack::PopAndDestroy(accounts); + + if(!count) { + // TODO: Task 259192: We should try to create account if count == 0 + // CSendUi would provide account creation service for us, but it requires ridicilous + // capabilities: LocalServices NetworkServices ReadDeviceData ReadUserData WriteDeviceData WriteUserData + User::Leave(KErrNotSupported); + } else { + RSendAsMessage sendAsMessage; + sendAsMessage.CreateL(sendAs, KUidMsgTypeSMTP); + QAutoClose<RSendAsMessage> sendAsMessageCleanup(sendAsMessage); + + + // Subject + sendAsMessage.SetSubjectL(qt_QString2TPtrC(subject)); + + // Body + sendAsMessage.SetBodyTextL(qt_QString2TPtrC(body)); + + // To + foreach(QString item, recipients) + sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientTo); + + foreach(QString item, tos) + sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientTo); + + // Cc + foreach(QString item, ccs) + sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientCc); + + // Bcc + foreach(QString item, bccs) + sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientBcc); + + // send the message + sendAsMessage.LaunchEditorAndCloseL(); + // sendAsMessage is already closed + sendAsMessageCleanup.Forget(); + } +} + +static bool handleMailtoScheme(const QUrl &url) +{ + TRAPD(err, QT_TRYCATCH_LEAVING(handleMailtoSchemeLX(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<RApaLsSession>(appArcSession); + TThreadId id; + appArcSession.StartDocument(*buf16, KUidBrowser, id); + CleanupStack::PopAndDestroy(); // appArcSession + } + + CleanupStack::PopAndDestroy(buf16); +} + +static bool handleOtherSchemes(const QUrl &url) +{ + QString encUrl(url.toEncoded()); + TPtrC urlPtr(qt_QString2TPtrC(encUrl)); + TRAPD( err, handleOtherSchemesL(urlPtr)); + 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(); +#ifdef Q_WS_S60 + 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: + return PathInfo::PhoneMemoryRootPath(); + break; + } +#else +#warning No fallback implementation of writableDataRoot() + return 0; +#endif +} + +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<RApaLsSession>(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; + + QString urlString(url.toString()); + TPtrC urlPtr(qt_QString2TPtrC(urlString)); + TRAPD( err, handleUrlL(urlPtr)); + 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); + TPtrC filePathPtr(qt_QString2TPtrC(filePath)); + TRAPD(err, openDocumentL(filePathPtr)); + return err ? false : true; +} + +QString QDesktopServices::storageLocation(StandardLocation type) +{ + TFileName path; + + switch (type) { + case DesktopLocation: + qWarning("No desktop concept in Symbian OS"); + // But lets still use some feasible default + path.Append(writableDataRoot()); + 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()); +#ifdef Q_WS_S60 + path.Append(PathInfo::SoundsPath()); +#endif + break; + case MoviesLocation: + path.Append(writableDataRoot()); +#ifdef Q_WS_S60 + path.Append(PathInfo::VideosPath()); +#endif + break; + case PicturesLocation: + path.Append(writableDataRoot()); +#ifdef Q_WS_S60 + path.Append(PathInfo::ImagesPath()); +#endif + 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); + path.Insert(0, writableExeDrive().Name()); + break; + case CacheLocation: + CEikonEnv::Static()->FsSession().PrivatePath(path); + path.Insert(0, writableExeDrive().Name()); + path.Append(KCacheSubDir); + break; + default: + // Lets use feasible default + path.Append(writableDataRoot()); + 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<LocalizerFunc> + (qt_resolveS60PluginFunc(S60Plugin_LocalizedDirectoryName)); + if (!ptrLocalizerFunc) + ptrLocalizerFunc = &defaultLocalizedDirectoryName; + } + + QString rawPath = storageLocation(type); + return ptrLocalizerFunc(rawPath); +} + + +QT_END_NAMESPACE diff --git a/src/gui/util/util.pri b/src/gui/util/util.pri index e628229..cdbb7cc 100644 --- a/src/gui/util/util.pri +++ b/src/gui/util/util.pri @@ -38,3 +38,8 @@ embedded { !embedded:!x11:mac { OBJECTIVE_SOURCES += util/qsystemtrayicon_mac.mm } + +symbian { + LIBS += -lsendas2 -letext -lapmime + contains(QT_CONFIG, s60): LIBS += -lplatformenv -lcommonui +} |