a941c060310903a96f1abc4eb00e5c480256e20f
[profile/ivi/qtbase.git] / src / gui / util / qdesktopservices.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdesktopservices.h"
43
44 #ifndef QT_NO_DESKTOPSERVICES
45
46 #include <qdebug.h>
47
48 #include <qstandardpaths.h>
49 #include <qhash.h>
50 #include <qobject.h>
51 #include <qcoreapplication.h>
52 #include <private/qguiapplication_p.h>
53 #include <qurl.h>
54 #include <qmutex.h>
55 #include <qplatformservices_qpa.h>
56 #include <qplatformintegration_qpa.h>
57 #include <qdir.h>
58
59 QT_BEGIN_NAMESPACE
60
61 class QOpenUrlHandlerRegistry : public QObject
62 {
63     Q_OBJECT
64 public:
65     inline QOpenUrlHandlerRegistry() : mutex(QMutex::Recursive) {}
66
67     QMutex mutex;
68
69     struct Handler
70     {
71         QObject *receiver;
72         QByteArray name;
73     };
74     typedef QHash<QString, Handler> HandlerHash;
75     HandlerHash handlers;
76
77 public Q_SLOTS:
78     void handlerDestroyed(QObject *handler);
79
80 };
81
82 Q_GLOBAL_STATIC(QOpenUrlHandlerRegistry, handlerRegistry)
83
84 void QOpenUrlHandlerRegistry::handlerDestroyed(QObject *handler)
85 {
86     HandlerHash::Iterator it = handlers.begin();
87     while (it != handlers.end()) {
88         if (it->receiver == handler) {
89             it = handlers.erase(it);
90         } else {
91             ++it;
92         }
93     }
94 }
95
96 /*!
97     \class QDesktopServices
98     \brief The QDesktopServices class provides methods for accessing common desktop services.
99     \since 4.2
100     \ingroup desktop
101
102     Many desktop environments provide services that can be used by applications to
103     perform common tasks, such as opening a web page, in a way that is both consistent
104     and takes into account the user's application preferences.
105
106     This class contains functions that provide simple interfaces to these services
107     that indicate whether they succeeded or failed.
108
109     The openUrl() function is used to open files located at arbitrary URLs in external
110     applications. For URLs that correspond to resources on the local filing system
111     (where the URL scheme is "file"), a suitable application will be used to open the
112     file; otherwise, a web browser will be used to fetch and display the file.
113
114     The user's desktop settings control whether certain executable file types are
115     opened for browsing, or if they are executed instead. Some desktop environments
116     are configured to prevent users from executing files obtained from non-local URLs,
117     or to ask the user's permission before doing so.
118
119     \section1 URL Handlers
120
121     The behavior of the openUrl() function can be customized for individual URL
122     schemes to allow applications to override the default handling behavior for
123     certain types of URLs.
124
125     The dispatch mechanism allows only one custom handler to be used for each URL
126     scheme; this is set using the setUrlHandler() function. Each handler is
127     implemented as a slot which accepts only a single QUrl argument.
128
129     The existing handlers for each scheme can be removed with the
130     unsetUrlHandler() function. This returns the handling behavior for the given
131     scheme to the default behavior.
132
133     This system makes it easy to implement a help system, for example. Help could be
134     provided in labels and text browsers using \gui{help://myapplication/mytopic}
135     URLs, and by registering a handler it becomes possible to display the help text
136     inside the application:
137
138     \snippet doc/src/snippets/code/src_gui_util_qdesktopservices.cpp 0
139
140     If inside the handler you decide that you can't open the requested
141     URL, you can just call QDesktopServices::openUrl() again with the
142     same argument, and it will try to open the URL using the
143     appropriate mechanism for the user's desktop environment.
144
145     \sa QSystemTrayIcon, QProcess
146 */
147
148 /*!
149     Opens the given \a url in the appropriate Web browser for the user's desktop
150     environment, and returns true if successful; otherwise returns false.
151
152     If the URL is a reference to a local file (i.e., the URL scheme is "file") then
153     it will be opened with a suitable application instead of a Web browser.
154
155     The following example opens a file on the Windows file system residing on a path
156     that contains spaces:
157
158     \snippet doc/src/snippets/code/src_gui_util_qdesktopservices.cpp 2
159
160     If a \c mailto URL is specified, the user's e-mail client will be used to open a
161     composer window containing the options specified in the URL, similar to the way
162     \c mailto links are handled by a Web browser.
163
164     For example, the following URL contains a recipient (\c{user@foo.com}), a
165     subject (\c{Test}), and a message body (\c{Just a test}):
166
167     \snippet doc/src/snippets/code/src_gui_util_qdesktopservices.cpp 1
168
169     \warning Although many e-mail clients can send attachments and are
170     Unicode-aware, the user may have configured their client without these features.
171     Also, certain e-mail clients (e.g., Lotus Notes) have problems with long URLs.
172
173     \sa setUrlHandler()
174 */
175 bool QDesktopServices::openUrl(const QUrl &url)
176 {
177     QOpenUrlHandlerRegistry *registry = handlerRegistry();
178     QMutexLocker locker(&registry->mutex);
179     static bool insideOpenUrlHandler = false;
180
181     if (!insideOpenUrlHandler) {
182         QOpenUrlHandlerRegistry::HandlerHash::ConstIterator handler = registry->handlers.constFind(url.scheme());
183         if (handler != registry->handlers.constEnd()) {
184             insideOpenUrlHandler = true;
185             bool result = QMetaObject::invokeMethod(handler->receiver, handler->name.constData(), Qt::DirectConnection, Q_ARG(QUrl, url));
186             insideOpenUrlHandler = false;
187             return result; // ### support bool slot return type
188         }
189     }
190     if (!url.isValid())
191         return false;
192     QPlatformServices *platformServices = QGuiApplicationPrivate::platformIntegration()->services();
193     if (!platformServices) {
194         qWarning("%s: The platform plugin does not support services.", Q_FUNC_INFO);
195         return false;
196     }
197     return url.scheme() == QStringLiteral("file") ?
198            platformServices->openDocument(url) : platformServices->openUrl(url);
199 }
200
201 /*!
202     Sets the handler for the given \a scheme to be the handler \a method provided by
203     the \a receiver object.
204
205     This function provides a way to customize the behavior of openUrl(). If openUrl()
206     is called with a URL with the specified \a scheme then the given \a method on the
207     \a receiver object is called instead of QDesktopServices launching an external
208     application.
209
210     The provided method must be implemented as a slot that only accepts a single QUrl
211     argument.
212
213     If setUrlHandler() is used to set a new handler for a scheme which already
214     has a handler, the existing handler is simply replaced with the new one.
215     Since QDesktopServices does not take ownership of handlers, no objects are
216     deleted when a handler is replaced.
217
218     Note that the handler will always be called from within the same thread that
219     calls QDesktopServices::openUrl().
220
221     \sa openUrl(), unsetUrlHandler()
222 */
223 void QDesktopServices::setUrlHandler(const QString &scheme, QObject *receiver, const char *method)
224 {
225     QOpenUrlHandlerRegistry *registry = handlerRegistry();
226     QMutexLocker locker(&registry->mutex);
227     if (!receiver) {
228         registry->handlers.remove(scheme);
229         return;
230     }
231     QOpenUrlHandlerRegistry::Handler h;
232     h.receiver = receiver;
233     h.name = method;
234     registry->handlers.insert(scheme, h);
235     QObject::connect(receiver, SIGNAL(destroyed(QObject*)),
236                      registry, SLOT(handlerDestroyed(QObject*)));
237 }
238
239 /*!
240     Removes a previously set URL handler for the specified \a scheme.
241
242     \sa setUrlHandler()
243 */
244 void QDesktopServices::unsetUrlHandler(const QString &scheme)
245 {
246     setUrlHandler(scheme, 0, 0);
247 }
248
249 /*!
250     \enum QDesktopServices::StandardLocation
251     \since 4.4
252
253     This enum describes the different locations that can be queried by
254     QDesktopServices::storageLocation and QDesktopServices::displayName.
255
256     \value DesktopLocation Returns the user's desktop directory.
257     \value DocumentsLocation Returns the user's document.
258     \value FontsLocation Returns the user's fonts.
259     \value ApplicationsLocation Returns the user's applications.
260     \value MusicLocation Returns the users music.
261     \value MoviesLocation Returns the user's movies.
262     \value PicturesLocation Returns the user's pictures.
263     \value TempLocation Returns the system's temporary directory.
264     \value HomeLocation Returns the user's home directory.
265     \value DataLocation Returns a directory location where persistent
266            application data can be stored. QCoreApplication::applicationName
267            and QCoreApplication::organizationName should work on all
268            platforms.
269     \value CacheLocation Returns a directory location where user-specific
270            non-essential (cached) data should be written.
271
272     \sa storageLocation() displayName()
273 */
274
275 /*!
276     \fn QString QDesktopServices::storageLocation(StandardLocation type)
277     \obsolete
278     Use QStandardPaths::writableLocation()
279 */
280
281 /*!
282     \fn QString QDesktopServices::displayName(StandardLocation type)
283     \obsolete
284     Use QStandardPaths::displayName()
285 */
286
287 extern Q_CORE_EXPORT QString qt_applicationName_noFallback();
288
289 QString QDesktopServices::storageLocationImpl(QStandardPaths::StandardLocation type)
290 {
291     if (type == QStandardPaths::DataLocation) {
292         // Preserve Qt 4 compatibility:
293         // * QCoreApplication::applicationName() must default to empty
294         // * Unix data location is under the "data/" subdirectory
295         const QString compatAppName = qt_applicationName_noFallback();
296         const QString baseDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
297 #if defined(Q_OS_WIN) || defined(Q_OS_MAC)
298         QString result = baseDir;
299         if (!QCoreApplication::organizationName().isEmpty())
300             result += QLatin1Char('/') + QCoreApplication::organizationName();
301         if (!compatAppName.isEmpty())
302             result += QLatin1Char('/') + compatAppName;
303         return result;
304 #elif defined(Q_OS_UNIX)
305         return baseDir + QLatin1String("/data/")
306             + QCoreApplication::organizationName() + QLatin1Char('/')
307             + compatAppName;
308 #endif
309     }
310     return QStandardPaths::writableLocation(type);
311 }
312
313 QT_END_NAMESPACE
314
315 #include "qdesktopservices.moc"
316
317 #endif // QT_NO_DESKTOPSERVICES