From e577d02cc9cba2033cd21c23a4420a1f0d5469a4 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sun, 8 May 2011 20:51:18 +0200 Subject: move files in src/gui into their final locations Rename the guikernel subdir to kernel and guiutil to util. --- src/gui/util/qdesktopservices.cpp | 309 ++++++++++++ src/gui/util/qdesktopservices.h | 91 ++++ src/gui/util/qdesktopservices_mac.cpp | 188 +++++++ src/gui/util/qdesktopservices_qpa.cpp | 93 ++++ src/gui/util/qdesktopservices_s60.cpp | 461 +++++++++++++++++ src/gui/util/qdesktopservices_win.cpp | 267 ++++++++++ src/gui/util/qdesktopservices_x11.cpp | 242 +++++++++ src/gui/util/qhexstring_p.h | 98 ++++ src/gui/util/qvalidator.cpp | 925 ++++++++++++++++++++++++++++++++++ src/gui/util/qvalidator.h | 217 ++++++++ src/gui/util/util.pri | 10 + 11 files changed, 2901 insertions(+) create mode 100644 src/gui/util/qdesktopservices.cpp create mode 100644 src/gui/util/qdesktopservices.h create mode 100644 src/gui/util/qdesktopservices_mac.cpp create mode 100644 src/gui/util/qdesktopservices_qpa.cpp create mode 100644 src/gui/util/qdesktopservices_s60.cpp create mode 100644 src/gui/util/qdesktopservices_win.cpp create mode 100644 src/gui/util/qdesktopservices_x11.cpp create mode 100644 src/gui/util/qhexstring_p.h create mode 100644 src/gui/util/qvalidator.cpp create mode 100644 src/gui/util/qvalidator.h create mode 100644 src/gui/util/util.pri (limited to 'src/gui/util') diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp new file mode 100644 index 0000000000..2c2c3308ca --- /dev/null +++ b/src/gui/util/qdesktopservices.cpp @@ -0,0 +1,309 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesktopservices.h" + +#ifndef QT_NO_DESKTOPSERVICES + +#include + +#if defined(Q_WS_QWS) || defined(Q_WS_QPA) +#include "qdesktopservices_qpa.cpp" +#elif defined(Q_WS_X11) +#include "qdesktopservices_x11.cpp" +#elif defined(Q_WS_WIN) +#include "qdesktopservices_win.cpp" +#elif defined(Q_WS_MAC) +#include "qdesktopservices_mac.cpp" +#elif defined(Q_OS_SYMBIAN) +#include "qdesktopservices_s60.cpp" +#endif + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QOpenUrlHandlerRegistry : public QObject +{ + Q_OBJECT +public: + inline QOpenUrlHandlerRegistry() : mutex(QMutex::Recursive) {} + + QMutex mutex; + + struct Handler + { + QObject *receiver; + QByteArray name; + }; + typedef QHash HandlerHash; + HandlerHash handlers; + +public Q_SLOTS: + void handlerDestroyed(QObject *handler); + +}; + +Q_GLOBAL_STATIC(QOpenUrlHandlerRegistry, handlerRegistry) + +void QOpenUrlHandlerRegistry::handlerDestroyed(QObject *handler) +{ + HandlerHash::Iterator it = handlers.begin(); + while (it != handlers.end()) { + if (it->receiver == handler) { + it = handlers.erase(it); + } else { + ++it; + } + } +} + +/*! + \class QDesktopServices + \brief The QDesktopServices class provides methods for accessing common desktop services. + \since 4.2 + \ingroup desktop + + Many desktop environments provide services that can be used by applications to + perform common tasks, such as opening a web page, in a way that is both consistent + and takes into account the user's application preferences. + + This class contains functions that provide simple interfaces to these services + that indicate whether they succeeded or failed. + + The openUrl() function is used to open files located at arbitrary URLs in external + applications. For URLs that correspond to resources on the local filing system + (where the URL scheme is "file"), a suitable application will be used to open the + file; otherwise, a web browser will be used to fetch and display the file. + + The user's desktop settings control whether certain executable file types are + opened for browsing, or if they are executed instead. Some desktop environments + are configured to prevent users from executing files obtained from non-local URLs, + or to ask the user's permission before doing so. + + \section1 URL Handlers + + The behavior of the openUrl() function can be customized for individual URL + schemes to allow applications to override the default handling behavior for + certain types of URLs. + + The dispatch mechanism allows only one custom handler to be used for each URL + scheme; this is set using the setUrlHandler() function. Each handler is + implemented as a slot which accepts only a single QUrl argument. + + The existing handlers for each scheme can be removed with the + unsetUrlHandler() function. This returns the handling behavior for the given + scheme to the default behavior. + + This system makes it easy to implement a help system, for example. Help could be + provided in labels and text browsers using \gui{help://myapplication/mytopic} + URLs, and by registering a handler it becomes possible to display the help text + inside the application: + + \snippet doc/src/snippets/code/src_gui_util_qdesktopservices.cpp 0 + + If inside the handler you decide that you can't open the requested + URL, you can just call QDesktopServices::openUrl() again with the + same argument, and it will try to open the URL using the + appropriate mechanism for the user's desktop environment. + + \sa QSystemTrayIcon, QProcess +*/ + +/*! + Opens the given \a url in the appropriate Web browser for the user's desktop + environment, and returns true if successful; otherwise returns false. + + If the URL is a reference to a local file (i.e., the URL scheme is "file") then + it will be opened with a suitable application instead of a Web browser. + + The following example opens a file on the Windows file system residing on a path + that contains spaces: + + \snippet doc/src/snippets/code/src_gui_util_qdesktopservices.cpp 2 + + If a \c mailto URL is specified, the user's e-mail client will be used to open a + composer window containing the options specified in the URL, similar to the way + \c mailto links are handled by a Web browser. + + For example, the following URL contains a recipient (\c{user@foo.com}), a + subject (\c{Test}), and a message body (\c{Just a test}): + + \snippet doc/src/snippets/code/src_gui_util_qdesktopservices.cpp 1 + + \warning Although many e-mail clients can send attachments and are + Unicode-aware, the user may have configured their client without these features. + Also, certain e-mail clients (e.g., Lotus Notes) have problems with long URLs. + + \sa setUrlHandler() +*/ +bool QDesktopServices::openUrl(const QUrl &url) +{ + QOpenUrlHandlerRegistry *registry = handlerRegistry(); + QMutexLocker locker(®istry->mutex); + static bool insideOpenUrlHandler = false; + + if (!insideOpenUrlHandler) { + QOpenUrlHandlerRegistry::HandlerHash::ConstIterator handler = registry->handlers.constFind(url.scheme()); + if (handler != registry->handlers.constEnd()) { + insideOpenUrlHandler = true; + bool result = QMetaObject::invokeMethod(handler->receiver, handler->name.constData(), Qt::DirectConnection, Q_ARG(QUrl, url)); + insideOpenUrlHandler = false; + return result; // ### support bool slot return type + } + } + + bool result; + if (url.scheme() == QLatin1String("file")) + result = openDocument(url); + else + result = launchWebBrowser(url); + + return result; +} + +/*! + Sets the handler for the given \a scheme to be the handler \a method provided by + the \a receiver object. + + This function provides a way to customize the behavior of openUrl(). If openUrl() + is called with a URL with the specified \a scheme then the given \a method on the + \a receiver object is called instead of QDesktopServices launching an external + application. + + The provided method must be implemented as a slot that only accepts a single QUrl + argument. + + If setUrlHandler() is used to set a new handler for a scheme which already + has a handler, the existing handler is simply replaced with the new one. + Since QDesktopServices does not take ownership of handlers, no objects are + deleted when a handler is replaced. + + Note that the handler will always be called from within the same thread that + calls QDesktopServices::openUrl(). + + \sa openUrl(), unsetUrlHandler() +*/ +void QDesktopServices::setUrlHandler(const QString &scheme, QObject *receiver, const char *method) +{ + QOpenUrlHandlerRegistry *registry = handlerRegistry(); + QMutexLocker locker(®istry->mutex); + if (!receiver) { + registry->handlers.remove(scheme); + return; + } + QOpenUrlHandlerRegistry::Handler h; + h.receiver = receiver; + h.name = method; + registry->handlers.insert(scheme, h); + QObject::connect(receiver, SIGNAL(destroyed(QObject*)), + registry, SLOT(handlerDestroyed(QObject*))); +} + +/*! + Removes a previously set URL handler for the specified \a scheme. + + \sa setUrlHandler() +*/ +void QDesktopServices::unsetUrlHandler(const QString &scheme) +{ + setUrlHandler(scheme, 0, 0); +} + +/*! + \enum QDesktopServices::StandardLocation + \since 4.4 + + This enum describes the different locations that can be queried by + QDesktopServices::storageLocation and QDesktopServices::displayName. + + \value DesktopLocation Returns the user's desktop directory. + \value DocumentsLocation Returns the user's document. + \value FontsLocation Returns the user's fonts. + \value ApplicationsLocation Returns the user's applications. + \value MusicLocation Returns the users music. + \value MoviesLocation Returns the user's movies. + \value PicturesLocation Returns the user's pictures. + \value TempLocation Returns the system's temporary directory. + \value HomeLocation Returns the user's home directory. + \value DataLocation Returns a directory location where persistent + application data can be stored. QCoreApplication::applicationName + and QCoreApplication::organizationName should work on all + platforms. + \value CacheLocation Returns a directory location where user-specific + non-essential (cached) data should be written. + + \sa storageLocation() displayName() +*/ + +/*! + \fn QString QDesktopServices::storageLocation(StandardLocation type) + \since 4.4 + + Returns the default system directory where files of \a type belong, or an empty string + if the location cannot be determined. + + \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. +*/ + +/*! + \fn QString QDesktopServices::displayName(StandardLocation type) + + Returns a localized display name for the given location \a type or + an empty QString if no relevant location can be found. +*/ + +QT_END_NAMESPACE + +#include "qdesktopservices.moc" + +#endif // QT_NO_DESKTOPSERVICES diff --git a/src/gui/util/qdesktopservices.h b/src/gui/util/qdesktopservices.h new file mode 100644 index 0000000000..9d5657ecca --- /dev/null +++ b/src/gui/util/qdesktopservices.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESKTOPSERVICES_H +#define QDESKTOPSERVICES_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_DESKTOPSERVICES + +class QStringList; +class QUrl; +class QObject; + +class Q_GUI_EXPORT QDesktopServices +{ +public: + static bool openUrl(const QUrl &url); + static void setUrlHandler(const QString &scheme, QObject *receiver, const char *method); + static void unsetUrlHandler(const QString &scheme); + + enum StandardLocation { + DesktopLocation, + DocumentsLocation, + FontsLocation, + ApplicationsLocation, + MusicLocation, + MoviesLocation, + PicturesLocation, + TempLocation, + HomeLocation, + DataLocation, + CacheLocation + }; + + static QString storageLocation(StandardLocation type); + static QString displayName(StandardLocation type); +}; + +#endif // QT_NO_DESKTOPSERVICES + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDESKTOPSERVICES_H + diff --git a/src/gui/util/qdesktopservices_mac.cpp b/src/gui/util/qdesktopservices_mac.cpp new file mode 100644 index 0000000000..e9868471cb --- /dev/null +++ b/src/gui/util/qdesktopservices_mac.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_DESKTOPSERVICES + +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +/* + Translates a QDesktopServices::StandardLocation into the mac equivalent. +*/ +OSType translateLocation(QDesktopServices::StandardLocation type) +{ + switch (type) { + case QDesktopServices::DesktopLocation: + return kDesktopFolderType; break; + + case QDesktopServices::DocumentsLocation: + return kDocumentsFolderType; break; + + case QDesktopServices::FontsLocation: + // There are at least two different font directories on the mac: /Library/Fonts and ~/Library/Fonts. + // To select a specific one we have to specify a different first parameter when calling FSFindFolder. + return kFontsFolderType; break; + + case QDesktopServices::ApplicationsLocation: + return kApplicationsFolderType; break; + + case QDesktopServices::MusicLocation: + return kMusicDocumentsFolderType; break; + + case QDesktopServices::MoviesLocation: + return kMovieDocumentsFolderType; break; + + case QDesktopServices::PicturesLocation: + return kPictureDocumentsFolderType; break; + + case QDesktopServices::TempLocation: + return kTemporaryFolderType; break; + + case QDesktopServices::DataLocation: + return kApplicationSupportFolderType; break; + + case QDesktopServices::CacheLocation: + return kCachedDataFolderType; break; + + default: + return kDesktopFolderType; break; + } +} + +static bool lsOpen(const QUrl &url) +{ + if (!url.isValid() || url.scheme().isEmpty()) + return false; + + QCFType cfUrl = CFURLCreateWithString(0, QCFString(QString::fromLatin1(url.toEncoded())), 0); + if (cfUrl == 0) + return false; + + const OSStatus err = LSOpenCFURLRef(cfUrl, 0); + return (err == noErr); +} + +static bool launchWebBrowser(const QUrl &url) +{ + return lsOpen(url); +} + +static bool openDocument(const QUrl &file) +{ + if (!file.isValid()) + return false; + + // LSOpen does not work in this case, use QProcess open instead. + return QProcess::startDetached(QLatin1String("open"), QStringList() << file.toLocalFile()); +} + +/* + Constructs a full unicode path from a FSRef. +*/ +static QString getFullPath(const FSRef &ref) +{ + QByteArray ba(2048, 0); + if (FSRefMakePath(&ref, reinterpret_cast(ba.data()), ba.size()) == noErr) + return QString::fromUtf8(ba).normalized(QString::NormalizationForm_C); + return QString(); +} + +QString QDesktopServices::storageLocation(StandardLocation type) +{ + if (type == HomeLocation) + return QDir::homePath(); + + if (type == TempLocation) + return QDir::tempPath(); + + short domain = kOnAppropriateDisk; + + if (type == DataLocation || type == CacheLocation) + domain = kUserDomain; + + // http://developer.apple.com/documentation/Carbon/Reference/Folder_Manager/Reference/reference.html + FSRef ref; + OSErr err = FSFindFolder(domain, translateLocation(type), false, &ref); + if (err) + return QString(); + + QString path = getFullPath(ref); + + if (type == DataLocation || type == CacheLocation) { + if (QCoreApplication::organizationName().isEmpty() == false) + path += QLatin1Char('/') + QCoreApplication::organizationName(); + if (QCoreApplication::applicationName().isEmpty() == false) + path += QLatin1Char('/') + QCoreApplication::applicationName(); + } + + return path; +} + +QString QDesktopServices::displayName(StandardLocation type) +{ + if (QDesktopServices::HomeLocation == type) + return QObject::tr("Home"); + + FSRef ref; + OSErr err = FSFindFolder(kOnAppropriateDisk, translateLocation(type), false, &ref); + if (err) + return QString(); + + QCFString displayName; + err = LSCopyDisplayNameForRef(&ref, &displayName); + if (err) + return QString(); + + return static_cast(displayName); +} + +QT_END_NAMESPACE + +#endif // QT_NO_DESKTOPSERVICES diff --git a/src/gui/util/qdesktopservices_qpa.cpp b/src/gui/util/qdesktopservices_qpa.cpp new file mode 100644 index 0000000000..324fa51a62 --- /dev/null +++ b/src/gui/util/qdesktopservices_qpa.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +QT_BEGIN_NAMESPACE + +static bool launchWebBrowser(const QUrl &url) +{ + Q_UNUSED(url); + qWarning("QDesktopServices::launchWebBrowser not implemented"); + return false; +} + +static bool openDocument(const QUrl &file) +{ + Q_UNUSED(file); + qWarning("QDesktopServices::openDocument not implemented"); + return false; +} + + +QString QDesktopServices::storageLocation(StandardLocation type) +{ + if (type == DataLocation) { + QString qwsDataHome = QLatin1String(qgetenv("QWS_DATA_HOME")); + if (qwsDataHome.isEmpty()) + qwsDataHome = QDir::homePath() + QLatin1String("/.qws/share"); + qwsDataHome += QLatin1String("/data/") + + QCoreApplication::organizationName() + QLatin1Char('/') + + QCoreApplication::applicationName(); + return qwsDataHome; + } + if (type == QDesktopServices::CacheLocation) { + QString qwsCacheHome = QLatin1String(qgetenv("QWS_CACHE_HOME")); + if (qwsCacheHome.isEmpty()) + qwsCacheHome = QDir::homePath() + QLatin1String("/.qws/cache/"); + qwsCacheHome += QCoreApplication::organizationName() + QLatin1Char('/') + + QCoreApplication::applicationName(); + return qwsCacheHome; + } + + qWarning("QDesktopServices::storageLocation %d not implemented", type); + return QString(); +} + +QString QDesktopServices::displayName(StandardLocation type) +{ + Q_UNUSED(type); + qWarning("QDesktopServices::displayName not implemented"); + return QString(); +} + +QT_END_NAMESPACE diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp new file mode 100644 index 0000000000..8caeb74fec --- /dev/null +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -0,0 +1,461 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include + +#include // TDriveUnit etc +#include // PathInfo + +#ifndef USE_SCHEMEHANDLER +#ifdef Q_WS_S60 +// This flag changes the implementation to use S60 CDcoumentHandler +// instead of apparc when opening the files +#define USE_DOCUMENTHANDLER +#endif + +#include // CRichText +#include // CEikonEnv +#include // RApaLsSession +#include // TApaTaskList, TApaTask +#include // RSendAs +#include // RSendAsMessage + +#ifdef USE_DOCUMENTHANDLER +#include // CDocumentHandler +#include +#endif +#else // USE_SCHEMEHANDLER +#include +#endif + +QT_BEGIN_NAMESPACE + +_LIT(KCacheSubDir, "Cache\\"); +_LIT(KSysBin, "\\Sys\\Bin\\"); +_LIT(KBrowserPrefix, "4 " ); +_LIT(KFontsDir, "z:\\resource\\Fonts\\"); + +#ifndef USE_SCHEMEHANDLER +// copied from miutset.h, so we don't get a dependency into the app layer +const TUid KUidMsgTypeSMTP = {0x10001028}; // 268439592 +const TUid KUidBrowser = { 0x10008D39 }; + +template +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; +}; + +#ifdef USE_DOCUMENTHANDLER +class QS60DocumentHandler : public MAknServerAppExitObserver +{ +public: + QS60DocumentHandler() :docHandler(0) {} + + ~QS60DocumentHandler() { + delete docHandler; + } + + CDocumentHandler& documentHandler() { + // In case user calls openUrl twice subsequently, before the first embedded app is closed + // we use the same CDocumentHandler instance. Using same instance makes sure the first + // launched embedded app is closed and latter one gets embedded to our app. + // Using different instance would help only theoretically since user cannot interact with + // several embedded apps at the same time. + if(!docHandler) { + QT_TRAP_THROWING(docHandler = CDocumentHandler::NewL()); + docHandler->SetExitObserver(this); + } + return *docHandler; + } + +private: // From MAknServerAppExitObserver + void HandleServerAppExit(TInt /*aReason*/) { + delete docHandler; + docHandler = 0; + } + +private: + CDocumentHandler* docHandler; +}; +Q_GLOBAL_STATIC(QS60DocumentHandler, qt_s60_documenthandler); +#endif + +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(QLatin1String("subject")); + QString body = url.queryItemValue(QLatin1String("body")); + QString to = url.queryItemValue(QLatin1String("to")); + QString cc = url.queryItemValue(QLatin1String("cc")); + QString bcc = url.queryItemValue(QLatin1String("bcc")); + + // these fields might have comma separated addresses + QStringList recipients = recipient.split(QLatin1String(","), QString::SkipEmptyParts); + QStringList tos = to.split(QLatin1String(","), QString::SkipEmptyParts); + QStringList ccs = cc.split(QLatin1String(","), QString::SkipEmptyParts); + QStringList bccs = bcc.split(QLatin1String(","), QString::SkipEmptyParts); + + RSendAs sendAs; + User::LeaveIfError(sendAs.Connect()); + QAutoClose 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 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 + task.BringToForeground(); + 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) +{ + QString encUrl(QString::fromUtf8(url.toEncoded())); + TPtrC urlPtr(qt_QString2TPtrC(encUrl)); + TRAPD( err, handleOtherSchemesL(urlPtr)); + return err ? false : true; +} + + +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 also supports opening apps in embedded mode. + TDataType temp; + qt_s60_documenthandler()->documentHandler().OpenFileEmbeddedL(aUrl, temp); +#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; +} + +#else //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 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 handleUrl(const QUrl &url) +{ + if (!url.isValid()) + return false; + + QString urlString(url.toEncoded()); + TPtrC urlPtr(qt_QString2TPtrC(urlString)); + TRAPD( err, handleUrlL(urlPtr)); + return err ? false : true; +} + +static bool launchWebBrowser(const QUrl &url) +{ + return handleUrl(url); +} + +static bool openDocument(const QUrl &file) +{ + return handleUrl(file); +} + +#endif //USE_SCHEMEHANDLER + +// Common functions to all implementations + +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: + return PathInfo::PhoneMemoryRootPath(); + break; + } +} + +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()); + 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: + return QDir::tempPath(); + break; + case HomeLocation: + path.Append(writableDataRoot()); + //return QDir::homePath(); break; + break; + case DataLocation: + qt_s60GetRFs().PrivatePath(path); + path.Insert(0, writableExeDrive().Name()); + break; + case CacheLocation: + qt_s60GetRFs().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 + (qt_resolveS60PluginFunc(S60Plugin_LocalizedDirectoryName)); + if (!ptrLocalizerFunc) + ptrLocalizerFunc = &defaultLocalizedDirectoryName; + } + + QString rawPath = storageLocation(type); + return ptrLocalizerFunc(rawPath); +} + + +QT_END_NAMESPACE diff --git a/src/gui/util/qdesktopservices_win.cpp b/src/gui/util/qdesktopservices_win.cpp new file mode 100644 index 0000000000..783970ba82 --- /dev/null +++ b/src/gui/util/qdesktopservices_win.cpp @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#if !defined(Q_OS_WINCE) +# include +#else +# include +# if !defined(STANDARDSHELL_UI_MODEL) +# include +# endif +#endif + +#ifndef CSIDL_MYMUSIC +#define CSIDL_MYMUSIC 13 +#define CSIDL_MYVIDEO 14 +#endif + +#ifndef QT_NO_DESKTOPSERVICES + +QT_BEGIN_NAMESPACE + +static bool openDocument(const QUrl &file) +{ + if (!file.isValid()) + return false; + QString filePath = file.toLocalFile(); + if (filePath.isEmpty()) + filePath = file.toString(); + quintptr returnValue = (quintptr)ShellExecute(0, 0, (wchar_t*)filePath.utf16(), 0, 0, SW_SHOWNORMAL); + return (returnValue > 32); //ShellExecute returns a value greater than 32 if successful +} + +static QString expandEnvStrings(const QString &command) +{ +#if defined(Q_OS_WINCE) + return command; +#else + wchar_t buffer[MAX_PATH]; + if (ExpandEnvironmentStrings((wchar_t*)command.utf16(), buffer, MAX_PATH)) + return QString::fromWCharArray(buffer); + else + return command; +#endif +} + +static bool launchWebBrowser(const QUrl &url) +{ + if (url.scheme() == QLatin1String("mailto")) { + //Retrieve the commandline for the default mail client + //the default key used below is the command line for the mailto: shell command + DWORD bufferSize = sizeof(wchar_t) * MAX_PATH; + long returnValue = -1; + QString command; + + HKEY handle; + LONG res; + wchar_t keyValue[MAX_PATH] = {0}; + QString keyName(QLatin1String("mailto")); + + //Check if user has set preference, otherwise use default. + res = RegOpenKeyEx(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\mailto\\UserChoice", + 0, KEY_READ, &handle); + if (res == ERROR_SUCCESS) { + returnValue = RegQueryValueEx(handle, L"Progid", 0, 0, reinterpret_cast(keyValue), &bufferSize); + if (!returnValue) + keyName = QString::fromUtf16((const ushort*)keyValue); + RegCloseKey(handle); + } + keyName += QLatin1String("\\Shell\\Open\\Command"); + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, (const wchar_t*)keyName.utf16(), 0, KEY_READ, &handle); + if (res != ERROR_SUCCESS) + return false; + + bufferSize = sizeof(wchar_t) * MAX_PATH; + returnValue = RegQueryValueEx(handle, L"", 0, 0, reinterpret_cast(keyValue), &bufferSize); + if (!returnValue) + command = QString::fromRawData((QChar*)keyValue, bufferSize); + RegCloseKey(handle); + + if (returnValue) + return false; + + command = expandEnvStrings(command); + command = command.trimmed(); + //Make sure the path for the process is in quotes + int index = -1 ; + if (command[0]!= QLatin1Char('\"')) { + index = command.indexOf(QLatin1String(".exe "), 0, Qt::CaseInsensitive); + command.insert(index+4, QLatin1Char('\"')); + command.insert(0, QLatin1Char('\"')); + } + //pass the url as the parameter + index = command.lastIndexOf(QLatin1String("%1")); + if (index != -1){ + command.replace(index, 2, url.toString()); + } + //start the process + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(pi)); + STARTUPINFO si; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + + returnValue = CreateProcess(NULL, (wchar_t*)command.utf16(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + + if (!returnValue) + return false; + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return true; + } + + if (!url.isValid()) + return false; + + if (url.scheme().isEmpty()) + return openDocument(url); + + quintptr returnValue = (quintptr)ShellExecute(0, 0, (wchar_t *)QString::fromUtf8(url.toEncoded().constData()).utf16(), + 0, 0, SW_SHOWNORMAL); + return (returnValue > 32); +} + +QString QDesktopServices::storageLocation(StandardLocation type) +{ + QString result; + +#ifndef Q_OS_WINCE + QSystemLibrary library(QLatin1String("shell32")); +#else + QSystemLibrary library(QLatin1String("coredll")); +#endif // Q_OS_WINCE + typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPWSTR, int, BOOL); + static GetSpecialFolderPath SHGetSpecialFolderPath = + (GetSpecialFolderPath)library.resolve("SHGetSpecialFolderPathW"); + if (!SHGetSpecialFolderPath) + return QString(); + + wchar_t path[MAX_PATH]; + + switch (type) { + case DataLocation: +#if defined Q_WS_WINCE + if (SHGetSpecialFolderPath(0, path, CSIDL_APPDATA, FALSE)) +#else + if (SHGetSpecialFolderPath(0, path, CSIDL_LOCAL_APPDATA, FALSE)) +#endif + result = QString::fromWCharArray(path); + if (!QCoreApplication::organizationName().isEmpty()) + result = result + QLatin1String("\\") + QCoreApplication::organizationName(); + if (!QCoreApplication::applicationName().isEmpty()) + result = result + QLatin1String("\\") + QCoreApplication::applicationName(); + break; + + case DesktopLocation: + if (SHGetSpecialFolderPath(0, path, CSIDL_DESKTOPDIRECTORY, FALSE)) + result = QString::fromWCharArray(path); + break; + + case DocumentsLocation: + if (SHGetSpecialFolderPath(0, path, CSIDL_PERSONAL, FALSE)) + result = QString::fromWCharArray(path); + break; + + case FontsLocation: + if (SHGetSpecialFolderPath(0, path, CSIDL_FONTS, FALSE)) + result = QString::fromWCharArray(path); + break; + + case ApplicationsLocation: + if (SHGetSpecialFolderPath(0, path, CSIDL_PROGRAMS, FALSE)) + result = QString::fromWCharArray(path); + break; + + case MusicLocation: + if (SHGetSpecialFolderPath(0, path, CSIDL_MYMUSIC, FALSE)) + result = QString::fromWCharArray(path); + break; + + case MoviesLocation: + if (SHGetSpecialFolderPath(0, path, CSIDL_MYVIDEO, FALSE)) + result = QString::fromWCharArray(path); + break; + + case PicturesLocation: + if (SHGetSpecialFolderPath(0, path, CSIDL_MYPICTURES, FALSE)) + result = QString::fromWCharArray(path); + break; + + case CacheLocation: + // Although Microsoft has a Cache key it is a pointer to IE's cache, not a cache + // location for everyone. Most applications seem to be using a + // cache directory located in their AppData directory + return storageLocation(DataLocation) + QLatin1String("\\cache"); + + case QDesktopServices::HomeLocation: + return QDir::homePath(); break; + + case QDesktopServices::TempLocation: + return QDir::tempPath(); break; + + default: + break; + } + return result; +} + +QString QDesktopServices::displayName(StandardLocation type) +{ + Q_UNUSED(type); + return QString(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_DESKTOPSERVICES diff --git a/src/gui/util/qdesktopservices_x11.cpp b/src/gui/util/qdesktopservices_x11.cpp new file mode 100644 index 0000000000..e685bed0b9 --- /dev/null +++ b/src/gui/util/qdesktopservices_x11.cpp @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesktopservices.h" + +#ifndef QT_NO_DESKTOPSERVICES + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +inline static bool launch(const QUrl &url, const QString &client) +{ +#if !defined(QT_NO_PROCESS) + return (QProcess::startDetached(client + QLatin1Char(' ') + QString::fromLatin1(url.toEncoded().constData()))); +#else + return (::system((client + QLatin1Char(' ') + QString::fromLatin1(url.toEncoded().constData())).toLocal8Bit().constData()) != -1); +#endif +} + +static bool openDocument(const QUrl &url) +{ + if (!url.isValid()) + return false; + + if (launch(url, QLatin1String("xdg-open"))) + return true; + + // Use the X11->desktopEnvironment value if X11 is non-NULL, + // otherwise just attempt to launch command regardless of the desktop environment + if ((!X11 || (X11 && X11->desktopEnvironment == DE_GNOME)) && launch(url, QLatin1String("gnome-open"))) { + return true; + } else { + if ((!X11 || (X11 && X11->desktopEnvironment == DE_KDE)) && launch(url, QLatin1String("kfmclient exec"))) + return true; + } + + if (launch(url, QLatin1String("firefox"))) + return true; + if (launch(url, QLatin1String("mozilla"))) + return true; + if (launch(url, QLatin1String("netscape"))) + return true; + if (launch(url, QLatin1String("opera"))) + return true; + + return false; +} + +static bool launchWebBrowser(const QUrl &url) +{ + if (!url.isValid()) + return false; + if (url.scheme() == QLatin1String("mailto")) + return openDocument(url); + + if (launch(url, QLatin1String("xdg-open"))) + return true; + if (launch(url, QString::fromLocal8Bit(getenv("DEFAULT_BROWSER")))) + return true; + if (launch(url, QString::fromLocal8Bit(getenv("BROWSER")))) + return true; + + // Use the X11->desktopEnvironment value if X11 is non-NULL, + // otherwise just attempt to launch command regardless of the desktop environment + if ((!X11 || (X11 && X11->desktopEnvironment == DE_GNOME)) && launch(url, QLatin1String("gnome-open"))) { + return true; + } else { + if ((!X11 || (X11 && X11->desktopEnvironment == DE_KDE)) && launch(url, QLatin1String("kfmclient openURL"))) + return true; + } + + if (launch(url, QLatin1String("firefox"))) + return true; + if (launch(url, QLatin1String("mozilla"))) + return true; + if (launch(url, QLatin1String("netscape"))) + return true; + if (launch(url, QLatin1String("opera"))) + return true; + return false; +} + + + +QString QDesktopServices::storageLocation(StandardLocation type) +{ + if (type == QDesktopServices::HomeLocation) + return QDir::homePath(); + if (type == QDesktopServices::TempLocation) + return QDir::tempPath(); + + // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html + if (type == QDesktopServices::CacheLocation) { + QString xdgCacheHome = QLatin1String(qgetenv("XDG_CACHE_HOME")); + if (xdgCacheHome.isEmpty()) + xdgCacheHome = QDir::homePath() + QLatin1String("/.cache"); + xdgCacheHome += QLatin1Char('/') + QCoreApplication::organizationName() + + QLatin1Char('/') + QCoreApplication::applicationName(); + return xdgCacheHome; + } + + if (type == QDesktopServices::DataLocation) { + QString xdgDataHome = QLatin1String(qgetenv("XDG_DATA_HOME")); + if (xdgDataHome.isEmpty()) + xdgDataHome = QDir::homePath() + QLatin1String("/.local/share"); + xdgDataHome += QLatin1String("/data/") + + QCoreApplication::organizationName() + QLatin1Char('/') + + QCoreApplication::applicationName(); + return xdgDataHome; + } + + // http://www.freedesktop.org/wiki/Software/xdg-user-dirs + QString xdgConfigHome = QLatin1String(qgetenv("XDG_CONFIG_HOME")); + if (xdgConfigHome.isEmpty()) + xdgConfigHome = QDir::homePath() + QLatin1String("/.config"); + QFile file(xdgConfigHome + QLatin1String("/user-dirs.dirs")); + if (file.exists() && file.open(QIODevice::ReadOnly)) { + QHash lines; + QTextStream stream(&file); + // Only look for lines like: XDG_DESKTOP_DIR="$HOME/Desktop" + QRegExp exp(QLatin1String("^XDG_(.*)_DIR=(.*)$")); + while (!stream.atEnd()) { + QString line = stream.readLine(); + if (exp.indexIn(line) != -1) { + QStringList lst = exp.capturedTexts(); + QString key = lst.at(1); + QString value = lst.at(2); + if (value.length() > 2 + && value.startsWith(QLatin1Char('\"')) + && value.endsWith(QLatin1Char('\"'))) + value = value.mid(1, value.length() - 2); + // Store the key and value: "DESKTOP", "$HOME/Desktop" + lines[key] = value; + } + } + + QString key; + switch (type) { + case DesktopLocation: key = QLatin1String("DESKTOP"); break; + case DocumentsLocation: key = QLatin1String("DOCUMENTS"); break; + case PicturesLocation: key = QLatin1String("PICTURES"); break; + case MusicLocation: key = QLatin1String("MUSIC"); break; + case MoviesLocation: key = QLatin1String("VIDEOS"); break; + default: break; + } + if (!key.isEmpty() && lines.contains(key)) { + QString value = lines[key]; + // value can start with $HOME + if (value.startsWith(QLatin1String("$HOME"))) + value = QDir::homePath() + value.mid(5); + return value; + } + } + + QDir emptyDir; + QString path; + switch (type) { + case DesktopLocation: + path = QDir::homePath() + QLatin1String("/Desktop"); + break; + case DocumentsLocation: + path = QDir::homePath() + QLatin1String("/Documents"); + break; + case PicturesLocation: + path = QDir::homePath() + QLatin1String("/Pictures"); + break; + + case FontsLocation: + path = QDir::homePath() + QLatin1String("/.fonts"); + break; + + case MusicLocation: + path = QDir::homePath() + QLatin1String("/Music"); + break; + + case MoviesLocation: + path = QDir::homePath() + QLatin1String("/Videos"); + break; + + case ApplicationsLocation: + default: + break; + } + + return path; +} + +QString QDesktopServices::displayName(StandardLocation type) +{ + Q_UNUSED(type); + return QString(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_DESKTOPSERVICES diff --git a/src/gui/util/qhexstring_p.h b/src/gui/util/qhexstring_p.h new file mode 100644 index 0000000000..3c8d562756 --- /dev/null +++ b/src/gui/util/qhexstring_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#ifndef QHEXSTRING_P_H +#define QHEXSTRING_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +// internal helper. Converts an integer value to an unique string token +template + struct HexString +{ + inline HexString(const T t) + : val(t) + {} + + inline void write(QChar *&dest) const + { + const ushort hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + const char *c = reinterpret_cast(&val); + for (uint i = 0; i < sizeof(T); ++i) { + *dest++ = hexChars[*c & 0xf]; + *dest++ = hexChars[(*c & 0xf0) >> 4]; + ++c; + } + } + const T val; +}; + +// specialization to enable fast concatenating of our string tokens to a string +template + struct QConcatenable > +{ + typedef HexString type; + enum { ExactSize = true }; + static int size(const HexString &) { return sizeof(T) * 2; } + static inline void appendTo(const HexString &str, QChar *&out) { str.write(out); } + typedef QString ConvertTo; +}; + +QT_END_NAMESPACE + +#endif // QHEXSTRING_P_H diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp new file mode 100644 index 0000000000..a76f7bb6e8 --- /dev/null +++ b/src/gui/util/qvalidator.cpp @@ -0,0 +1,925 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qvalidator.h" +#ifndef QT_NO_VALIDATOR +#include "private/qobject_p.h" +#include "private/qlocale_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QValidator + \brief The QValidator class provides validation of input text. + + The class itself is abstract. Two subclasses, \l QIntValidator and + \l QDoubleValidator, provide basic numeric-range checking, and \l + QRegExpValidator provides general checking using a custom regular + expression. + + If the built-in validators aren't sufficient, you can subclass + QValidator. The class has two virtual functions: validate() and + fixup(). + + \l validate() must be implemented by every subclass. It returns + \l Invalid, \l Intermediate or \l Acceptable depending on whether + its argument is valid (for the subclass's definition of valid). + + These three states require some explanation. An \l Invalid string + is \e clearly invalid. \l Intermediate is less obvious: the + concept of validity is difficult to apply when the string is + incomplete (still being edited). QValidator defines \l Intermediate + as the property of a string that is neither clearly invalid nor + acceptable as a final result. \l Acceptable means that the string + is acceptable as a final result. One might say that any string + that is a plausible intermediate state during entry of an \l + Acceptable string is \l Intermediate. + + Here are some examples: + + \list + + \i For a line edit that accepts integers from 10 to 1000 inclusive, + 42 and 123 are \l Acceptable, the empty string and 5 are \l + Intermediate, and "asdf" and 1114 is \l Invalid. + + \i For an editable combobox that accepts URLs, any well-formed URL + is \l Acceptable, "http://example.com/," is \l Intermediate + (it might be a cut and paste action that accidentally took in a + comma at the end), the empty string is \l Intermediate (the user + might select and delete all of the text in preparation for entering + a new URL) and "http:///./" is \l Invalid. + + \i For a spin box that accepts lengths, "11cm" and "1in" are \l + Acceptable, "11" and the empty string are \l Intermediate, and + "http://example.com" and "hour" are \l Invalid. + + \endlist + + \l fixup() is provided for validators that can repair some user + errors. The default implementation does nothing. QLineEdit, for + example, will call fixup() if the user presses Enter (or Return) + and the content is not currently valid. This allows the fixup() + function the opportunity of performing some magic to make an \l + Invalid string \l Acceptable. + + A validator has a locale, set with setLocale(). It is typically used + to parse localized data. For example, QIntValidator and QDoubleValidator + use it to parse localized representations of integers and doubles. + + QValidator is typically used with QLineEdit, QSpinBox and + QComboBox. + + \sa QIntValidator, QDoubleValidator, QRegExpValidator, {Line Edits Example} +*/ + + +/*! + \enum QValidator::State + + This enum type defines the states in which a validated string can + exist. + + \value Invalid The string is \e clearly invalid. + \value Intermediate The string is a plausible intermediate value. + \value Acceptable The string is acceptable as a final result; + i.e. it is valid. + + \omitvalue Valid +*/ + +class QValidatorPrivate : public QObjectPrivate{ + Q_DECLARE_PUBLIC(QValidator) +public: + QValidatorPrivate() : QObjectPrivate() + { + } + + QLocale locale; +}; + + +/*! + Sets up the validator. The \a parent parameter is + passed on to the QObject constructor. +*/ + +QValidator::QValidator(QObject * parent) + : QObject(*new QValidatorPrivate, parent) +{ +} + +#ifdef QT3_SUPPORT +/*! + \obsolete + Sets up the validator. The \a parent and \a name parameters are + passed on to the QObject constructor. +*/ + +QValidator::QValidator(QObject * parent, const char *name) + : QObject(*new QValidatorPrivate, parent) +{ + setObjectName(QString::fromAscii(name)); +} +#endif + +/*! + Destroys the validator, freeing any storage and other resources + used. +*/ + +QValidator::~QValidator() +{ +} + +/*! + Returns the locale for the validator. The locale is by default initialized to the same as QLocale(). + + \sa setLocale() + \sa QLocale::QLocale() +*/ +QLocale QValidator::locale() const +{ + Q_D(const QValidator); + return d->locale; +} + +/*! + Sets the \a locale that will be used for the validator. Unless + setLocale has been called, the validator will use the default + locale set with QLocale::setDefault(). If a default locale has not + been set, it is the operating system's locale. + + \sa locale() QLocale::setDefault() +*/ +void QValidator::setLocale(const QLocale &locale) +{ + Q_D(QValidator); + d->locale = locale; +} + +/*! + \fn QValidator::State QValidator::validate(QString &input, int &pos) const + + This virtual function returns \l Invalid if \a input is invalid + according to this validator's rules, \l Intermediate if it + is likely that a little more editing will make the input + acceptable (e.g. the user types "4" into a widget which accepts + integers between 10 and 99), and \l Acceptable if the input is + valid. + + The function can change both \a input and \a pos (the cursor position) + if required. +*/ + + +/*! + \fn void QValidator::fixup(QString & input) const + + This function attempts to change \a input to be valid according to + this validator's rules. It need not result in a valid string: + callers of this function must re-test afterwards; the default does + nothing. + + Reimplementations of this function can change \a input even if + they do not produce a valid string. For example, an ISBN validator + might want to delete every character except digits and "-", even + if the result is still not a valid ISBN; a surname validator might + want to remove whitespace from the start and end of the string, + even if the resulting string is not in the list of accepted + surnames. +*/ + +void QValidator::fixup(QString &) const +{ +} + + +/*! + \class QIntValidator + \brief The QIntValidator class provides a validator that ensures + a string contains a valid integer within a specified range. + + Example of use: + + \snippet doc/src/snippets/code/src_gui_widgets_qvalidator.cpp 0 + + Below we present some examples of validators. In practice they would + normally be associated with a widget as in the example above. + + \snippet doc/src/snippets/code/src_gui_widgets_qvalidator.cpp 1 + + Notice that the value \c 999 returns Intermediate. Values + consisting of a number of digits equal to or less than the max + value are considered intermediate. This is intended because the + digit that prevents a number to be in range is not necessarily the + last digit typed. This also means that an intermediate number can + have leading zeros. + + The minimum and maximum values are set in one call with setRange(), + or individually with setBottom() and setTop(). + + QIntValidator uses its locale() to interpret the number. For example, + in Arabic locales, QIntValidator will accept Arabic digits. In addition, + QIntValidator is always guaranteed to accept a number formatted according + to the "C" locale. + + \sa QDoubleValidator, QRegExpValidator, {Line Edits Example} +*/ + +/*! + Constructs a validator with a \a parent object that + accepts all integers. +*/ + +QIntValidator::QIntValidator(QObject * parent) + : QValidator(parent) +{ + b = INT_MIN; + t = INT_MAX; +} + + +/*! + Constructs a validator with a \a parent, that accepts integers + from \a minimum to \a maximum inclusive. +*/ + +QIntValidator::QIntValidator(int minimum, int maximum, + QObject * parent) + : QValidator(parent) +{ + b = minimum; + t = maximum; +} + + +#ifdef QT3_SUPPORT +/*! + \obsolete + + Constructs a validator with a \a parent object and a \a name that + accepts all integers. +*/ + +QIntValidator::QIntValidator(QObject * parent, const char *name) + : QValidator(parent) +{ + setObjectName(QString::fromAscii(name)); + b = INT_MIN; + t = INT_MAX; +} + + +/*! + \obsolete + + Constructs a validator called \a name with a \a parent, that + accepts integers from \a minimum to \a maximum inclusive. +*/ + +QIntValidator::QIntValidator(int minimum, int maximum, + QObject * parent, const char* name) + : QValidator(parent) +{ + setObjectName(QString::fromAscii(name)); + b = minimum; + t = maximum; +} +#endif + +/*! + Destroys the validator. +*/ + +QIntValidator::~QIntValidator() +{ + // nothing +} + + +/*! + \fn QValidator::State QIntValidator::validate(QString &input, int &pos) const + + Returns \l Acceptable if the \a input is an integer within the + valid range, \l Intermediate if the \a input is a prefix of an integer in the + valid range, and \l Invalid otherwise. + + If the valid range consists of just positive integers (e.g., 32 to 100) + and \a input is a negative integer, then Invalid is returned. (On the other + hand, if the range consists of negative integers (e.g., -100 to -32) and + \a input is a positive integer, then Intermediate is returned, because + the user might be just about to type the minus (especially for right-to-left + languages). + + \snippet doc/src/snippets/code/src_gui_widgets_qvalidator.cpp 2 + + By default, the \a pos parameter is not used by this validator. +*/ + +static int numDigits(qlonglong n) +{ + if (n == 0) + return 1; + return (int)log10(double(n)) + 1; +} + +static qlonglong pow10(int exp) +{ + qlonglong result = 1; + for (int i = 0; i < exp; ++i) + result *= 10; + return result; +} + +QValidator::State QIntValidator::validate(QString & input, int&) const +{ + QByteArray buff; + if (!locale().d()->validateChars(input, QLocalePrivate::IntegerMode, &buff)) { + QLocale cl(QLocale::C); + if (!cl.d()->validateChars(input, QLocalePrivate::IntegerMode, &buff)) + return Invalid; + } + + if (buff.isEmpty()) + return Intermediate; + + if (b >= 0 && buff.startsWith('-')) + return Invalid; + + if (t < 0 && buff.startsWith('+')) + return Invalid; + + if (buff.size() == 1 && (buff.at(0) == '+' || buff.at(0) == '-')) + return Intermediate; + + bool ok, overflow; + qlonglong entered = QLocalePrivate::bytearrayToLongLong(buff.constData(), 10, &ok, &overflow); + if (overflow || !ok) + return Invalid; + if (entered >= b && entered <= t) { + locale().toInt(input, &ok); + return ok ? Acceptable : Intermediate; + } + + if (entered >= 0) { + // the -entered < b condition is necessary to allow people to type + // the minus last (e.g. for right-to-left languages) + return (entered > t && -entered < b) ? Invalid : Intermediate; + } else { + return (entered < b) ? Invalid : Intermediate; + } +} + +/*! \reimp */ +void QIntValidator::fixup(QString &input) const +{ + QByteArray buff; + if (!locale().d()->validateChars(input, QLocalePrivate::IntegerMode, &buff)) { + QLocale cl(QLocale::C); + if (!cl.d()->validateChars(input, QLocalePrivate::IntegerMode, &buff)) + return; + } + bool ok, overflow; + qlonglong entered = QLocalePrivate::bytearrayToLongLong(buff.constData(), 10, &ok, &overflow); + if (ok && !overflow) + input = locale().toString(entered); +} + +/*! + Sets the range of the validator to only accept integers between \a + bottom and \a top inclusive. +*/ + +void QIntValidator::setRange(int bottom, int top) +{ + b = bottom; + t = top; +} + + +/*! + \property QIntValidator::bottom + \brief the validator's lowest acceptable value + + By default, this property's value is derived from the lowest signed + integer available (typically -2147483647). + + \sa setRange() +*/ +void QIntValidator::setBottom(int bottom) +{ + setRange(bottom, top()); +} + +/*! + \property QIntValidator::top + \brief the validator's highest acceptable value + + By default, this property's value is derived from the highest signed + integer available (typically 2147483647). + + \sa setRange() +*/ +void QIntValidator::setTop(int top) +{ + setRange(bottom(), top); +} + + +#ifndef QT_NO_REGEXP + +/*! + \internal +*/ +QValidator::QValidator(QObjectPrivate &d, QObject *parent) + : QObject(d, parent) +{ +} + +/*! + \internal +*/ +QValidator::QValidator(QValidatorPrivate &d, QObject *parent) + : QObject(d, parent) +{ +} + +class QDoubleValidatorPrivate : public QValidatorPrivate +{ + Q_DECLARE_PUBLIC(QDoubleValidator) +public: + QDoubleValidatorPrivate() + : QValidatorPrivate() + , notation(QDoubleValidator::ScientificNotation) + { + } + + QDoubleValidator::Notation notation; + + QValidator::State validateWithLocale(QString & input, QLocalePrivate::NumberMode numMode, const QLocale &locale) const; +}; + + +/*! + \class QDoubleValidator + + \brief The QDoubleValidator class provides range checking of + floating-point numbers. + + QDoubleValidator provides an upper bound, a lower bound, and a + limit on the number of digits after the decimal point. It does not + provide a fixup() function. + + You can set the acceptable range in one call with setRange(), or + with setBottom() and setTop(). Set the number of decimal places + with setDecimals(). The validate() function returns the validation + state. + + QDoubleValidator uses its locale() to interpret the number. For example, + in the German locale, "1,234" will be accepted as the fractional number + 1.234. In Arabic locales, QDoubleValidator will accept Arabic digits. + + In addition, QDoubleValidator is always guaranteed to accept a number + formatted according to the "C" locale. QDoubleValidator will not accept + numbers with thousand-separators. + + \sa QIntValidator, QRegExpValidator, {Line Edits Example} +*/ + + /*! + \enum QDoubleValidator::Notation + \since 4.3 + This enum defines the allowed notations for entering a double. + + \value StandardNotation The string is written as a standard number + (i.e. 0.015). + \value ScientificNotation The string is written in scientific + form. It may have an exponent part(i.e. 1.5E-2). +*/ + +/*! + Constructs a validator object with a \a parent object + that accepts any double. +*/ + +QDoubleValidator::QDoubleValidator(QObject * parent) + : QValidator(*new QDoubleValidatorPrivate , parent) +{ + b = -HUGE_VAL; + t = HUGE_VAL; + dec = 1000; +} + + +/*! + Constructs a validator object with a \a parent object. This + validator will accept doubles from \a bottom to \a top inclusive, + with up to \a decimals digits after the decimal point. +*/ + +QDoubleValidator::QDoubleValidator(double bottom, double top, int decimals, + QObject * parent) + : QValidator(*new QDoubleValidatorPrivate , parent) +{ + b = bottom; + t = top; + dec = decimals; +} + +#ifdef QT3_SUPPORT +/*! + \obsolete + + Constructs a validator object with a \a parent object and a \a name + that accepts any double. +*/ + +QDoubleValidator::QDoubleValidator(QObject * parent, const char *name) + : QValidator(*new QDoubleValidatorPrivate , parent) +{ + setObjectName(QString::fromAscii(name)); + b = -HUGE_VAL; + t = HUGE_VAL; + dec = 1000; +} + + +/*! + \obsolete + + Constructs a validator object with a \a parent object, called \a + name. This validator will accept doubles from \a bottom to \a top + inclusive, with up to \a decimals digits after the decimal point. +*/ + +QDoubleValidator::QDoubleValidator(double bottom, double top, int decimals, + QObject * parent, const char* name) + : QValidator(*new QDoubleValidatorPrivate, parent) +{ + setObjectName(QString::fromAscii(name)); + b = bottom; + t = top; + dec = decimals; +} +#endif + +/*! + Destroys the validator. +*/ + +QDoubleValidator::~QDoubleValidator() +{ +} + + +/*! + \fn QValidator::State QDoubleValidator::validate(QString &input, int &pos) const + + Returns \l Acceptable if the string \a input contains a double + that is within the valid range and is in the correct format. + + Returns \l Intermediate if \a input contains a double that is + outside the range or is in the wrong format; e.g. with too many + digits after the decimal point or is empty. + + Returns \l Invalid if the \a input is not a double. + + Note: If the valid range consists of just positive doubles (e.g. 0.0 to 100.0) + and \a input is a negative double then \l Invalid is returned. If notation() + is set to StandardNotation, and the input contains more digits before the + decimal point than a double in the valid range may have, \l Invalid is returned. + If notation() is ScientificNotation, and the input is not in the valid range, + \l Intermediate is returned. The value may yet become valid by changing the exponent. + + By default, the \a pos parameter is not used by this validator. +*/ + +#ifndef LLONG_MAX +# define LLONG_MAX Q_INT64_C(0x7fffffffffffffff) +#endif + +QValidator::State QDoubleValidator::validate(QString & input, int &) const +{ + Q_D(const QDoubleValidator); + + QLocalePrivate::NumberMode numMode = QLocalePrivate::DoubleStandardMode; + switch (d->notation) { + case StandardNotation: + numMode = QLocalePrivate::DoubleStandardMode; + break; + case ScientificNotation: + numMode = QLocalePrivate::DoubleScientificMode; + break; + } + + State currentLocaleValidation = d->validateWithLocale(input, numMode, locale()); + if (currentLocaleValidation == Acceptable || locale().language() == QLocale::C) + return currentLocaleValidation; + State cLocaleValidation = d->validateWithLocale(input, numMode, QLocale(QLocale::C)); + return qMax(currentLocaleValidation, cLocaleValidation); +} + +QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QLocalePrivate::NumberMode numMode, const QLocale &locale) const +{ + Q_Q(const QDoubleValidator); + QByteArray buff; + if (!locale.d()->validateChars(input, numMode, &buff, q->dec)) + return QValidator::Invalid; + + if (buff.isEmpty()) + return QValidator::Intermediate; + + if (q->b >= 0 && buff.startsWith('-')) + return QValidator::Invalid; + + if (q->t < 0 && buff.startsWith('+')) + return QValidator::Invalid; + + bool ok, overflow; + double i = QLocalePrivate::bytearrayToDouble(buff.constData(), &ok, &overflow); + if (overflow) + return QValidator::Invalid; + if (!ok) + return QValidator::Intermediate; + + if (i >= q->b && i <= q->t) + return QValidator::Acceptable; + + if (notation == QDoubleValidator::StandardNotation) { + double max = qMax(qAbs(q->b), qAbs(q->t)); + if (max < LLONG_MAX) { + qlonglong n = pow10(numDigits(qlonglong(max))) - 1; + if (qAbs(i) > n) + return QValidator::Invalid; + } + } + + return QValidator::Intermediate; +} + + +/*! + Sets the validator to accept doubles from \a minimum to \a maximum + inclusive, with at most \a decimals digits after the decimal + point. +*/ + +void QDoubleValidator::setRange(double minimum, double maximum, int decimals) +{ + b = minimum; + t = maximum; + dec = decimals; +} + +/*! + \property QDoubleValidator::bottom + \brief the validator's minimum acceptable value + + By default, this property contains a value of -infinity. + + \sa setRange() +*/ + +void QDoubleValidator::setBottom(double bottom) +{ + setRange(bottom, top(), decimals()); +} + + +/*! + \property QDoubleValidator::top + \brief the validator's maximum acceptable value + + By default, this property contains a value of infinity. + + \sa setRange() +*/ + +void QDoubleValidator::setTop(double top) +{ + setRange(bottom(), top, decimals()); +} + +/*! + \property QDoubleValidator::decimals + \brief the validator's maximum number of digits after the decimal point + + By default, this property contains a value of 1000. + + \sa setRange() +*/ + +void QDoubleValidator::setDecimals(int decimals) +{ + setRange(bottom(), top(), decimals); +} + +/*! + \property QDoubleValidator::notation + \since 4.3 + \brief the notation of how a string can describe a number + + By default, this property is set to ScientificNotation. + + \sa Notation +*/ + +void QDoubleValidator::setNotation(Notation newNotation) +{ + Q_D(QDoubleValidator); + d->notation = newNotation; +} + +QDoubleValidator::Notation QDoubleValidator::notation() const +{ + Q_D(const QDoubleValidator); + return d->notation; +} + +/*! + \class QRegExpValidator + \brief The QRegExpValidator class is used to check a string + against a regular expression. + + QRegExpValidator uses a regular expression (regexp) to + determine whether an input string is \l Acceptable, \l + Intermediate, or \l Invalid. The regexp can either be supplied + when the QRegExpValidator is constructed, or at a later time. + + When QRegExpValidator determines whether a string is \l Acceptable + or not, the regexp is treated as if it begins with the start of string + assertion (\bold{^}) and ends with the end of string assertion + (\bold{$}); the match is against the entire input string, or from + the given position if a start position greater than zero is given. + + If a string is a prefix of an \l Acceptable string, it is considered + \l Intermediate. For example, "" and "A" are \l Intermediate for the + regexp \bold{[A-Z][0-9]} (whereas "_" would be \l Invalid). + + For a brief introduction to Qt's regexp engine, see \l QRegExp. + + Example of use: + \snippet doc/src/snippets/code/src_gui_widgets_qvalidator.cpp 3 + + Below we present some examples of validators. In practice they would + normally be associated with a widget as in the example above. + + \snippet doc/src/snippets/code/src_gui_widgets_qvalidator.cpp 4 + + \sa QRegExp, QIntValidator, QDoubleValidator, {Settings Editor Example} +*/ + +/*! + Constructs a validator with a \a parent object that accepts + any string (including an empty one) as valid. +*/ + +QRegExpValidator::QRegExpValidator(QObject *parent) + : QValidator(parent), r(QString::fromLatin1(".*")) +{ +} + +/*! + Constructs a validator with a \a parent object that + accepts all strings that match the regular expression \a rx. + + The match is made against the entire string; e.g. if the regexp is + \bold{[A-Fa-f0-9]+} it will be treated as \bold{^[A-Fa-f0-9]+$}. +*/ + +QRegExpValidator::QRegExpValidator(const QRegExp& rx, QObject *parent) + : QValidator(parent), r(rx) +{ +} + +#ifdef QT3_SUPPORT +/*! + \obsolete + + Constructs a validator with a \a parent object and \a name that accepts + any string (including an empty one) as valid. +*/ + +QRegExpValidator::QRegExpValidator(QObject *parent, const char *name) + : QValidator(parent), r(QString::fromLatin1(".*")) +{ + setObjectName(QString::fromAscii(name)); +} + +/*! + \obsolete + + Constructs a validator with a \a parent object and a \a name that + accepts all strings that match the regular expression \a rx. + + The match is made against the entire string; e.g. if the regexp is + \bold{[A-Fa-f0-9]+} it will be treated as \bold{^[A-Fa-f0-9]+$}. +*/ + +QRegExpValidator::QRegExpValidator(const QRegExp& rx, QObject *parent, + const char *name) + : QValidator(parent), r(rx) +{ + setObjectName(QString::fromAscii(name)); +} +#endif + +/*! + Destroys the validator. +*/ + +QRegExpValidator::~QRegExpValidator() +{ +} + +/*! + Returns \l Acceptable if \a input is matched by the regular + expression for this validator, \l Intermediate if it has matched + partially (i.e. could be a valid match if additional valid + characters are added), and \l Invalid if \a input is not matched. + + The \a pos parameter is set to the length of the \a input parameter. + + For example, if the regular expression is \bold{\\w\\d\\d} + (word-character, digit, digit) then "A57" is \l Acceptable, + "E5" is \l Intermediate, and "+9" is \l Invalid. + + \sa QRegExp::exactMatch() +*/ + +QValidator::State QRegExpValidator::validate(QString &input, int& pos) const +{ + if (r.exactMatch(input)) { + return Acceptable; + } else { + if (const_cast(r).matchedLength() == input.size()) { + return Intermediate; + } else { + pos = input.size(); + return Invalid; + } + } +} + +/*! + \property QRegExpValidator::regExp + \brief the regular expression used for validation + + By default, this property contains a regular expression with the pattern \c{.*} + that matches any string. +*/ + +void QRegExpValidator::setRegExp(const QRegExp& rx) +{ + r = rx; +} + +#endif + +QT_END_NAMESPACE + +#endif // QT_NO_VALIDATOR diff --git a/src/gui/util/qvalidator.h b/src/gui/util/qvalidator.h new file mode 100644 index 0000000000..5a0162afd5 --- /dev/null +++ b/src/gui/util/qvalidator.h @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVALIDATOR_H +#define QVALIDATOR_H + +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_VALIDATOR + +class QValidatorPrivate; + +class Q_GUI_EXPORT QValidator : public QObject +{ + Q_OBJECT +public: + explicit QValidator(QObject * parent = 0); + ~QValidator(); + + enum State { + Invalid, + Intermediate, + Acceptable + +#if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN) + , Valid = Intermediate +#endif + }; + + void setLocale(const QLocale &locale); + QLocale locale() const; + + virtual State validate(QString &, int &) const = 0; + virtual void fixup(QString &) const; + +#ifdef QT3_SUPPORT +public: + QT3_SUPPORT_CONSTRUCTOR QValidator(QObject * parent, const char *name); +#endif +protected: + QValidator(QObjectPrivate &d, QObject *parent); + QValidator(QValidatorPrivate &d, QObject *parent); + +private: + Q_DISABLE_COPY(QValidator) + Q_DECLARE_PRIVATE(QValidator) +}; + +class Q_GUI_EXPORT QIntValidator : public QValidator +{ + Q_OBJECT + Q_PROPERTY(int bottom READ bottom WRITE setBottom) + Q_PROPERTY(int top READ top WRITE setTop) + +public: + explicit QIntValidator(QObject * parent = 0); + QIntValidator(int bottom, int top, QObject *parent = 0); + ~QIntValidator(); + + QValidator::State validate(QString &, int &) const; + void fixup(QString &input) const; + + void setBottom(int); + void setTop(int); + virtual void setRange(int bottom, int top); + + int bottom() const { return b; } + int top() const { return t; } + +#ifdef QT3_SUPPORT +public: + QT3_SUPPORT_CONSTRUCTOR QIntValidator(QObject * parent, const char *name); + QT3_SUPPORT_CONSTRUCTOR QIntValidator(int bottom, int top, QObject * parent, const char *name); +#endif + +private: + Q_DISABLE_COPY(QIntValidator) + + int b; + int t; +}; + +#ifndef QT_NO_REGEXP + +class QDoubleValidatorPrivate; + +class Q_GUI_EXPORT QDoubleValidator : public QValidator +{ + Q_OBJECT + Q_PROPERTY(double bottom READ bottom WRITE setBottom) + Q_PROPERTY(double top READ top WRITE setTop) + Q_PROPERTY(int decimals READ decimals WRITE setDecimals) + Q_ENUMS(Notation) + Q_PROPERTY(Notation notation READ notation WRITE setNotation) + +public: + explicit QDoubleValidator(QObject * parent = 0); + QDoubleValidator(double bottom, double top, int decimals, QObject *parent = 0); + ~QDoubleValidator(); + + enum Notation { + StandardNotation, + ScientificNotation + }; + + QValidator::State validate(QString &, int &) const; + + virtual void setRange(double bottom, double top, int decimals = 0); + void setBottom(double); + void setTop(double); + void setDecimals(int); + void setNotation(Notation); + + double bottom() const { return b; } + double top() const { return t; } + int decimals() const { return dec; } + Notation notation() const; + +#ifdef QT3_SUPPORT +public: + QT3_SUPPORT_CONSTRUCTOR QDoubleValidator(QObject * parent, const char *name); + QT3_SUPPORT_CONSTRUCTOR QDoubleValidator(double bottom, double top, int decimals, + QObject * parent, const char *name); +#endif +private: + Q_DECLARE_PRIVATE(QDoubleValidator) + Q_DISABLE_COPY(QDoubleValidator) + + double b; + double t; + int dec; +}; + + +class Q_GUI_EXPORT QRegExpValidator : public QValidator +{ + Q_OBJECT + Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp) + +public: + explicit QRegExpValidator(QObject *parent = 0); + QRegExpValidator(const QRegExp& rx, QObject *parent = 0); + ~QRegExpValidator(); + + virtual QValidator::State validate(QString& input, int& pos) const; + + void setRegExp(const QRegExp& rx); + const QRegExp& regExp() const { return r; } // ### make inline for 5.0 + +#ifdef QT3_SUPPORT +public: + QT3_SUPPORT_CONSTRUCTOR QRegExpValidator(QObject *parent, const char *name); + QT3_SUPPORT_CONSTRUCTOR QRegExpValidator(const QRegExp& rx, QObject *parent, const char *name); +#endif + +private: + Q_DISABLE_COPY(QRegExpValidator) + + QRegExp r; +}; + +#endif // QT_NO_REGEXP + +#endif // QT_NO_VALIDATOR + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QVALIDATOR_H diff --git a/src/gui/util/util.pri b/src/gui/util/util.pri new file mode 100644 index 0000000000..dfb221667e --- /dev/null +++ b/src/gui/util/util.pri @@ -0,0 +1,10 @@ +# Qt util module + +HEADERS += \ + util/qdesktopservices.h \ + util/qhexstring_p.h \ + util/qvalidator.h + +SOURCES += \ + util/qdesktopservices.cpp \ + util/qvalidator.cpp -- cgit v1.2.3