1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qdesktopservices.h"
44 #ifndef QT_NO_DESKTOPSERVICES
48 #include <qstandardpaths.h>
51 #include <qcoreapplication.h>
52 #include <private/qguiapplication_p.h>
55 #include <qplatformservices_qpa.h>
56 #include <qplatformintegration_qpa.h>
61 class QOpenUrlHandlerRegistry : public QObject
65 inline QOpenUrlHandlerRegistry() : mutex(QMutex::Recursive) {}
74 typedef QHash<QString, Handler> HandlerHash;
78 void handlerDestroyed(QObject *handler);
82 Q_GLOBAL_STATIC(QOpenUrlHandlerRegistry, handlerRegistry)
84 void QOpenUrlHandlerRegistry::handlerDestroyed(QObject *handler)
86 HandlerHash::Iterator it = handlers.begin();
87 while (it != handlers.end()) {
88 if (it->receiver == handler) {
89 it = handlers.erase(it);
97 \class QDesktopServices
98 \brief The QDesktopServices class provides methods for accessing common desktop services.
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.
106 This class contains functions that provide simple interfaces to these services
107 that indicate whether they succeeded or failed.
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.
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.
119 \section1 URL Handlers
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.
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.
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.
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:
138 \snippet doc/src/snippets/code/src_gui_util_qdesktopservices.cpp 0
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.
145 \sa QSystemTrayIcon, QProcess
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.
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.
155 The following example opens a file on the Windows file system residing on a path
156 that contains spaces:
158 \snippet doc/src/snippets/code/src_gui_util_qdesktopservices.cpp 2
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.
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}):
167 \snippet doc/src/snippets/code/src_gui_util_qdesktopservices.cpp 1
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.
175 bool QDesktopServices::openUrl(const QUrl &url)
177 QOpenUrlHandlerRegistry *registry = handlerRegistry();
178 QMutexLocker locker(®istry->mutex);
179 static bool insideOpenUrlHandler = false;
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
192 QPlatformServices *platformServices = QGuiApplicationPrivate::platformIntegration()->services();
193 if (!platformServices) {
194 qWarning("%s: The platform plugin does not support services.", Q_FUNC_INFO);
197 return url.scheme() == QStringLiteral("file") ?
198 platformServices->openDocument(url) : platformServices->openUrl(url);
202 Sets the handler for the given \a scheme to be the handler \a method provided by
203 the \a receiver object.
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
210 The provided method must be implemented as a slot that only accepts a single QUrl
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.
218 Note that the handler will always be called from within the same thread that
219 calls QDesktopServices::openUrl().
221 \sa openUrl(), unsetUrlHandler()
223 void QDesktopServices::setUrlHandler(const QString &scheme, QObject *receiver, const char *method)
225 QOpenUrlHandlerRegistry *registry = handlerRegistry();
226 QMutexLocker locker(®istry->mutex);
228 registry->handlers.remove(scheme);
231 QOpenUrlHandlerRegistry::Handler h;
232 h.receiver = receiver;
234 registry->handlers.insert(scheme, h);
235 QObject::connect(receiver, SIGNAL(destroyed(QObject*)),
236 registry, SLOT(handlerDestroyed(QObject*)));
240 Removes a previously set URL handler for the specified \a scheme.
244 void QDesktopServices::unsetUrlHandler(const QString &scheme)
246 setUrlHandler(scheme, 0, 0);
250 \enum QDesktopServices::StandardLocation
253 This enum describes the different locations that can be queried by
254 QDesktopServices::storageLocation and QDesktopServices::displayName.
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
269 \value CacheLocation Returns a directory location where user-specific
270 non-essential (cached) data should be written.
272 \sa storageLocation() displayName()
276 \fn QString QDesktopServices::storageLocation(StandardLocation type)
278 Use QStandardPaths::writableLocation()
282 \fn QString QDesktopServices::displayName(StandardLocation type)
284 Use QStandardPaths::displayName()
287 extern Q_CORE_EXPORT QString qt_applicationName_noFallback();
289 QString QDesktopServices::storageLocationImpl(QStandardPaths::StandardLocation type)
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;
304 #elif defined(Q_OS_UNIX)
305 return baseDir + QLatin1String("/data/")
306 + QCoreApplication::organizationName() + QLatin1Char('/')
310 return QStandardPaths::writableLocation(type);
315 #include "qdesktopservices.moc"
317 #endif // QT_NO_DESKTOPSERVICES