source: trunk/src/gui/util/qdesktopservices_s60.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 14.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42
43#include <qcoreapplication.h>
44#include <qdir.h>
45#include <qurl.h>
46#include <private/qcore_symbian_p.h>
47
48#include <f32file.h> // TDriveUnit etc
49#include <pathinfo.h> // PathInfo
50
51#ifndef USE_SCHEMEHANDLER
52#ifdef Q_WS_S60
53// This flag changes the implementation to use S60 CDcoumentHandler
54// instead of apparc when opening the files
55#define USE_DOCUMENTHANDLER
56#endif
57
58#include <txtrich.h> // CRichText
59#include <eikenv.h> // CEikonEnv
60#include <apgcli.h> // RApaLsSession
61#include <apgtask.h> // TApaTaskList, TApaTask
62#include <rsendas.h> // RSendAs
63#include <rsendasmessage.h> // RSendAsMessage
64
65#ifdef USE_DOCUMENTHANDLER
66#include <DocumentHandler.h> // CDocumentHandler
67#include <AknServerApp.h>
68#endif
69#else // USE_SCHEMEHANDLER
70#include <schemehandler.h>
71#endif
72
73QT_BEGIN_NAMESPACE
74
75_LIT(KCacheSubDir, "Cache\\");
76_LIT(KSysBin, "\\Sys\\Bin\\");
77_LIT(KBrowserPrefix, "4 " );
78_LIT(KFontsDir, "z:\\resource\\Fonts\\");
79
80#ifndef USE_SCHEMEHANDLER
81// copied from miutset.h, so we don't get a dependency into the app layer
82const TUid KUidMsgTypeSMTP = {0x10001028}; // 268439592
83const TUid KUidBrowser = { 0x10008D39 };
84
85template<class R>
86class QAutoClose
87{
88public:
89 QAutoClose(R& aObj) : mPtr(&aObj) {}
90 ~QAutoClose()
91 {
92 if (mPtr)
93 mPtr->Close();
94 }
95 void Forget()
96 {
97 mPtr = 0;
98 }
99private:
100 QAutoClose(const QAutoClose&);
101 QAutoClose& operator=(const QAutoClose&);
102private:
103 R* mPtr;
104};
105
106#ifdef USE_DOCUMENTHANDLER
107class QS60DocumentHandler : public MAknServerAppExitObserver
108{
109public:
110 QS60DocumentHandler() :docHandler(0) {}
111
112 ~QS60DocumentHandler() {
113 delete docHandler;
114 }
115
116 CDocumentHandler& documentHandler() {
117 // In case user calls openUrl twice subsequently, before the first embedded app is closed
118 // we use the same CDocumentHandler instance. Using same instance makes sure the first
119 // launched embedded app is closed and latter one gets embedded to our app.
120 // Using different instance would help only theoretically since user cannot interact with
121 // several embedded apps at the same time.
122 if(!docHandler) {
123 QT_TRAP_THROWING(docHandler = CDocumentHandler::NewL());
124 docHandler->SetExitObserver(this);
125 }
126 return *docHandler;
127 }
128
129private: // From MAknServerAppExitObserver
130 void HandleServerAppExit(TInt /*aReason*/) {
131 delete docHandler;
132 docHandler = 0;
133 }
134
135private:
136 CDocumentHandler* docHandler;
137};
138Q_GLOBAL_STATIC(QS60DocumentHandler, qt_s60_documenthandler);
139#endif
140
141static void handleMailtoSchemeLX(const QUrl &url)
142{
143 // this function has many intermingled leaves and throws. Qt and Symbian objects do not have
144 // destructor dependencies, and cleanup object is used to prevent cleanup stack dependency on stack.
145 QString recipient = url.path();
146 QString subject = url.queryItemValue(QLatin1String("subject"));
147 QString body = url.queryItemValue(QLatin1String("body"));
148 QString to = url.queryItemValue(QLatin1String("to"));
149 QString cc = url.queryItemValue(QLatin1String("cc"));
150 QString bcc = url.queryItemValue(QLatin1String("bcc"));
151
152 // these fields might have comma separated addresses
153 QStringList recipients = recipient.split(QLatin1String(","), QString::SkipEmptyParts);
154 QStringList tos = to.split(QLatin1String(","), QString::SkipEmptyParts);
155 QStringList ccs = cc.split(QLatin1String(","), QString::SkipEmptyParts);
156 QStringList bccs = bcc.split(QLatin1String(","), QString::SkipEmptyParts);
157
158 RSendAs sendAs;
159 User::LeaveIfError(sendAs.Connect());
160 QAutoClose<RSendAs> sendAsCleanup(sendAs);
161
162 CSendAsAccounts* accounts = CSendAsAccounts::NewL();
163 CleanupStack::PushL(accounts);
164 sendAs.AvailableAccountsL(KUidMsgTypeSMTP, *accounts);
165 TInt count = accounts->Count();
166 CleanupStack::PopAndDestroy(accounts);
167
168 if(!count) {
169 // TODO: Task 259192: We should try to create account if count == 0
170 // CSendUi would provide account creation service for us, but it requires ridicilous
171 // capabilities: LocalServices NetworkServices ReadDeviceData ReadUserData WriteDeviceData WriteUserData
172 User::Leave(KErrNotSupported);
173 } else {
174 RSendAsMessage sendAsMessage;
175 sendAsMessage.CreateL(sendAs, KUidMsgTypeSMTP);
176 QAutoClose<RSendAsMessage> sendAsMessageCleanup(sendAsMessage);
177
178
179 // Subject
180 sendAsMessage.SetSubjectL(qt_QString2TPtrC(subject));
181
182 // Body
183 sendAsMessage.SetBodyTextL(qt_QString2TPtrC(body));
184
185 // To
186 foreach(QString item, recipients)
187 sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientTo);
188
189 foreach(QString item, tos)
190 sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientTo);
191
192 // Cc
193 foreach(QString item, ccs)
194 sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientCc);
195
196 // Bcc
197 foreach(QString item, bccs)
198 sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientBcc);
199
200 // send the message
201 sendAsMessage.LaunchEditorAndCloseL();
202 // sendAsMessage is already closed
203 sendAsMessageCleanup.Forget();
204 }
205}
206
207static bool handleMailtoScheme(const QUrl &url)
208{
209 TRAPD(err, QT_TRYCATCH_LEAVING(handleMailtoSchemeLX(url)));
210 return err ? false : true;
211}
212
213static void handleOtherSchemesL(const TDesC& aUrl)
214{
215 // Other schemes are at the moment passed to WEB browser
216 HBufC* buf16 = HBufC::NewLC(aUrl.Length() + KBrowserPrefix.iTypeLength);
217 buf16->Des().Copy(KBrowserPrefix); // Prefix used to launch correct browser view
218 buf16->Des().Append(aUrl);
219
220 TApaTaskList taskList(CEikonEnv::Static()->WsSession());
221 TApaTask task = taskList.FindApp(KUidBrowser);
222 if (task.Exists()){
223 // Switch to existing browser instance
224 task.BringToForeground();
225 HBufC8* param8 = HBufC8::NewLC(buf16->Length());
226 param8->Des().Append(buf16->Des());
227 task.SendMessage(TUid::Uid( 0 ), *param8); // Uid is not used
228 CleanupStack::PopAndDestroy(param8);
229 } else {
230 // Start a new browser instance
231 RApaLsSession appArcSession;
232 User::LeaveIfError(appArcSession.Connect());
233 CleanupClosePushL<RApaLsSession>(appArcSession);
234 TThreadId id;
235 appArcSession.StartDocument(*buf16, KUidBrowser, id);
236 CleanupStack::PopAndDestroy(); // appArcSession
237 }
238
239 CleanupStack::PopAndDestroy(buf16);
240}
241
242static bool handleOtherSchemes(const QUrl &url)
243{
244 QString encUrl(QString::fromUtf8(url.toEncoded()));
245 TPtrC urlPtr(qt_QString2TPtrC(encUrl));
246 TRAPD( err, handleOtherSchemesL(urlPtr));
247 return err ? false : true;
248}
249
250
251static void openDocumentL(const TDesC& aUrl)
252{
253#ifndef USE_DOCUMENTHANDLER
254 // Start app associated to file MIME type by using RApaLsSession
255 // Apparc base method cannot be used to open app in embedded mode,
256 // but seems to be most stable way at the moment
257 RApaLsSession appArcSession;
258 User::LeaveIfError(appArcSession.Connect());
259 CleanupClosePushL<RApaLsSession>(appArcSession);
260 TThreadId id;
261 // ESwitchFiles means do not start another instance
262 // Leaves if file does not exist, leave is trapped in openDocument and false returned to user.
263 User::LeaveIfError(appArcSession.StartDocument(aUrl, id,
264 RApaLsSession::ESwitchFiles)); // ELaunchNewApp
265 CleanupStack::PopAndDestroy(); // appArcSession
266#else
267 // This is an alternative way to launch app associated to MIME type
268 // CDocumentHandler also supports opening apps in embedded mode.
269 TDataType temp;
270 qt_s60_documenthandler()->documentHandler().OpenFileEmbeddedL(aUrl, temp);
271#endif
272}
273
274static bool launchWebBrowser(const QUrl &url)
275{
276 if (!url.isValid())
277 return false;
278
279 if (url.scheme() == QLatin1String("mailto")) {
280 return handleMailtoScheme(url);
281 }
282 return handleOtherSchemes( url );
283}
284
285static bool openDocument(const QUrl &file)
286{
287 if (!file.isValid())
288 return false;
289
290 QString filePath = file.toLocalFile();
291 filePath = QDir::toNativeSeparators(filePath);
292 TPtrC filePathPtr(qt_QString2TPtrC(filePath));
293 TRAPD(err, openDocumentL(filePathPtr));
294 return err ? false : true;
295}
296
297#else //USE_SCHEMEHANDLER
298// The schemehandler component only exist in private SDK. This implementation
299// exist here just for convenience in case that we need to use it later on
300// The schemehandle based implementation is not yet tested.
301
302// The biggest advantage of schemehandler is that it can handle
303// wide range of schemes and is extensible by plugins
304static void handleUrlL(const TDesC& aUrl)
305{
306 CSchemeHandler* schemeHandler = CSchemeHandler::NewL(aUrl);
307 CleanupStack::PushL(schemeHandler);
308 schemeHandler->HandleUrlStandaloneL(); // Process the Url in standalone mode
309 CleanupStack::PopAndDestroy();
310}
311
312static bool handleUrl(const QUrl &url)
313{
314 if (!url.isValid())
315 return false;
316
317 QString urlString(url.toString());
318 TPtrC urlPtr(qt_QString2TPtrC(urlString));
319 TRAPD( err, handleUrlL(urlPtr));
320 return err ? false : true;
321}
322
323static bool launchWebBrowser(const QUrl &url)
324{
325 return handleUrl(url);
326}
327
328static bool openDocument(const QUrl &file)
329{
330 return handleUrl(file);
331}
332
333#endif //USE_SCHEMEHANDLER
334
335// Common functions to all implementations
336
337static TDriveUnit exeDrive()
338{
339 RProcess me;
340 TFileName processFileName = me.FileName();
341 TDriveUnit drive(processFileName);
342 return drive;
343}
344
345static TDriveUnit writableExeDrive()
346{
347 TDriveUnit drive = exeDrive();
348 if (drive.operator TInt() == EDriveZ)
349 return TDriveUnit(EDriveC);
350 return drive;
351}
352
353static TPtrC writableDataRoot()
354{
355 TDriveUnit drive = exeDrive();
356 switch (drive.operator TInt()){
357 case EDriveC:
358 return PathInfo::PhoneMemoryRootPath();
359 break;
360 case EDriveE:
361 return PathInfo::MemoryCardRootPath();
362 break;
363 case EDriveZ:
364 // It is not possible to write on ROM drive ->
365 // return phone mem root path instead
366 return PathInfo::PhoneMemoryRootPath();
367 break;
368 default:
369 return PathInfo::PhoneMemoryRootPath();
370 break;
371 }
372}
373
374QString QDesktopServices::storageLocation(StandardLocation type)
375{
376 TFileName path;
377
378 switch (type) {
379 case DesktopLocation:
380 qWarning("No desktop concept in Symbian OS");
381 // But lets still use some feasible default
382 path.Append(writableDataRoot());
383 break;
384 case DocumentsLocation:
385 path.Append(writableDataRoot());
386 break;
387 case FontsLocation:
388 path.Append(KFontsDir);
389 break;
390 case ApplicationsLocation:
391 path.Append(exeDrive().Name());
392 path.Append(KSysBin);
393 break;
394 case MusicLocation:
395 path.Append(writableDataRoot());
396 path.Append(PathInfo::SoundsPath());
397 break;
398 case MoviesLocation:
399 path.Append(writableDataRoot());
400 path.Append(PathInfo::VideosPath());
401 break;
402 case PicturesLocation:
403 path.Append(writableDataRoot());
404 path.Append(PathInfo::ImagesPath());
405 break;
406 case TempLocation:
407 return QDir::tempPath();
408 break;
409 case HomeLocation:
410 path.Append(writableDataRoot());
411 //return QDir::homePath(); break;
412 break;
413 case DataLocation:
414 qt_s60GetRFs().PrivatePath(path);
415 path.Insert(0, writableExeDrive().Name());
416 break;
417 case CacheLocation:
418 qt_s60GetRFs().PrivatePath(path);
419 path.Insert(0, writableExeDrive().Name());
420 path.Append(KCacheSubDir);
421 break;
422 default:
423 // Lets use feasible default
424 path.Append(writableDataRoot());
425 break;
426 }
427
428 // Convert to cross-platform format and clean the path
429 QString nativePath = QString::fromUtf16(path.Ptr(), path.Length());
430 QString qtPath = QDir::fromNativeSeparators(nativePath);
431 qtPath = QDir::cleanPath(qtPath);
432
433 // Note: The storage location returned can be a directory that does not exist;
434 // i.e., it may need to be created by the system or the user.
435 return qtPath;
436}
437
438typedef QString (*LocalizerFunc)(QString&);
439
440static QString defaultLocalizedDirectoryName(QString&)
441{
442 return QString();
443}
444
445QString QDesktopServices::displayName(StandardLocation type)
446{
447 static LocalizerFunc ptrLocalizerFunc = NULL;
448
449 if (!ptrLocalizerFunc) {
450 ptrLocalizerFunc = reinterpret_cast<LocalizerFunc>
451 (qt_resolveS60PluginFunc(S60Plugin_LocalizedDirectoryName));
452 if (!ptrLocalizerFunc)
453 ptrLocalizerFunc = &defaultLocalizedDirectoryName;
454 }
455
456 QString rawPath = storageLocation(type);
457 return ptrLocalizerFunc(rawPath);
458}
459
460
461QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.