diff options
author | Alexis Menard <alexis.menard@nokia.com> | 2009-04-17 10:40:52 (GMT) |
---|---|---|
committer | Alexis Menard <alexis.menard@nokia.com> | 2009-04-17 10:40:52 (GMT) |
commit | bb2e4df9bee3148e819c98410aa36e22dad95d7a (patch) | |
tree | a6e6e8c070a72378d4b2e5f39ad3cc9c368b61ab /src/corelib/kernel | |
download | Qt-bb2e4df9bee3148e819c98410aa36e22dad95d7a.zip Qt-bb2e4df9bee3148e819c98410aa36e22dad95d7a.tar.gz Qt-bb2e4df9bee3148e819c98410aa36e22dad95d7a.tar.bz2 |
Initial import of kinetic-animations branch from the old kinetic
repository to the new repository
Diffstat (limited to 'src/corelib/kernel')
74 files changed, 34480 insertions, 0 deletions
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri new file mode 100644 index 0000000..b34e59d --- /dev/null +++ b/src/corelib/kernel/kernel.pri @@ -0,0 +1,111 @@ +# Qt core object module + +HEADERS += \ + kernel/qabstracteventdispatcher.h \ + kernel/qabstractitemmodel.h \ + kernel/qabstractitemmodel_p.h \ + kernel/qbasictimer.h \ + kernel/qeventloop.h\ + kernel/qpointer.h \ + kernel/qcorecmdlineargs_p.h \ + kernel/qcoreapplication.h \ + kernel/qcoreevent.h \ + kernel/qmetaobject.h \ + kernel/qmetatype.h \ + kernel/qmimedata.h \ + kernel/qobject.h \ + kernel/qobjectdefs.h \ + kernel/qsignalmapper.h \ + kernel/qsocketnotifier.h \ + kernel/qtimer.h \ + kernel/qtranslator.h \ + kernel/qtranslator_p.h \ + kernel/qvariant.h \ + kernel/qabstracteventdispatcher_p.h \ + kernel/qcoreapplication_p.h \ + kernel/qobjectcleanuphandler.h \ + kernel/qvariant_p.h \ + kernel/qmetaobject_p.h \ + kernel/qobject_p.h \ + kernel/qcoreglobaldata_p.h \ + kernel/qsharedmemory.h \ + kernel/qsharedmemory_p.h \ + kernel/qsystemsemaphore.h \ + kernel/qsystemsemaphore_p.h \ + kernel/qfunctions_p.h + +SOURCES += \ + kernel/qabstracteventdispatcher.cpp \ + kernel/qabstractitemmodel.cpp \ + kernel/qbasictimer.cpp \ + kernel/qeventloop.cpp \ + kernel/qcoreapplication.cpp \ + kernel/qcoreevent.cpp \ + kernel/qmetaobject.cpp \ + kernel/qmetatype.cpp \ + kernel/qmimedata.cpp \ + kernel/qobject.cpp \ + kernel/qobjectcleanuphandler.cpp \ + kernel/qsignalmapper.cpp \ + kernel/qsocketnotifier.cpp \ + kernel/qtimer.cpp \ + kernel/qtranslator.cpp \ + kernel/qvariant.cpp \ + kernel/qcoreglobaldata.cpp \ + kernel/qsharedmemory.cpp \ + kernel/qsystemsemaphore.cpp + +win32 { + SOURCES += \ + kernel/qeventdispatcher_win.cpp \ + kernel/qcoreapplication_win.cpp \ + kernel/qwineventnotifier_p.cpp \ + kernel/qsharedmemory_win.cpp \ + kernel/qsystemsemaphore_win.cpp + HEADERS += \ + kernel/qeventdispatcher_win_p.h \ + kernel/qwineventnotifier_p.h +} + + +wince*: { + SOURCES += \ + kernel/qfunctions_wince.cpp + HEADERS += \ + kernel/qfunctions_wince.h +} + +mac:!embedded { + SOURCES += \ + kernel/qcoreapplication_mac.cpp +} + +mac { + SOURCES += \ + kernel/qcore_mac.cpp +} + +unix { + SOURCES += \ + kernel/qcrashhandler.cpp \ + kernel/qsharedmemory_unix.cpp \ + kernel/qsystemsemaphore_unix.cpp + HEADERS += \ + kernel/qcrashhandler_p.h + + contains(QT_CONFIG, glib) { + SOURCES += \ + kernel/qeventdispatcher_glib.cpp + HEADERS += \ + kernel/qeventdispatcher_glib_p.h + QMAKE_CXXFLAGS += $$QT_CFLAGS_GLIB + LIBS +=$$QT_LIBS_GLIB + } + SOURCES += \ + kernel/qeventdispatcher_unix.cpp + HEADERS += \ + kernel/qeventdispatcher_unix_p.h + + contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri) +} + diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp new file mode 100644 index 0000000..51fde17 --- /dev/null +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -0,0 +1,461 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstracteventdispatcher.h" +#include "qabstracteventdispatcher_p.h" + +#include "qthread.h" +#include <private/qthread_p.h> +#include <private/qcoreapplication_p.h> + +QT_BEGIN_NAMESPACE + +// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers +enum { NumberOfBuckets = 8, FirstBucketSize = 8 }; + +static const int BucketSize[NumberOfBuckets] = + { 8, 64, 512, 4096, 32768, 262144, 2097152, 16777216 - 2396744 }; +static const int BucketOffset[NumberOfBuckets] = + { 0, 8, 72, 584, 4680, 37448, 299592, 2396744 }; + +static int FirstBucket[FirstBucketSize] = { 1, 2, 3, 4, 5, 6, 7, 8 }; +static QBasicAtomicPointer<int> timerIds[NumberOfBuckets] = + { Q_BASIC_ATOMIC_INITIALIZER(FirstBucket), + Q_BASIC_ATOMIC_INITIALIZER(0), + Q_BASIC_ATOMIC_INITIALIZER(0), + Q_BASIC_ATOMIC_INITIALIZER(0), + Q_BASIC_ATOMIC_INITIALIZER(0), + Q_BASIC_ATOMIC_INITIALIZER(0), + Q_BASIC_ATOMIC_INITIALIZER(0), + Q_BASIC_ATOMIC_INITIALIZER(0) }; + +static void timerIdsDestructorFunction() +{ + // start at one, the first bucket is pre-allocated + for (int i = 1; i < NumberOfBuckets; ++i) + delete [] static_cast<int *>(timerIds[i]); +} +Q_DESTRUCTOR_FUNCTION(timerIdsDestructorFunction) + +static QBasicAtomicInt nextFreeTimerId = Q_BASIC_ATOMIC_INITIALIZER(1); + +// avoid the ABA-problem by using 7 of the top 8 bits of the timerId as a serial number +static inline int prepareNewValueWithSerialNumber(int oldId, int newId) +{ + return (newId & 0x00FFFFFF) | ((oldId + 0x01000000) & 0x7f000000); +} + +static inline int bucketOffset(int timerId) +{ + for (int i = 0; i < NumberOfBuckets; ++i) { + if (timerId < BucketSize[i]) + return i; + timerId -= BucketSize[i]; + } + qFatal("QAbstractEventDispatcher: INTERNAL ERROR, timer ID %d is too large", timerId); + return -1; +} + +static inline int bucketIndex(int bucket, int timerId) +{ + return timerId - BucketOffset[bucket]; +} + +static inline int *allocateBucket(int bucket) +{ + // allocate a new bucket + const int size = BucketSize[bucket]; + const int offset = BucketOffset[bucket]; + int *b = new int[size]; + for (int i = 0; i != size; ++i) + b[i] = offset + i + 1; + return b; +} + +void QAbstractEventDispatcherPrivate::init() +{ + Q_Q(QAbstractEventDispatcher); + if (threadData->eventDispatcher != 0) { + qWarning("QAbstractEventDispatcher: An event dispatcher has already been created for this thread"); + } else { + threadData->eventDispatcher = q; + } +} + +int QAbstractEventDispatcherPrivate::allocateTimerId() +{ + int timerId, newTimerId; + do { + timerId = nextFreeTimerId; + + // which bucket are we looking in? + int which = timerId & 0x00ffffff; + int bucket = bucketOffset(which); + int at = bucketIndex(bucket, which); + int *b = timerIds[bucket]; + + if (!b) { + // allocate a new bucket + b = allocateBucket(bucket); + if (!timerIds[bucket].testAndSetRelease(0, b)) { + // another thread won the race to allocate the bucket + delete [] b; + b = timerIds[bucket]; + } + } + + newTimerId = b[at]; + } while (!nextFreeTimerId.testAndSetRelaxed(timerId, newTimerId)); + + return timerId; +} + +void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId) +{ + int which = timerId & 0x00ffffff; + int bucket = bucketOffset(which); + int at = bucketIndex(bucket, which); + int *b = timerIds[bucket]; + + int freeId, newTimerId; + do { + freeId = nextFreeTimerId; + b[at] = freeId & 0x00ffffff; + + newTimerId = prepareNewValueWithSerialNumber(freeId, timerId); + } while (!nextFreeTimerId.testAndSetRelease(freeId, newTimerId)); +} + +/*! + \class QAbstractEventDispatcher + \brief The QAbstractEventDispatcher class provides an interface to manage Qt's event queue. + + \ingroup application + \ingroup events + + An event dispatcher receives events from the window system and other + sources. It then sends them to the QCoreApplication or QApplication + instance for processing and delivery. QAbstractEventDispatcher provides + fine-grained control over event delivery. + + For simple control of event processing use + QCoreApplication::processEvents(). + + For finer control of the application's event loop, call + instance() and call functions on the QAbstractEventDispatcher + object that is returned. If you want to use your own instance of + QAbstractEventDispatcher or of a QAbstractEventDispatcher + subclass, you must create your instance \e before you create the + QApplication object. + + The main event loop is started by calling + QCoreApplication::exec(), and stopped by calling + QCoreApplication::exit(). Local event loops can be created using + QEventLoop. + + Programs that perform long operations can call processEvents() + with a bitwise OR combination of various QEventLoop::ProcessEventsFlag + values to control which events should be delivered. + + QAbstractEventDispatcher also allows the integration of an + external event loop with the Qt event loop. For example, the + \l{Qt Solutions}{Motif Extension Qt Solution} includes a + reimplementation of QAbstractEventDispatcher that merges Qt and + Motif events together. + + \sa QEventLoop, QCoreApplication +*/ + +/*! + Constructs a new event dispatcher with the given \a parent. +*/ +QAbstractEventDispatcher::QAbstractEventDispatcher(QObject *parent) + : QObject(*new QAbstractEventDispatcherPrivate, parent) +{ + Q_D(QAbstractEventDispatcher); + d->init(); +} + +/*! + \internal +*/ +QAbstractEventDispatcher::QAbstractEventDispatcher(QAbstractEventDispatcherPrivate &dd, + QObject *parent) + : QObject(dd, parent) +{ + Q_D(QAbstractEventDispatcher); + d->init(); +} + +/*! + Destroys the event dispatcher. +*/ +QAbstractEventDispatcher::~QAbstractEventDispatcher() +{ } + +/*! + Returns a pointer to the event dispatcher object for the specified + \a thread. If \a thread is zero, the current thread is used. If no + event dispatcher exists for the specified thread, this function + returns 0. + + \bold{Note:} If Qt is built without thread support, the \a thread + argument is ignored. + */ +QAbstractEventDispatcher *QAbstractEventDispatcher::instance(QThread *thread) +{ + QThreadData *data = thread ? QThreadData::get2(thread) : QThreadData::current(); + return data->eventDispatcher; +} + +/*! + \fn bool QAbstractEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) + + Processes pending events that match \a flags until there are no + more events to process. Returns true if an event was processed; + otherwise returns false. + + This function is especially useful if you have a long running + operation and want to show its progress without allowing user + input; i.e. by using the QEventLoop::ExcludeUserInputEvents flag. + + If the QEventLoop::WaitForMoreEvents flag is set in \a flags, the + behavior of this function is as follows: + + \list + + \i If events are available, this function returns after processing + them. + + \i If no events are available, this function will wait until more + are available and return after processing newly available events. + + \endlist + + If the QEventLoop::WaitForMoreEvents flag is not set in \a flags, + and no events are available, this function will return + immediately. + + \bold{Note:} This function does not process events continuously; it + returns after all available events are processed. + + \sa hasPendingEvents() +*/ + +/*! \fn bool QAbstractEventDispatcher::hasPendingEvents() + + Returns true if there is an event waiting; otherwise returns + false. +*/ + +/*! + \fn void QAbstractEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier) + + Registers \a notifier with the event loop. Subclasses must + implement this method to tie a socket notifier into another + event loop. +*/ + +/*! \fn void QAbstractEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier) + + Unregisters \a notifier from the event dispatcher. Subclasses must + reimplement this method to tie a socket notifier into another + event loop. Reimplementations must call the base + implementation. +*/ + +/*! + \fn int QAbstractEventDispatcher::registerTimer(int interval, QObject *object) + + Registers a timer with the specified \a interval for the given \a object. +*/ +int QAbstractEventDispatcher::registerTimer(int interval, QObject *object) +{ + int id = QAbstractEventDispatcherPrivate::allocateTimerId(); + registerTimer(id, interval, object); + return id; +} + +/*! + \fn void QAbstractEventDispatcher::registerTimer(int timerId, int interval, QObject *object) + + Register a timer with the specified \a timerId and \a interval for + the given \a object. +*/ + +/*! + \fn bool QAbstractEventDispatcher::unregisterTimer(int timerId) + + Unregisters the timer with the given \a timerId. + Returns true if successful; otherwise returns false. + + \sa registerTimer(), unregisterTimers() +*/ + +/*! + \fn bool QAbstractEventDispatcher::unregisterTimers(QObject *object) + + Unregisters all the timers associated with the given \a object. + Returns true if all timers were successful removed; otherwise returns false. + + \sa unregisterTimer(), registeredTimers() +*/ + +/*! + \fn QList<TimerInfo> QAbstractEventDispatcher::registeredTimers(QObject *object) const + + Returns a list of registered timers for \a object. The timer ID + is the first member in each pair; the interval is the second. +*/ + +/*! \fn void QAbstractEventDispatcher::wakeUp() + \threadsafe + + Wakes up the event loop. + + \sa awake() +*/ + +/*! + \fn void QAbstractEventDispatcher::interrupt() + + Interrupts event dispatching; i.e. the event dispatcher will + return from processEvents() as soon as possible. +*/ + +/*! \fn void QAbstractEventDispatcher::flush() + + Flushes the event queue. This normally returns almost + immediately. Does nothing on platforms other than X11. +*/ + +// ### DOC: Are these called when the _application_ starts/stops or just +// when the current _event loop_ starts/stops? +/*! \internal */ +void QAbstractEventDispatcher::startingUp() +{ } + +/*! \internal */ +void QAbstractEventDispatcher::closingDown() +{ } + +/*! + \typedef QAbstractEventDispatcher::TimerInfo + + Typedef for QPair<int, int>. The first component of + the pair is the timer ID; the second component is + the interval. + + \sa registeredTimers() +*/ + +/*! + \typedef QAbstractEventDispatcher::EventFilter + + Typedef for a function with the signature + + \snippet doc/src/snippets/code/src_corelib_kernel_qabstracteventdispatcher.cpp 0 + + \sa setEventFilter(), filterEvent() +*/ + +/*! + Sets the event filter \a filter. Returns a pointer to the filter + function previously defined. + + The event filter is a function that receives all messages taken + from the system event loop before the event is dispatched to the + respective target. This includes messages that are not sent to Qt + objects. + + The function can return true to stop the event to be processed by + Qt, or false to continue with the standard event processing. + + Only one filter can be defined, but the filter can use the return + value to call the previously set event filter. By default, no + filter is set (i.e. the function returns 0). +*/ +QAbstractEventDispatcher::EventFilter QAbstractEventDispatcher::setEventFilter(EventFilter filter) +{ + Q_D(QAbstractEventDispatcher); + EventFilter oldFilter = d->event_filter; + d->event_filter = filter; + return oldFilter; +} + +/*! + Sends \a message through the event filter that was set by + setEventFilter(). If no event filter has been set, this function + returns false; otherwise, this function returns the result of the + event filter function. + + Subclasses of QAbstractEventDispatcher \e must call this function + for \e all messages received from the system to ensure + compatibility with any extensions that may be used in the + application. + + \sa setEventFilter() +*/ +bool QAbstractEventDispatcher::filterEvent(void *message) +{ + Q_D(QAbstractEventDispatcher); + if (d->event_filter) + return d->event_filter(message); + return false; +} + +/*! \fn void QAbstractEventDispatcher::awake() + + This signal is emitted after the event loop returns from a + function that could block. + + \sa wakeUp() aboutToBlock() +*/ + +/*! \fn void QAbstractEventDispatcher::aboutToBlock() + + This signal is emitted before the event loop calls a function that + could block. + + \sa awake() +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h new file mode 100644 index 0000000..7daeaad --- /dev/null +++ b/src/corelib/kernel/qabstracteventdispatcher.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTEVENTDISPATCHER_H +#define QABSTRACTEVENTDISPATCHER_H + +#include <QtCore/qobject.h> +#include <QtCore/qeventloop.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QAbstractEventDispatcherPrivate; +class QSocketNotifier; +template <typename T1, typename T2> struct QPair; + +class Q_CORE_EXPORT QAbstractEventDispatcher : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QAbstractEventDispatcher) + +public: + typedef QPair<int, int> TimerInfo; + + explicit QAbstractEventDispatcher(QObject *parent = 0); + ~QAbstractEventDispatcher(); + + static QAbstractEventDispatcher *instance(QThread *thread = 0); + + virtual bool processEvents(QEventLoop::ProcessEventsFlags flags) = 0; + virtual bool hasPendingEvents() = 0; + + virtual void registerSocketNotifier(QSocketNotifier *notifier) = 0; + virtual void unregisterSocketNotifier(QSocketNotifier *notifier) = 0; + + int registerTimer(int interval, QObject *object); + virtual void registerTimer(int timerId, int interval, QObject *object) = 0; + virtual bool unregisterTimer(int timerId) = 0; + virtual bool unregisterTimers(QObject *object) = 0; + virtual QList<TimerInfo> registeredTimers(QObject *object) const = 0; + + virtual void wakeUp() = 0; + virtual void interrupt() = 0; + virtual void flush() = 0; + + virtual void startingUp(); + virtual void closingDown(); + + typedef bool(*EventFilter)(void *message); + EventFilter setEventFilter(EventFilter filter); + bool filterEvent(void *message); + +Q_SIGNALS: + void aboutToBlock(); + void awake(); + +protected: + QAbstractEventDispatcher(QAbstractEventDispatcherPrivate &, + QObject *parent); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QABSTRACTEVENTDISPATCHER_H diff --git a/src/corelib/kernel/qabstracteventdispatcher_p.h b/src/corelib/kernel/qabstracteventdispatcher_p.h new file mode 100644 index 0000000..7909ab4 --- /dev/null +++ b/src/corelib/kernel/qabstracteventdispatcher_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTEVENTDISPATCHER_P_H +#define QABSTRACTEVENTDISPATCHER_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. +// + +#include "QtCore/qabstracteventdispatcher.h" +#include "private/qobject_p.h" + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QAbstractEventDispatcherPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QAbstractEventDispatcher) +public: + inline QAbstractEventDispatcherPrivate() + : event_filter(0) + { } + void init(); + QAbstractEventDispatcher::EventFilter event_filter; + + static int allocateTimerId(); + static void releaseTimerId(int id); +}; + +QT_END_NAMESPACE + +#endif // QABSTRACTEVENTDISPATCHER_P_H diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp new file mode 100644 index 0000000..fd0e105 --- /dev/null +++ b/src/corelib/kernel/qabstractitemmodel.cpp @@ -0,0 +1,2783 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstractitemmodel.h" +#include <private/qabstractitemmodel_p.h> +#include <qdatastream.h> +#include <qstringlist.h> +#include <qsize.h> +#include <qmimedata.h> +#include <qdebug.h> +#include <qvector.h> +#include <qstack.h> +#include <qbitarray.h> + +#include <limits.h> + +QT_BEGIN_NAMESPACE + +QPersistentModelIndexData *QPersistentModelIndexData::create(const QModelIndex &index) +{ + Q_ASSERT(index.isValid()); // we will _never_ insert an invalid index in the list + QPersistentModelIndexData *d = 0; + QAbstractItemModel *model = const_cast<QAbstractItemModel *>(index.model()); + QHash<QModelIndex, QPersistentModelIndexData *> &indexes = model->d_func()->persistent.indexes; + const QHash<QModelIndex, QPersistentModelIndexData *>::iterator it = indexes.find(index); + if (it != indexes.end()) { + d = (*it); + } else { + d = new QPersistentModelIndexData(index); + indexes.insert(index, d); + } + Q_ASSERT(d); + return d; +} + +void QPersistentModelIndexData::destroy(QPersistentModelIndexData *data) +{ + Q_ASSERT(data); + Q_ASSERT(data->ref == 0); + QAbstractItemModel *model = const_cast<QAbstractItemModel *>(data->model); + // a valid persistent model index with a null model pointer can only happen if the model was destroyed + if (model) { + QAbstractItemModelPrivate *p = model->d_func(); + Q_ASSERT(p); + p->removePersistentIndexData(data); + } + delete data; +} + +/*! + \class QPersistentModelIndex + + \brief The QPersistentModelIndex class is used to locate data in a data model. + + \ingroup model-view + + A QPersistentModelIndex is a model index that can be stored by an + application, and later used to access information in a model. + Unlike the QModelIndex class, it is safe to store a + QPersistentModelIndex since the model will ensure that references + to items will continue to be valid as long as they can be accessed + by the model. + + It is good practice to check that persistent model indexes are valid + before using them. + + \sa {Model/View Programming}, QModelIndex, QAbstractItemModel +*/ + + +/*! + \fn QPersistentModelIndex::QPersistentModelIndex() + + \internal +*/ + +QPersistentModelIndex::QPersistentModelIndex() + : d(0) +{ +} + +/*! + \fn QPersistentModelIndex::QPersistentModelIndex(const QPersistentModelIndex &other) + + Creates a new QPersistentModelIndex that is a copy of the \a other persistent + model index. +*/ + +QPersistentModelIndex::QPersistentModelIndex(const QPersistentModelIndex &other) + : d(other.d) +{ + if (d) d->ref.ref(); +} + +/*! + Creates a new QPersistentModelIndex that is a copy of the model \a index. +*/ + +QPersistentModelIndex::QPersistentModelIndex(const QModelIndex &index) + : d(0) +{ + if (index.isValid()) { + d = QPersistentModelIndexData::create(index); + d->ref.ref(); + } +} + +/*! + \fn QPersistentModelIndex::~QPersistentModelIndex() + + \internal +*/ + +QPersistentModelIndex::~QPersistentModelIndex() +{ + if (d && !d->ref.deref()) { + QPersistentModelIndexData::destroy(d); + d = 0; + } +} + +/*! + Returns true if this persistent model index is equal to the \a other + persistent model index; otherwise returns false. + + All values in the persistent model index are used when comparing + with another persistent model index. +*/ + +bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const +{ + if (d && other.d) + return d->index == other.d->index; + return d == other.d; +} + +/*! + \since 4.1 + + Returns true if this persistent model index is smaller than the \a other + persistent model index; otherwise returns false. + + All values in the persistent model index are used when comparing + with another persistent model index. +*/ + +bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const +{ + if (d && other.d) + return d->index < other.d->index; + + return d < other.d; +} + +/*! + \fn bool QPersistentModelIndex::operator!=(const QPersistentModelIndex &other) const + \since 4.2 + + Returns true if this persistent model index is not equal to the \a + other persistent model index; otherwise returns false. +*/ + +/*! + Sets the persistent model index to refer to the same item in a model + as the \a other persistent model index. +*/ + +QPersistentModelIndex &QPersistentModelIndex::operator=(const QPersistentModelIndex &other) +{ + if (d == other.d) + return *this; + if (d && !d->ref.deref()) + QPersistentModelIndexData::destroy(d); + d = other.d; + if (d) d->ref.ref(); + return *this; +} + +/*! + Sets the persistent model index to refer to the same item in a model + as the \a other model index. +*/ + +QPersistentModelIndex &QPersistentModelIndex::operator=(const QModelIndex &other) +{ + if (d && !d->ref.deref()) + QPersistentModelIndexData::destroy(d); + if (other.isValid()) { + d = QPersistentModelIndexData::create(other); + if (d) d->ref.ref(); + } else { + d = 0; + } + return *this; +} + +/*! + \fn QPersistentModelIndex::operator const QModelIndex&() const + + Cast operator that returns a const QModelIndex&. +*/ + +QPersistentModelIndex::operator const QModelIndex&() const +{ + static const QModelIndex invalid; + if (d) + return d->index; + return invalid; +} + +/*! + \fn bool QPersistentModelIndex::operator==(const QModelIndex &other) const + + Returns true if this persistent model index refers to the same location as + the \a other model index; otherwise returns false. + Note that all values in the persistent model index are used when comparing + with another model index. +*/ + +bool QPersistentModelIndex::operator==(const QModelIndex &other) const +{ + if (d) + return d->index == other; + return !other.isValid(); +} + +/*! + \fn bool QPersistentModelIndex::operator!=(const QModelIndex &other) const + + Returns true if this persistent model index does not refer to the same + location as the \a other model index; otherwise returns false. +*/ + +bool QPersistentModelIndex::operator!=(const QModelIndex &other) const +{ + if (d) + return d->index != other; + return other.isValid(); +} + +/*! + \fn int QPersistentModelIndex::row() const + + Returns the row this persistent model index refers to. +*/ + +int QPersistentModelIndex::row() const +{ + if (d) + return d->index.row(); + return -1; +} + +/*! + \fn int QPersistentModelIndex::column() const + + Returns the column this persistent model index refers to. +*/ + +int QPersistentModelIndex::column() const +{ + if (d) + return d->index.column(); + return -1; +} + +/*! + \fn void *QPersistentModelIndex::internalPointer() const + + \internal + + Returns a \c{void} \c{*} pointer used by the model to associate the index with + the internal data structure. +*/ + +void *QPersistentModelIndex::internalPointer() const +{ + if (d) + return d->index.internalPointer(); + return 0; +} + +/*! + \fn void *QPersistentModelIndex::internalId() const + + \internal + + Returns a \c{qint64} used by the model to associate the index with + the internal data structure. +*/ + +qint64 QPersistentModelIndex::internalId() const +{ + if (d) + return d->index.internalId(); + return 0; +} + +/*! + Returns the parent QModelIndex for this persistent index, or + QModelIndex() if it has no parent. + + \sa child() sibling() model() +*/ +QModelIndex QPersistentModelIndex::parent() const +{ + if (d) + return d->index.parent(); + return QModelIndex(); +} + +/*! + Returns the sibling at \a row and \a column or an invalid + QModelIndex if there is no sibling at this position. + + \sa parent() child() +*/ + +QModelIndex QPersistentModelIndex::sibling(int row, int column) const +{ + if (d) + return d->index.sibling(row, column); + return QModelIndex(); +} + +/*! + Returns the child of the model index that is stored in the given + \a row and \a column. + + \sa parent() sibling() +*/ + +QModelIndex QPersistentModelIndex::child(int row, int column) const +{ + if (d) + return d->index.child(row, column); + return QModelIndex(); +} + +/*! + Returns the data for the given \a role for the item referred to by the index. + + \sa Qt::ItemDataRole, QAbstractItemModel::setData() +*/ +QVariant QPersistentModelIndex::data(int role) const +{ + if (d) + return d->index.data(role); + return QVariant(); +} + +/*! + \since 4.2 + + Returns the flags for the item referred to by the index. +*/ +Qt::ItemFlags QPersistentModelIndex::flags() const +{ + if (d) + return d->index.flags(); + return 0; +} + +/*! + Returns the model that the index belongs to. +*/ +const QAbstractItemModel *QPersistentModelIndex::model() const +{ + if (d) + return d->index.model(); + return 0; +} + +/*! + \fn bool QPersistentModelIndex::isValid() const + + Returns true if this persistent model index is valid; otherwise returns + false. + A valid index belongs to a model, and has non-negative row and column numbers. + + \sa model(), row(), column() +*/ + +bool QPersistentModelIndex::isValid() const +{ + return d && d->index.isValid(); +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QModelIndex &idx) +{ +#ifndef Q_BROKEN_DEBUG_STREAM + dbg.nospace() << "QModelIndex(" << idx.row() << "," << idx.column() + << "," << idx.internalPointer() << "," << idx.model() << ")"; + return dbg.space(); +#else + qWarning("This compiler doesn't support streaming QModelIndex to QDebug"); + return dbg; + Q_UNUSED(idx); +#endif +} + +QDebug operator<<(QDebug dbg, const QPersistentModelIndex &idx) +{ + if (idx.d) + dbg << idx.d->index; + else + dbg << QModelIndex(); + return dbg; +} +#endif + +class QEmptyItemModel : public QAbstractItemModel +{ +public: + explicit QEmptyItemModel(QObject *parent = 0) : QAbstractItemModel(parent) {} + QModelIndex index(int, int, const QModelIndex &) const { return QModelIndex(); } + QModelIndex parent(const QModelIndex &) const { return QModelIndex(); } + int rowCount(const QModelIndex &) const { return 0; } + int columnCount(const QModelIndex &) const { return 0; } + bool hasChildren(const QModelIndex &) const { return false; } + QVariant data(const QModelIndex &, int) const { return QVariant(); } +}; + +Q_GLOBAL_STATIC(QEmptyItemModel, qEmptyModel) + +QAbstractItemModel *QAbstractItemModelPrivate::staticEmptyModel() +{ + return qEmptyModel(); +} + +void QAbstractItemModelPrivate::removePersistentIndexData(QPersistentModelIndexData *data) +{ + if (data->index.isValid()) { + int removed = persistent.indexes.remove(data->index); + Q_ASSERT_X(removed == 1, "QPersistentModelIndex::~QPersistentModelIndex", + "persistent model indexes corrupted"); //maybe the index was somewhat invalid? + // This assert may happen if the model use changePersistentIndex in a way that could result on two + // QPersistentModelIndex pointing to the same index. + Q_UNUSED(removed); + } + // make sure our optimization still works + for (int i = persistent.moved.count() - 1; i >= 0; --i) { + int idx = persistent.moved[i].indexOf(data); + if (idx >= 0) + persistent.moved[i].remove(idx); + } + // update the references to invalidated persistent indexes + for (int i = persistent.invalidated.count() - 1; i >= 0; --i) { + int idx = persistent.invalidated[i].indexOf(data); + if (idx >= 0) + persistent.invalidated[i].remove(idx); + } + +} + +void QAbstractItemModelPrivate::rowsAboutToBeInserted(const QModelIndex &parent, + int first, int last) +{ + Q_Q(QAbstractItemModel); + Q_UNUSED(last); + QVector<QPersistentModelIndexData *> persistent_moved; + if (first < q->rowCount(parent)) { + for (QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it = persistent.indexes.constBegin(); + it != persistent.indexes.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + const QModelIndex &index = data->index; + if (index.row() >= first && index.isValid() && index.parent() == parent) { + persistent_moved.append(data); + } + } + } + persistent.moved.push(persistent_moved); +} + +void QAbstractItemModelPrivate::rowsInserted(const QModelIndex &parent, + int first, int last) +{ + QVector<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop(); + int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested + for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_moved.constBegin(); + it != persistent_moved.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + QModelIndex old = data->index; + persistent.indexes.erase(persistent.indexes.find(old)); + data->index = q_func()->index(old.row() + count, old.column(), parent); + if (data->index.isValid()) { + persistent.insertMultiAtEnd(data->index, data); + } else { + qWarning() << "QAbstractItemModel::endInsertRows: Invalid index (" << old.row() + count << "," << old.column() << ") in model" << q_func(); + } + } +} + +void QAbstractItemModelPrivate::rowsAboutToBeRemoved(const QModelIndex &parent, + int first, int last) +{ + QVector<QPersistentModelIndexData *> persistent_moved; + QVector<QPersistentModelIndexData *> persistent_invalidated; + // find the persistent indexes that are affected by the change, either by being in the removed subtree + // or by being on the same level and below the removed rows + for (QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it = persistent.indexes.constBegin(); + it != persistent.indexes.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + bool level_changed = false; + QModelIndex current = data->index; + while (current.isValid()) { + QModelIndex current_parent = current.parent(); + if (current_parent == parent) { // on the same level as the change + if (!level_changed && current.row() > last) // below the removed rows + persistent_moved.append(data); + else if (current.row() <= last && current.row() >= first) // in the removed subtree + persistent_invalidated.append(data); + break; + } + current = current_parent; + level_changed = true; + } + } + + persistent.moved.push(persistent_moved); + persistent.invalidated.push(persistent_invalidated); +} + +void QAbstractItemModelPrivate::rowsRemoved(const QModelIndex &parent, + int first, int last) +{ + QVector<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop(); + int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested + for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_moved.constBegin(); + it != persistent_moved.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + QModelIndex old = data->index; + persistent.indexes.erase(persistent.indexes.find(old)); + data->index = q_func()->index(old.row() - count, old.column(), parent); + if (data->index.isValid()) { + persistent.insertMultiAtEnd(data->index, data); + } else { + qWarning() << "QAbstractItemModel::endRemoveRows: Invalid index (" << old.row() - count << "," << old.column() << ") in model" << q_func(); + } + } + QVector<QPersistentModelIndexData *> persistent_invalidated = persistent.invalidated.pop(); + for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_invalidated.constBegin(); + it != persistent_invalidated.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + persistent.indexes.erase(persistent.indexes.find(data->index)); + data->index = QModelIndex(); + data->model = 0; + } +} + +void QAbstractItemModelPrivate::columnsAboutToBeInserted(const QModelIndex &parent, + int first, int last) +{ + Q_Q(QAbstractItemModel); + Q_UNUSED(last); + QVector<QPersistentModelIndexData *> persistent_moved; + if (first < q->columnCount(parent)) { + for (QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it = persistent.indexes.constBegin(); + it != persistent.indexes.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + const QModelIndex &index = data->index; + if (index.column() >= first && index.isValid() && index.parent() == parent) + persistent_moved.append(data); + } + } + persistent.moved.push(persistent_moved); +} + +void QAbstractItemModelPrivate::columnsInserted(const QModelIndex &parent, + int first, int last) +{ + QVector<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop(); + int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested + for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_moved.constBegin(); + it != persistent_moved.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + QModelIndex old = data->index; + persistent.indexes.erase(persistent.indexes.find(old)); + data->index = q_func()->index(old.row(), old.column() + count, parent); + if (data->index.isValid()) { + persistent.insertMultiAtEnd(data->index, data); + } else { + qWarning() << "QAbstractItemModel::endInsertColumns: Invalid index (" << old.row() << "," << old.column() + count << ") in model" << q_func(); + } + } +} + +void QAbstractItemModelPrivate::columnsAboutToBeRemoved(const QModelIndex &parent, + int first, int last) +{ + QVector<QPersistentModelIndexData *> persistent_moved; + QVector<QPersistentModelIndexData *> persistent_invalidated; + // find the persistent indexes that are affected by the change, either by being in the removed subtree + // or by being on the same level and to the right of the removed columns + for (QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it = persistent.indexes.constBegin(); + it != persistent.indexes.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + bool level_changed = false; + QModelIndex current = data->index; + while (current.isValid()) { + QModelIndex current_parent = current.parent(); + if (current_parent == parent) { // on the same level as the change + if (!level_changed && current.column() > last) // right of the removed columns + persistent_moved.append(data); + else if (current.column() <= last && current.column() >= first) // in the removed subtree + persistent_invalidated.append(data); + break; + } + current = current_parent; + level_changed = true; + } + } + + persistent.moved.push(persistent_moved); + persistent.invalidated.push(persistent_invalidated); + +} + +void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent, + int first, int last) +{ + QVector<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop(); + int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested + for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_moved.constBegin(); + it != persistent_moved.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + QModelIndex old = data->index; + persistent.indexes.erase(persistent.indexes.find(old)); + data->index = q_func()->index(old.row(), old.column() - count, parent); + if (data->index.isValid()) { + persistent.insertMultiAtEnd(data->index, data); + } else { + qWarning() << "QAbstractItemModel::endRemoveColumns: Invalid index (" << old.row() << "," << old.column() - count << ") in model" << q_func(); + } + } + QVector<QPersistentModelIndexData *> persistent_invalidated = persistent.invalidated.pop(); + for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_invalidated.constBegin(); + it != persistent_invalidated.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + persistent.indexes.erase(persistent.indexes.find(data->index)); + data->index = QModelIndex(); + data->model = 0; + } +} + +/*! + \class QModelIndex + + \brief The QModelIndex class is used to locate data in a data model. + + \ingroup model-view + \mainclass + + This class is used as an index into item models derived from + QAbstractItemModel. The index is used by item views, delegates, and + selection models to locate an item in the model. + + New QModelIndex objects are created by the model using the + QAbstractItemModel::createIndex() function. An \e invalid model index + can be constructed with the QModelIndex constructor. Invalid indexes are + often used as parent indexes when referring to top-level items in a model. + + Model indexes refer to items in models, and contain all the information + required to specify their locations in those models. Each index is located + in a given row and column, and may have a parent index; use row(), column(), + and parent() to obtain this information. Each top-level item in a model is + represented by a model index that does not have a parent index - in this + case, parent() will return an invalid model index, equivalent to an index + constructed with the zero argument form of the QModelIndex() constructor. + + To obtain a model index that refers to an existing item in a model, call + QAbstractItemModel::index() with the required row and column + values, and the model index of the parent. When referring to + top-level items in a model, supply QModelIndex() as the parent index. + + The model() function returns the model that the index references as a + QAbstractItemModel. + The child() function is used to examine the items held beneath the index + in the model. + The sibling() function allows you to traverse items in the model on the + same level as the index. + + \note Model indexes should be used immediately and then discarded. You + should not rely on indexes to remain valid after calling model functions + that change the structure of the model or delete items. If you need to + keep a model index over time use a QPersistentModelIndex. + + \sa \link model-view-programming.html Model/View Programming\endlink QPersistentModelIndex QAbstractItemModel +*/ + +/*! + \fn QModelIndex::QModelIndex() + + Creates a new empty model index. + This type of model index is used to indicate + that the position in the model is invalid. + + \sa isValid() QAbstractItemModel +*/ + +/*! + \fn QModelIndex::QModelIndex(int row, int column, void *data, const QAbstractItemModel *model) + + \internal + + Creates a new model index at the given \a row and \a column, + pointing to some \a data. +*/ + +/*! + \fn QModelIndex::QModelIndex(const QModelIndex &other) + + Creates a new model index that is a copy of the \a other model + index. +*/ + +/*! + \fn QModelIndex::~QModelIndex() + + Destroys the model index. +*/ + +/*! + \fn int QModelIndex::row() const + + Returns the row this model index refers to. +*/ + + +/*! + \fn int QModelIndex::column() const + + Returns the column this model index refers to. +*/ + + +/*! + \fn void *QModelIndex::internalPointer() const + + Returns a \c{void} \c{*} pointer used by the model to associate + the index with the internal data structure. + + \sa QAbstractItemModel::createIndex() +*/ + +/*! + \fn void *QModelIndex::internalId() const + + Returns a \c{qint64} used by the model to associate + the index with the internal data structure. + + \sa QAbstractItemModel::createIndex() +*/ + +/*! + \fn bool QModelIndex::isValid() const + + Returns true if this model index is valid; otherwise returns false. + A valid index belongs to a model, and has non-negative row and column numbers. + + \sa model(), row(), column() +*/ + +/*! + \fn const QAbstractItemModel *QModelIndex::model() const + + Returns a pointer to the model containing the item that this index + refers to. + + You receive a const pointer to the model because calls to + non-const functions of the model might invalidate the model index + - and possibly crash your application. +*/ + +/*! + \fn QModelIndex QModelIndex::sibling(int row, int column) const + + Returns the sibling at \a row and \a column or an invalid + QModelIndex if there is no sibling at this position. + + \sa parent() child() +*/ + +/*! + \fn QModelIndex QModelIndex::child(int row, int column) const + + Returns the child of the model index that is stored in the given + \a row and \a column. + + \sa parent() sibling() +*/ + +/*! + \fn QVariant QModelIndex::data(int role) const + + Returns the data for the given \a role for the item referred to by the index. +*/ + +/*! + \fn Qt::ItemFlags QModelIndex::flags() const + \since 4.2 + + Returns the flags for the item referred to by the index. +*/ + +/*! + \fn bool QModelIndex::operator==(const QModelIndex &other) const + + Returns true if this model index refers to the same location as + the \a other model index; otherwise returns false. + Note that all values in the model index are used when comparing + with another model index. +*/ + + +/*! + \fn bool QModelIndex::operator!=(const QModelIndex &other) const + + Returns true if this model index does not refer to the same + location as the \a other model index; otherwise returns false. +*/ + + +/*! + \fn QModelIndex QModelIndex::parent() const + + Returns the parent of the model index, or QModelIndex() if it has no + parent. + + \sa child() sibling() model() +*/ + +/*! + \class QAbstractItemModel + + \brief The QAbstractItemModel class provides the abstract interface for + item model classes. + + \ingroup model-view + \mainclass + + The QAbstractItemModel class defines the standard interface that item + models must use to be able to interoperate with other components in the + model/view architecture. It is not supposed to be instantiated directly. + Instead, you should subclass it to create new models. + + The QAbstractItemModel class is one of the \l{Model/View Classes} + and is part of Qt's \l{Model/View Programming}{model/view framework}. + + If you need a model to use with a QListView or a QTableView, you should + consider subclassing QAbstractListModel or QAbstractTableModel instead of + this class. + + The underlying data model is exposed to views and delegates as a hierarchy + of tables. If you do not make use of the hierarchy, then the model is a + simple table of rows and columns. Each item has a unique index specified by + a QModelIndex. + + \img modelindex-no-parent.png + + Every item of data that can be accessed via a model has an associated model + index. You can obtain this model index using the index() function. Each + index may have a sibling() index; child items have a parent() index. + + Each item has a number of data elements associated with it and they can be + retrieved by specifying a role (see \l Qt::ItemDataRole) to the model's + data() function. Data for all available roles can be obtained at the same + time using the itemData() function. + + Data for each role is set using a particular \l Qt::ItemDataRole. Data for + individual roles are set individually with setData(), or they can be set + for all roles with setItemData(). + + Items can be queried with flags() (see \l Qt::ItemFlag) to see if they can + be selected, dragged, or manipulated in other ways. + + If an item has child objects, hasChildren() returns true for the + corresponding index. + + The model has a rowCount() and a columnCount() for each level of the + hierarchy. Rows and columns can be inserted and removed with insertRows(), + insertColumns(), removeRows(), and removeColumns(). + + The model emits signals to indicate changes. For example, dataChanged() is + emitted whenever items of data made available by the model are changed. + Changes to the headers supplied by the model cause headerDataChanged() to + be emitted. If the structure of the underlying data changes, the model can + emit layoutChanged() to indicate to any attached views that they should + redisplay any items shown, taking the new structure into account. + + The items available through the model can be searched for particular data + using the match() function. + + To sort the model, you can use sort(). + + + \section1 Subclassing + + \note Some general guidelines for subclassing models are available in the + \l{Model Subclassing Reference}. + + When subclassing QAbstractItemModel, at the very least you must implement + index(), parent(), rowCount(), columnCount(), and data(). These functions + are used in all read-only models, and form the basis of editable models. + + You can also reimplement hasChildren() to provide special behavior for + models where the implementation of rowCount() is expensive. This makes it + possible for models to restrict the amount of data requested by views, and + can be used as a way to implement lazy population of model data. + + To enable editing in your model, you must also implement setData(), and + reimplement flags() to ensure that \c ItemIsEditable is returned. You can + also reimplement headerData() and setHeaderData() to control the way the + headers for your model are presented. + + The dataChanged() and headerDataChanged() signals must be emitted + explicitly when reimplementing the setData() and setHeaderData() functions, + respectively. + + Custom models need to create model indexes for other components to use. To + do this, call createIndex() with suitable row and column numbers for the + item, and an identifier for it, either as a pointer or as an integer value. + The combination of these values must be unique for each item. Custom models + typically use these unique identifiers in other reimplemented functions to + retrieve item data and access information about the item's parents and + children. See the \l{Simple Tree Model Example} for more information about + unique identifiers. + + It is not necessary to support every role defined in Qt::ItemDataRole. + Depending on the type of data contained within a model, it may only be + useful to implement the data() function to return valid information for + some of the more common roles. Most models provide at least a textual + representation of item data for the Qt::DisplayRole, and well-behaved + models should also provide valid information for the Qt::ToolTipRole and + Qt::WhatsThisRole. Supporting these roles enables models to be used with + standard Qt views. However, for some models that handle highly-specialized + data, it may be appropriate to provide data only for user-defined roles. + + Models that provide interfaces to resizable data structures can provide + implementations of insertRows(), removeRows(), insertColumns(),and + removeColumns(). When implementing these functions, it is important to + notify any connected views about changes to the model's dimensions both + \e before and \e after they occur: + + \list + \o An insertRows() implementation must call beginInsertRows() \e before + inserting new rows into the data structure, and endInsertRows() + \e{immediately afterwards}. + \o An insertColumns() implementation must call beginInsertColumns() + \e before inserting new columns into the data structure, and + endInsertColumns() \e{immediately afterwards}. + \o A removeRows() implementation must call beginRemoveRows() \e before + the rows are removed from the data structure, and endRemoveRows() + \e{immediately afterwards}. + \o A removeColumns() implementation must call beginRemoveColumns() + \e before the columns are removed from the data structure, and + endRemoveColumns() \e{immediately afterwards}. + \endlist + + The \e private signals that these functions emit give attached components + the chance to take action before any data becomes unavailable. The + encapsulation of the insert and remove operations with these begin and end + functions also enables the model to manage \l{QPersistentModelIndex} + {persistent model indexes} correctly. \bold{If you want selections to be + handled properly, you must ensure that you call these functions.} If you + insert or remove an item with children, you do not need to call these + functions for the child items. In other words, the parent item will take + care of its child items. + + To create models that populate incrementally, you can reimplement + fetchMore() and canFetchMore(). If the reimplementation of fetchMore() adds + rows to the model, \l{QAbstractItemModel::}{beginInsertRows()} and + \l{QAbstractItemModel::}{endInsertRows()} must be called. + + \sa {Model Classes}, {Model Subclassing Reference}, QModelIndex, + QAbstractItemView, {Using Drag and Drop with Item Views}, + {Simple DOM Model Example}, + {Simple Tree Model Example}, {Editable Tree Model Example}, + {Fetch More Example} +*/ + +/*! + \fn QModelIndex QAbstractItemModel::index(int row, int column, const QModelIndex &parent) const = 0 + + Returns the index of the item in the model specified by the given \a row, + \a column and \a parent index. + + When reimplementing this function in a subclass, call createIndex() to generate + model indexes that other components can use to refer to items in your model. + + \sa createIndex() +*/ + +/*! + \fn bool QAbstractItemModel::insertColumn(int column, const QModelIndex &parent) + + Inserts a single column before the given \a column in the child items of + the \a parent specified. Returns true if the column is inserted; otherwise + returns false. + + \sa insertColumns() insertRow() removeColumn() +*/ + +/*! + \fn bool QAbstractItemModel::insertRow(int row, const QModelIndex &parent) + + Inserts a single row before the given \a row in the child items of the + \a parent specified. Returns true if the row is inserted; otherwise + returns false. + + \sa insertRows() insertColumn() removeRow() +*/ + +/*! + \fn QObject *QAbstractItemModel::parent() const + \internal +*/ + +/*! + \fn QModelIndex QAbstractItemModel::parent(const QModelIndex &index) const = 0 + + Returns the parent of the model item with the given \a index, or QModelIndex() + if it has no parent. + + A common convention used in models that expose tree data structures is that + only items in the first column have children. For that case, when reimplementing + this function in a subclass the column of the returned QModelIndex would be 0. + + \note When reimplementing this function in a subclass, be careful to avoid + calling QModelIndex member functions, such as QModelIndex::parent(), since + indexes belonging to your model will simply call your implementation, leading + to infinite recursion. + + \sa createIndex() +*/ + +/*! + \fn bool QAbstractItemModel::removeColumn(int column, const QModelIndex &parent) + + Removes the given \a column from the child items of the \a parent specified. + Returns true if the column is removed; otherwise returns false. + + \sa removeColumns(), removeRow(), insertColumn() +*/ + +/*! + \fn bool QAbstractItemModel::removeRow(int row, const QModelIndex &parent) + + Removes the given \a row from the child items of the \a parent specified. + Returns true if the row is removed; otherwise returns false. + + The removeRow() is a convenience function that calls removeRows(). + The QAbstractItemModel implementation of removeRows does nothing. + + \sa removeRows(), removeColumn(), insertRow() +*/ + +/*! + \fn void QAbstractItemModel::headerDataChanged(Qt::Orientation orientation, int first, int last) + + This signal is emitted whenever a header is changed. The \a orientation + indicates whether the horizontal or vertical header has changed. The + sections in the header from the \a first to the \a last need to be updated. + + Note that this signal must be emitted explicitly when + reimplementing the setHeaderData() function. + + If you are changing the number of columns or rows you don't need + to emit this signal, but use the begin/end functions (see the + section on subclassing in the QAbstractItemModel class description + for details). + + \sa headerData(), setHeaderData(), dataChanged() +*/ + +/*! + \fn void QAbstractItemModel::layoutAboutToBeChanged() + \since 4.2 + + This signal is emitted just before the layout of a model is changed. + Components connected to this signal use it to adapt to changes + in the model's layout. + + Subclasses should update any persistent model indexes after emitting + layoutAboutToBeChanged(). + + \sa layoutChanged(), changePersistentIndex() +*/ + +/*! + \fn void QAbstractItemModel::layoutChanged() + + This signal is emitted whenever the layout of items exposed by the model + has changed; for example, when the model has been sorted. When this signal is + received by a view, it should update the layout of items to reflect this + change. + + When subclassing QAbstractItemModel or QAbstractProxyModel, ensure that + you emit layoutAboutToBeChanged() before changing the order of items or + altering the structure of the data you expose to views, and emit + layoutChanged() after changing the layout. + + Subclasses should update any persistent model indexes before + emitting layoutChanged(). + + \sa layoutAboutToBeChanged(), dataChanged(), headerDataChanged(), reset(), changePersistentIndex() +*/ + +/*! + Constructs an abstract item model with the given \a parent. +*/ +QAbstractItemModel::QAbstractItemModel(QObject *parent) + : QObject(*new QAbstractItemModelPrivate, parent) +{ +} + +/*! + \internal +*/ +QAbstractItemModel::QAbstractItemModel(QAbstractItemModelPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + +/*! + Destroys the abstract item model. +*/ +QAbstractItemModel::~QAbstractItemModel() +{ + d_func()->invalidatePersistentIndexes(); +} + +/*! + \fn QModelIndex QAbstractItemModel::sibling(int row, int column, const QModelIndex &index) const + + Returns the sibling at \a row and \a column for the item at \a index, or + an invalid QModelIndex if there is no sibling at that location. + + sibling() is just a convenience function that finds the item's parent, and + uses it to retrieve the index of the child item in the specified \a row + and \a column. + + \sa index(), QModelIndex::row(), QModelIndex::column() +*/ + + +/*! + \fn int QAbstractItemModel::rowCount(const QModelIndex &parent) const + + Returns the number of rows under the given \a parent. When the parent + is valid it means that rowCount is returning the number of children of parent. + + \bold{Tip:} When implementing a table based model, rowCount() should return 0 when + the parent is valid. + + \sa columnCount() +*/ + +/*! + \fn int QAbstractItemModel::columnCount(const QModelIndex &parent) const + + Returns the number of columns for the children of the given \a parent. + + In most subclasses, the number of columns is independent of the + \a parent. For example: + + \snippet examples/itemviews/simpledommodel/dommodel.cpp 2 + + \bold{Tip:} When implementing a table based model, columnCount() should return 0 when + the parent is valid. + + \sa rowCount() +*/ + +/*! + \fn void QAbstractItemModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) + + This signal is emitted whenever the data in an existing item changes. + + If the items are of the same parent, the affected ones are those between + \a topLeft and \a bottomRight inclusive. If the items do not have the same + parent, the behavior is undefined. + + When reimplementing the setData() function, this signal must be emitted + explicitly. + + \sa headerDataChanged(), setData(), layoutChanged() +*/ + +/*! + \fn void QAbstractItemModel::rowsInserted(const QModelIndex &parent, int start, int end) + + This signal is emitted after rows have been inserted into the + model. The new items are those between \a start and \a end + inclusive, under the given \a parent item. + + \bold{Note:} Components connected to this signal use it to adapt to changes + in the model's dimensions. It can only be emitted by the QAbstractItemModel + implementation, and cannot be explicitly emitted in subclass code. + + \sa insertRows(), beginInsertRows() +*/ + +/*! + \fn void QAbstractItemModel::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) + + This signal is emitted just before rows are inserted into the + model. The new items will be positioned between \a start and \a end + inclusive, under the given \a parent item. + + \bold{Note:} Components connected to this signal use it to adapt to changes + in the model's dimensions. It can only be emitted by the QAbstractItemModel + implementation, and cannot be explicitly emitted in subclass code. + + \sa insertRows(), beginInsertRows() +*/ + +/*! + \fn void QAbstractItemModel::rowsRemoved(const QModelIndex &parent, int start, int end) + + This signal is emitted after rows have been removed from the + model. The removed items are those between \a start and \a end + inclusive, under the given \a parent item. + + \bold{Note:} Components connected to this signal use it to adapt to changes + in the model's dimensions. It can only be emitted by the QAbstractItemModel + implementation, and cannot be explicitly emitted in subclass code. + + \sa removeRows(), beginRemoveRows() +*/ + +/*! + \fn void QAbstractItemModel::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) + + This signal is emitted just before rows are removed from the + model. The items that will be removed are those between \a start and \a end + inclusive, under the given \a parent item. + + \bold{Note:} Components connected to this signal use it to adapt to changes + in the model's dimensions. It can only be emitted by the QAbstractItemModel + implementation, and cannot be explicitly emitted in subclass code. + + \sa removeRows(), beginRemoveRows() +*/ + +/*! + \fn void QAbstractItemModel::columnsInserted(const QModelIndex &parent, int start, int end) + + This signal is emitted after columns have been inserted into the + model. The new items are those between \a start and \a end + inclusive, under the given \a parent item. + + \bold{Note:} Components connected to this signal use it to adapt to changes + in the model's dimensions. It can only be emitted by the QAbstractItemModel + implementation, and cannot be explicitly emitted in subclass code. + + \sa insertColumns(), beginInsertColumns() +*/ + +/*! + \fn void QAbstractItemModel::columnsAboutToBeInserted(const QModelIndex &parent, int start, int end) + + This signal is emitted just before columns are inserted into the + model. The new items will be positioned between \a start and \a end + inclusive, under the given \a parent item. + + \bold{Note:} Components connected to this signal use it to adapt to changes + in the model's dimensions. It can only be emitted by the QAbstractItemModel + implementation, and cannot be explicitly emitted in subclass code. + + \sa insertColumns(), beginInsertColumns() +*/ + +/*! + \fn void QAbstractItemModel::columnsRemoved(const QModelIndex &parent, int start, int end) + + This signal is emitted after columns have been removed from the + model. The removed items are those between \a start and \a end + inclusive, under the given \a parent item. + + \bold{Note:} Components connected to this signal use it to adapt to changes + in the model's dimensions. It can only be emitted by the QAbstractItemModel + implementation, and cannot be explicitly emitted in subclass code. + + \sa removeColumns(), beginRemoveColumns() +*/ + +/*! + \fn void QAbstractItemModel::columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) + + This signal is emitted just before columns are removed + from the model. The items to be removed are those between \a start and + \a end inclusive, under the given \a parent item. + + \bold{Note:} Components connected to this signal use it to adapt to changes + in the model's dimensions. It can only be emitted by the QAbstractItemModel + implementation, and cannot be explicitly emitted in subclass code. + + \sa removeColumns(), beginRemoveColumns() +*/ + +/*! + Returns true if the model returns a valid QModelIndex for \a row and + \a column with \a parent, otherwise returns false. +*/ +bool QAbstractItemModel::hasIndex(int row, int column, const QModelIndex &parent) const +{ + if (row < 0 || column < 0) + return false; + return row < rowCount(parent) && column < columnCount(parent); +} + + +/*! + Returns true if \a parent has any children; otherwise returns false. + Use rowCount() on the parent to find out the number of children. + + \sa parent() index() +*/ +bool QAbstractItemModel::hasChildren(const QModelIndex &parent) const +{ + return (rowCount(parent) > 0) && (columnCount(parent) > 0); +} + + +/*! + Returns a map with values for all predefined roles in the model + for the item at the given \a index. + + Reimplemented this function if you want to extend the default behavior + of this function to include custom roles in the map. + + \sa Qt::ItemDataRole, data() +*/ +QMap<int, QVariant> QAbstractItemModel::itemData(const QModelIndex &index) const +{ + QMap<int, QVariant> roles; + for (int i = 0; i < Qt::UserRole; ++i) { + QVariant variantData = data(index, i); + if (variantData.type() != QVariant::Invalid) + roles.insert(i, variantData); + } + return roles; +} + +/*! + Sets the \a role data for the item at \a index to \a value. + Returns true if successful; otherwise returns false. + + The dataChanged() signal should be emitted if the data was successfully set. + + The base class implementation returns false. This function and + data() must be reimplemented for editable models. Note that the + dataChanged() signal must be emitted explicitly when + reimplementing this function. + + \sa Qt::ItemDataRole, data(), itemData() +*/ +bool QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + Q_UNUSED(index); + Q_UNUSED(value); + Q_UNUSED(role); + return false; +} + +/*! + \fn QVariant QAbstractItemModel::data(const QModelIndex &index, int role) const = 0 + + Returns the data stored under the given \a role for the item referred to + by the \a index. + + \note If you do not have a value to return, return an \bold invalid + QVariant() instead of returning 0. + + \sa Qt::ItemDataRole, setData(), headerData() +*/ + +/*! + Sets the role data for the item at \a index to the associated value in + \a roles, for every Qt::ItemDataRole. Returns true if successful; otherwise + returns false. + + Roles that are not in \a roles will not be modified. + + \sa setData() data() itemData() +*/ +bool QAbstractItemModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles) +{ + bool b = true; + for (QMap<int, QVariant>::ConstIterator it = roles.begin(); it != roles.end(); ++it) + b = b && setData(index, it.value(), it.key()); + return b; +} + +/*! + Returns a list of MIME types that can be used to describe a list of + model indexes. + + \sa mimeData() +*/ +QStringList QAbstractItemModel::mimeTypes() const +{ + QStringList types; + types << QLatin1String("application/x-qabstractitemmodeldatalist"); + return types; +} + +/*! + Returns an object that contains serialized items of data corresponding to the + list of \a indexes specified. The formats used to describe the encoded data + is obtained from the mimeTypes() function. + + If the list of indexes is empty, or there are no supported MIME types, + 0 is returned rather than a serialized empty list. + + \sa mimeTypes(), dropMimeData() +*/ +QMimeData *QAbstractItemModel::mimeData(const QModelIndexList &indexes) const +{ + if (indexes.count() <= 0) + return 0; + QStringList types = mimeTypes(); + if (types.isEmpty()) + return 0; + QMimeData *data = new QMimeData(); + QString format = types.at(0); + QByteArray encoded; + QDataStream stream(&encoded, QIODevice::WriteOnly); + encodeData(indexes, stream); + data->setData(format, encoded); + return data; +} + +/*! + Handles the \a data supplied by a drag and drop operation that ended with + the given \a action. Returns true if the data and action can be handled + by the model; otherwise returns false. + + Although the specified \a row, \a column and \a parent indicate the location of + an item in the model where the operation ended, it is the responsibility of the + view to provide a suitable location for where the data should be inserted. + + For instance, a drop action on an item in a QTreeView can result in new items + either being inserted as children of the item specified by \a row, \a column, + and \a parent, or as siblings of the item. + + When row and column are -1 it means that it is up to the model to decide + where to place the data. This can occur in a tree when data is dropped + on a parent. Models will usually append the data to the parent in this case. + + Returns true if the dropping was successful otherwise false. + + \sa supportedDropActions(), {Using Drag and Drop with Item Views} +*/ +bool QAbstractItemModel::dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) +{ + // check if the action is supported + if (!data || !(action == Qt::CopyAction || action == Qt::MoveAction)) + return false; + // check if the format is supported + QStringList types = mimeTypes(); + if (types.isEmpty()) + return false; + QString format = types.at(0); + if (!data->hasFormat(format)) + return false; + if (row > rowCount(parent)) + row = rowCount(parent); + if (row == -1) + row = rowCount(parent); + if (column == -1) + column = 0; + // decode and insert + QByteArray encoded = data->data(format); + QDataStream stream(&encoded, QIODevice::ReadOnly); + return decodeData(row, column, parent, stream); +} + +/*! + \since 4.2 + + Returns the drop actions supported by this model. + + The default implementation returns Qt::CopyAction. Reimplement this + function if you wish to support additional actions. Note that you + must also reimplement the dropMimeData() function to handle the + additional operations. + + \sa dropMimeData(), Qt::DropActions, {Using Drag and Drop with Item + Views} +*/ +Qt::DropActions QAbstractItemModel::supportedDropActions() const +{ + return Qt::CopyAction; +} + +/*! + Returns the actions supported by the data in this model. + + The default implementation returns supportedDropActions() unless + specific values have been set with setSupportedDragActions(). + + supportedDragActions() is used by QAbstractItemView::startDrag() as + the default values when a drag occurs. + + \sa Qt::DropActions, {Using Drag and Drop with Item Views} +*/ +Qt::DropActions QAbstractItemModel::supportedDragActions() const +{ + // ### Qt 5: make this virtual or these properties + Q_D(const QAbstractItemModel); + if (d->supportedDragActions != -1) + return d->supportedDragActions; + return supportedDropActions(); +} + +/*! + \since 4.2 + + Sets the supported drag \a actions for the items in the model. + + \sa supportedDragActions(), {Using Drag and Drop with Item Views} +*/ +void QAbstractItemModel::setSupportedDragActions(Qt::DropActions actions) +{ + Q_D(QAbstractItemModel); + d->supportedDragActions = actions; +} + +/*! + On models that support this, inserts \a count rows into the model before the + given \a row. The items in the new row will be children of the item + represented by the \a parent model index. + + If \a row is 0, the rows are prepended to any existing rows in the parent. + If \a row is rowCount(), the rows are appended to any existing rows in the + parent. + If \a parent has no children, a single column with \a count rows is inserted. + + Returns true if the rows were successfully inserted; otherwise returns + false. + + The base class implementation does nothing and returns false. + + If you implement your own model, you can reimplement this function + if you want to support insertions. Alternatively, you can provide + you own API for altering the data. + + \sa insertColumns(), removeRows(), beginInsertRows(), endInsertRows() +*/ +bool QAbstractItemModel::insertRows(int, int, const QModelIndex &) +{ + return false; +} + +/*! + On models that support this, inserts \a count new columns into the model + before the given \a column. The items in each new column will be children + of the item represented by the \a parent model index. + + If \a column is 0, the columns are prepended to any existing columns. + If \a column is columnCount(), the columns are appended to any existing + columns. + If \a parent has no children, a single row with \a count columns is inserted. + + Returns true if the columns were successfully inserted; otherwise returns + false. + + The base class implementation does nothing and returns false. + + If you implement your own model, you can reimplement this function + if you want to support insertions. Alternatively, you can provide + you own API for altering the data. + + \sa insertRows(), removeColumns(), beginInsertColumns(), endInsertColumns() +*/ +bool QAbstractItemModel::insertColumns(int, int, const QModelIndex &) +{ + return false; +} + +/*! + On models that support this, removes \a count rows starting with the given + \a row under parent \a parent from the model. Returns true if the rows + were successfully removed; otherwise returns false. + + The base class implementation does nothing and returns false. + + If you implement your own model, you can reimplement this function + if you want to support removing. Alternatively, you can provide + you own API for altering the data. + + \sa removeRow(), removeColumns(), insertColumns(), beginRemoveRows(), endRemoveRows() +*/ +bool QAbstractItemModel::removeRows(int, int, const QModelIndex &) +{ + return false; +} + +/*! + On models that support this, removes \a count columns starting with the + given \a column under parent \a parent from the model. Returns true if the + columns were successfully removed; otherwise returns false. + + The base class implementation does nothing and returns false. + + If you implement your own model, you can reimplement this function + if you want to support removing. Alternatively, you can provide + you own API for altering the data. + + \sa removeColumn(), removeRows(), insertColumns(), beginRemoveColumns(), endRemoveColumns() +*/ +bool QAbstractItemModel::removeColumns(int, int, const QModelIndex &) +{ + return false; +} + +/*! + Fetches any available data for the items with the parent specified by the + \a parent index. + + Reimplement this if you are populating your model incrementally. + + The default implementation does nothing. + + \sa canFetchMore() +*/ +void QAbstractItemModel::fetchMore(const QModelIndex &) +{ + // do nothing +} + +/*! + Returns true if there is more data available for \a parent; otherwise returns + false. + + The default implementation always returns false. + + If canFetchMore() returns true, QAbstractItemView will call fetchMore(). + However, the fetchMore() function is only called when the model is being + populated incrementally. + + \sa fetchMore() +*/ +bool QAbstractItemModel::canFetchMore(const QModelIndex &) const +{ + return false; +} + +/*! + Returns the item flags for the given \a index. + + The base class implementation returns a combination of flags that + enables the item (\c ItemIsEnabled) and allows it to be + selected (\c ItemIsSelectable). + + \sa Qt::ItemFlags +*/ +Qt::ItemFlags QAbstractItemModel::flags(const QModelIndex &index) const +{ + Q_D(const QAbstractItemModel); + if (!d->indexValid(index)) + return 0; + + return Qt::ItemIsSelectable|Qt::ItemIsEnabled; +} + +/*! + Sorts the model by \a column in the given \a order. + + The base class implementation does nothing. +*/ +void QAbstractItemModel::sort(int column, Qt::SortOrder order) +{ + Q_UNUSED(column); + Q_UNUSED(order); + // do nothing +} + +/*! + Returns a model index for the buddy of the item represented by \a index. + When the user wants to edit an item, the view will call this function to + check whether another item in the model should be edited instead, and + construct a delegate using the model index returned by the buddy item. + + In the default implementation each item is its own buddy. +*/ +QModelIndex QAbstractItemModel::buddy(const QModelIndex &index) const +{ + return index; +} + +/*! + Returns a list of indexes for the items in the column of the \a + start index where the data stored under the given \a role matches + the specified \a value. The way the search is performed is defined + by the \a flags given. The list that is returned may be empty. + + The search starts from the \a start index, and continues until the + number of matching data items equals \a hits, the search reaches + the last row, or the search reaches \a start again, depending on + whether \c MatchWrap is specified in \a flags. If you want to search + for all matching items, use \a hits = -1. + + By default, this function will perform a wrapping, string-based comparison + on all items, searching for items that begin with the search term specified + by \a value. + + \note The default implementation of this function only searches columns, + This function can be reimplemented to include other search behavior. +*/ +QModelIndexList QAbstractItemModel::match(const QModelIndex &start, int role, + const QVariant &value, int hits, + Qt::MatchFlags flags) const +{ + QModelIndexList result; + uint matchType = flags & 0x0F; + Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; + bool recurse = flags & Qt::MatchRecursive; + bool wrap = flags & Qt::MatchWrap; + bool allHits = (hits == -1); + QString text; // only convert to a string if it is needed + QModelIndex p = parent(start); + int from = start.row(); + int to = rowCount(p); + + // iterates twice if wrapping + for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) { + for (int r = from; (r < to) && (allHits || result.count() < hits); ++r) { + QModelIndex idx = index(r, start.column(), p); + if (!idx.isValid()) + continue; + QVariant v = data(idx, role); + // QVariant based matching + if (matchType == Qt::MatchExactly) { + if (value == v) + result.append(idx); + } else { // QString based matching + if (text.isEmpty()) // lazy conversion + text = value.toString(); + QString t = v.toString(); + switch (matchType) { + case Qt::MatchRegExp: + if (QRegExp(text, cs).exactMatch(t)) + result.append(idx); + break; + case Qt::MatchWildcard: + if (QRegExp(text, cs, QRegExp::Wildcard).exactMatch(t)) + result.append(idx); + break; + case Qt::MatchStartsWith: + if (t.startsWith(text, cs)) + result.append(idx); + break; + case Qt::MatchEndsWith: + if (t.endsWith(text, cs)) + result.append(idx); + break; + case Qt::MatchFixedString: + if (t.compare(text, cs) == 0) + result.append(idx); + break; + case Qt::MatchContains: + default: + if (t.contains(text, cs)) + result.append(idx); + } + } + if (recurse && hasChildren(idx)) { // search the hierarchy + result += match(index(0, idx.column(), idx), role, + (text.isEmpty() ? value : text), + (allHits ? -1 : hits - result.count()), flags); + } + } + // prepare for the next iteration + from = 0; + to = start.row(); + } + return result; +} + +/*! + Returns the row and column span of the item represented by \a index. + + Note: span is not used currently, but will be in the future. +*/ + +QSize QAbstractItemModel::span(const QModelIndex &) const +{ + return QSize(1, 1); +} + +/*! + Called to let the model know that it should submit whatever it has cached + to the permanent storage. Typically used for row editing. + + Returns false on error, otherwise true. +*/ + +bool QAbstractItemModel::submit() +{ + return true; +} + +/*! + Called to let the model know that it should discard whatever it has cached. + Typically used for row editing. +*/ + +void QAbstractItemModel::revert() +{ + // do nothing +} + +/*! + Returns the data for the given \a role and \a section in the header + with the specified \a orientation. + + For horizontal headers, the section number corresponds to the column + number of items shown beneath it. For vertical headers, the section + number typically to the row number of items shown alongside it. + + \sa Qt::ItemDataRole, setHeaderData(), QHeaderView +*/ + +QVariant QAbstractItemModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + Q_UNUSED(orientation); + if (role == Qt::DisplayRole) + return section + 1; + return QVariant(); +} + +/*! + Sets the data for the given \a role and \a section in the header with + the specified \a orientation to the \a value supplied. + Returns true if the header's data was updated; otherwise returns false. + + Note that the headerDataChanged() signal must be emitted explicitly + when reimplementing this function. + + \sa Qt::ItemDataRole, headerData() +*/ + +bool QAbstractItemModel::setHeaderData(int section, Qt::Orientation orientation, + const QVariant &value, int role) +{ + Q_UNUSED(section); + Q_UNUSED(orientation); + Q_UNUSED(value); + Q_UNUSED(role); + return false; +} + +/*! + \fn QModelIndex QAbstractItemModel::createIndex(int row, int column, void *ptr) const + + Creates a model index for the given \a row and \a column with the internal pointer \a ptr. + + Note that when you are using a QSortFilterProxyModel its indexes have their own + internal pointer. It is not advisable to access the internal pointer in the index + outside of the model. Use the data() function instead. + + This function provides a consistent interface that model subclasses must + use to create model indexes. +*/ + +/*! + \fn QModelIndex QAbstractItemModel::createIndex(int row, int column, int id) const + \obsolete + + Use QModelIndex QAbstractItemModel::createIndex(int row, int column, quint32 id) instead. +*/ + +/*! + \fn QModelIndex QAbstractItemModel::createIndex(int row, int column, quint32 id) const + + Creates a model index for the given \a row and \a column with the internal + identifier, \a id. + + This function provides a consistent interface that model subclasses must + use to create model indexes. + \sa QModelIndex::internalId() +*/ + +/*! + \internal +*/ +void QAbstractItemModel::encodeData(const QModelIndexList &indexes, QDataStream &stream) const +{ + QModelIndexList::ConstIterator it = indexes.begin(); + for (; it != indexes.end(); ++it) + stream << (*it).row() << (*it).column() << itemData(*it); +} + +/*! + \internal + */ +bool QAbstractItemModel::decodeData(int row, int column, const QModelIndex &parent, + QDataStream &stream) +{ + int top = INT_MAX; + int left = INT_MAX; + int bottom = 0; + int right = 0; + QVector<int> rows, columns; + QVector<QMap<int, QVariant> > data; + + while (!stream.atEnd()) { + int r, c; + QMap<int, QVariant> v; + stream >> r >> c >> v; + rows.append(r); + columns.append(c); + data.append(v); + top = qMin(r, top); + left = qMin(c, left); + bottom = qMax(r, bottom); + right = qMax(c, right); + } + + // insert the dragged items into the table, use a bit array to avoid overwriting items, + // since items from different tables can have the same row and column + int dragRowCount = 0; + int dragColumnCount = right - left + 1; + + // Compute the number of continuous rows upon insertion and modify the rows to match + QVector<int> rowsToInsert(bottom + 1); + for (int i = 0; i < rows.count(); ++i) + rowsToInsert[rows.at(i)] = 1; + for (int i = 0; i < rowsToInsert.count(); ++i) { + if (rowsToInsert[i] == 1){ + rowsToInsert[i] = dragRowCount; + ++dragRowCount; + } + } + for (int i = 0; i < rows.count(); ++i) + rows[i] = top + rowsToInsert[rows[i]]; + + QBitArray isWrittenTo(dragRowCount * dragColumnCount); + + // make space in the table for the dropped data + int colCount = columnCount(parent); + if (colCount == 0) { + insertColumns(colCount, dragColumnCount - colCount, parent); + colCount = columnCount(parent); + } + insertRows(row, dragRowCount, parent); + + row = qMax(0, row); + column = qMax(0, column); + + QVector<QPersistentModelIndex> newIndexes(data.size()); + // set the data in the table + for (int j = 0; j < data.size(); ++j) { + int relativeRow = rows.at(j) - top; + int relativeColumn = columns.at(j) - left; + int destinationRow = relativeRow + row; + int destinationColumn = relativeColumn + column; + int flat = (relativeRow * dragColumnCount) + relativeColumn; + // if the item was already written to, or we just can't fit it in the table, create a new row + if (destinationColumn >= colCount || isWrittenTo.testBit(flat)) { + destinationColumn = qBound(column, destinationColumn, colCount - 1); + destinationRow = row + dragRowCount; + insertRows(row + dragRowCount, 1, parent); + flat = (dragRowCount * dragColumnCount) + relativeColumn; + isWrittenTo.resize(++dragRowCount * dragColumnCount); + } + if (!isWrittenTo.testBit(flat)) { + newIndexes[j] = index(destinationRow, destinationColumn, parent); + isWrittenTo.setBit(flat); + } + } + + for(int k = 0; k < newIndexes.size(); k++) { + if (newIndexes.at(k).isValid()) + setItemData(newIndexes.at(k), data.at(k)); + } + + return true; +} + +/*! + Begins a row insertion operation. + + When reimplementing insertRows() in a subclass, you must call this + function \e before inserting data into the model's underlying data + store. + + The \a parent index corresponds to the parent into which the new + rows are inserted; \a first and \a last are the row numbers that the + new rows will have after they have been inserted. + + \table 80% + \row \o \inlineimage modelview-begin-insert-rows.png Inserting rows + \o Specify the first and last row numbers for the span of rows + you want to insert into an item in a model. + + For example, as shown in the diagram, we insert three rows before + row 2, so \a first is 2 and \a last is 4: + \snippet doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp 0 + This inserts the three new rows as rows 2, 3, and 4. + \row + \o \inlineimage modelview-begin-append-rows.png Appending rows + \o To append rows, insert them after the last row. + + For example, as shown in the diagram, we append two rows to a + collection of 4 existing rows (ending in row 3), so \a first is 4 + and \a last is 5: + \snippet doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp 1 + This appends the two new rows as rows 4 and 5. + \endtable + + \sa endInsertRows() +*/ +void QAbstractItemModel::beginInsertRows(const QModelIndex &parent, int first, int last) +{ + Q_ASSERT(first >= 0); + Q_ASSERT(last >= first); + Q_D(QAbstractItemModel); + d->changes.push(QAbstractItemModelPrivate::Change(parent, first, last)); + emit rowsAboutToBeInserted(parent, first, last); + d->rowsAboutToBeInserted(parent, first, last); +} + +/*! + Ends a row insertion operation. + + When reimplementing insertRows() in a subclass, you must call this + function \e after inserting data into the model's underlying data + store. + + \sa beginInsertRows() +*/ +void QAbstractItemModel::endInsertRows() +{ + Q_D(QAbstractItemModel); + QAbstractItemModelPrivate::Change change = d->changes.pop(); + d->rowsInserted(change.parent, change.first, change.last); + emit rowsInserted(change.parent, change.first, change.last); +} + +/*! + Begins a row removal operation. + + When reimplementing removeRows() in a subclass, you must call this + function \e before removing data from the model's underlying data + store. + + The \a parent index corresponds to the parent from which the new + rows are removed; \a first and \a last are the row numbers of the + rows to be removed. + + \table 80% + \row \o \inlineimage modelview-begin-remove-rows.png Removing rows + \o Specify the first and last row numbers for the span of rows + you want to remove from an item in a model. + + For example, as shown in the diagram, we remove the two rows from + row 2 to row 3, so \a first is 2 and \a last is 3: + \snippet doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp 2 + \endtable + + \sa endRemoveRows() +*/ +void QAbstractItemModel::beginRemoveRows(const QModelIndex &parent, int first, int last) +{ + Q_ASSERT(first >= 0); + Q_ASSERT(last >= first); + Q_D(QAbstractItemModel); + d->changes.push(QAbstractItemModelPrivate::Change(parent, first, last)); + emit rowsAboutToBeRemoved(parent, first, last); + d->rowsAboutToBeRemoved(parent, first, last); +} + +/*! + Ends a row removal operation. + + When reimplementing removeRows() in a subclass, you must call this + function \e after removing data from the model's underlying data + store. + + \sa beginRemoveRows() +*/ +void QAbstractItemModel::endRemoveRows() +{ + Q_D(QAbstractItemModel); + QAbstractItemModelPrivate::Change change = d->changes.pop(); + d->rowsRemoved(change.parent, change.first, change.last); + emit rowsRemoved(change.parent, change.first, change.last); +} + +/*! + Begins a column insertion operation. + + When reimplementing insertColumns() in a subclass, you must call this + function \e before inserting data into the model's underlying data + store. + + The \a parent index corresponds to the parent into which the new + columns are inserted; \a first and \a last are the column numbers of + the new columns will have after they have been inserted. + + \table 80% + \row \o \inlineimage modelview-begin-insert-columns.png Inserting columns + \o Specify the first and last column numbers for the span of columns + you want to insert into an item in a model. + + For example, as shown in the diagram, we insert three columns before + column 4, so \a first is 4 and \a last is 6: + \snippet doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp 3 + This inserts the three new columns as columns 4, 5, and 6. + \row + \o \inlineimage modelview-begin-append-columns.png Appending columns + \o To append columns, insert them after the last column. + + For example, as shown in the diagram, we append three columns to a + collection of six existing columns (ending in column 5), so \a first + is 6 and \a last is 8: + \snippet doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp 4 + This appends the two new columns as columns 6, 7, and 8. + \endtable + + \sa endInsertColumns() +*/ +void QAbstractItemModel::beginInsertColumns(const QModelIndex &parent, int first, int last) +{ + Q_ASSERT(first >= 0); + Q_ASSERT(last >= first); + Q_D(QAbstractItemModel); + d->changes.push(QAbstractItemModelPrivate::Change(parent, first, last)); + emit columnsAboutToBeInserted(parent, first, last); + d->columnsAboutToBeInserted(parent, first, last); +} + +/*! + Ends a column insertion operation. + + When reimplementing insertColumns() in a subclass, you must call this + function \e after inserting data into the model's underlying data + store. + + \sa beginInsertColumns() +*/ +void QAbstractItemModel::endInsertColumns() +{ + Q_D(QAbstractItemModel); + QAbstractItemModelPrivate::Change change = d->changes.pop(); + d->columnsInserted(change.parent, change.first, change.last); + emit columnsInserted(change.parent, change.first, change.last); +} + +/*! + Begins a column removal operation. + + When reimplementing removeColumns() in a subclass, you must call this + function \e before removing data from the model's underlying data + store. + + The \a parent index corresponds to the parent from which the new + columns are removed; \a first and \a last are the column numbers of + the first and last columns to be removed. + + \table 80% + \row \o \inlineimage modelview-begin-remove-columns.png Removing columns + \o Specify the first and last column numbers for the span of columns + you want to remove from an item in a model. + + For example, as shown in the diagram, we remove the three columns + from column 4 to column 6, so \a first is 4 and \a last is 6: + \snippet doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp 5 + \endtable + + \sa endRemoveColumns() +*/ +void QAbstractItemModel::beginRemoveColumns(const QModelIndex &parent, int first, int last) +{ + Q_ASSERT(first >= 0); + Q_ASSERT(last >= first); + Q_D(QAbstractItemModel); + d->changes.push(QAbstractItemModelPrivate::Change(parent, first, last)); + emit columnsAboutToBeRemoved(parent, first, last); + d->columnsAboutToBeRemoved(parent, first, last); +} + +/*! + Ends a column removal operation. + + When reimplementing removeColumns() in a subclass, you must call this + function \e after removing data from the model's underlying data + store. + + \sa beginRemoveColumns() +*/ +void QAbstractItemModel::endRemoveColumns() +{ + Q_D(QAbstractItemModel); + QAbstractItemModelPrivate::Change change = d->changes.pop(); + d->columnsRemoved(change.parent, change.first, change.last); + emit columnsRemoved(change.parent, change.first, change.last); +} + +/*! + Resets the model to its original state in any attached views. + + \note The view to which the model is attached to will be reset as well. + + When a model is reset it means that any previous data reported from the + model is now invalid and has to be queried for again. + + When a model radically changes its data it can sometimes be easier to just + call this function rather than emit dataChanged() to inform other + components when the underlying data source, or its structure, has changed. + + \sa modelAboutToBeReset(), modelReset() +*/ +void QAbstractItemModel::reset() +{ + Q_D(QAbstractItemModel); + emit modelAboutToBeReset(); + d->invalidatePersistentIndexes(); + emit modelReset(); +} + +/*! + Changes the QPersistentModelIndex that is equal to the given \a from + model index to the given \a to model index. + + If no persistent model index equal to the given \a from model index was + found, nothing is changed. + + \sa persistentIndexList(), changePersistentIndexList() +*/ +void QAbstractItemModel::changePersistentIndex(const QModelIndex &from, const QModelIndex &to) +{ + Q_D(QAbstractItemModel); + if (d->persistent.indexes.isEmpty()) + return; + // find the data and reinsert it sorted + const QHash<QModelIndex, QPersistentModelIndexData *>::iterator it = d->persistent.indexes.find(from); + if (it != d->persistent.indexes.end()) { + QPersistentModelIndexData *data = *it; + d->persistent.indexes.erase(it); + data->index = to; + if (to.isValid()) + d->persistent.insertMultiAtEnd(to, data); + else + data->model = 0; + } +} + +/*! + \since 4.1 + + Changes the QPersistentModelIndexes that is equal to the indexes in the given \a from + model index list to the given \a to model index list. + + If no persistent model indexes equal to the indexes in the given \a from model index list + was found, nothing is changed. + + \sa persistentIndexList(), changePersistentIndex() +*/ +void QAbstractItemModel::changePersistentIndexList(const QModelIndexList &from, + const QModelIndexList &to) +{ + Q_D(QAbstractItemModel); + if (d->persistent.indexes.isEmpty()) + return; + QVector<QPersistentModelIndexData *> toBeReinserted; + toBeReinserted.reserve(to.count()); + for (int i = 0; i < from.count(); ++i) { + if (from.at(i) == to.at(i)) + continue; + const QHash<QModelIndex, QPersistentModelIndexData *>::iterator it = d->persistent.indexes.find(from.at(i)); + if (it != d->persistent.indexes.end()) { + QPersistentModelIndexData *data = *it; + d->persistent.indexes.erase(it); + data->index = to.at(i); + if (data->index.isValid()) + toBeReinserted << data; + else + data->model = 0; + } + } + + for (QVector<QPersistentModelIndexData *>::const_iterator it = toBeReinserted.constBegin(); + it != toBeReinserted.constEnd() ; ++it) { + QPersistentModelIndexData *data = *it; + d->persistent.insertMultiAtEnd(data->index, data); + } +} + +/*! + \since 4.2 + + Returns the list of indexes stored as persistent indexes in the model. +*/ +QModelIndexList QAbstractItemModel::persistentIndexList() const +{ + Q_D(const QAbstractItemModel); + QModelIndexList result; + for (QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it = d->persistent.indexes.constBegin(); + it != d->persistent.indexes.constEnd(); ++it) { + QPersistentModelIndexData *data = *it; + result.append(data->index); + } + return result; +} + + +/*! + \class QAbstractTableModel + \brief The QAbstractTableModel class provides an abstract model that can be + subclassed to create table models. + + \ingroup model-view + + QAbstractTableModel provides a standard interface for models that represent + their data as a two-dimensional array of items. It is not used directly, + but must be subclassed. + + Since the model provides a more specialized interface than + QAbstractItemModel, it is not suitable for use with tree views, although + it can be used to provide data to a QListView. If you need to represent + a simple list of items, and only need a model to contain a single column + of data, subclassing the QAbstractListModel may be more appropriate. + + The rowCount() and columnCount() functions return the dimensions of the + table. To retrieve a model index corresponding to an item in the model, use + index() and provide only the row and column numbers. + + \section1 Subclassing + + \bold{Note:} Some general guidelines for subclassing models are + available in the \l{Model Subclassing Reference}. + + When subclassing QAbstractTableModel, you must implement rowCount(), + columnCount(), and data(). Default implementations of the index() and + parent() functions are provided by QAbstractTableModel. + Well behaved models will also implement headerData(). + + Editable models need to implement setData(), and implement flags() to + return a value containing + \l{Qt::ItemFlags}{Qt::ItemIsEditable}. + + Models that provide interfaces to resizable data structures can + provide implementations of insertRows(), removeRows(), insertColumns(), + and removeColumns(). When implementing these functions, it is + important to call the appropriate functions so that all connected views + are aware of any changes: + + \list + \o An insertRows() implementation must call beginInsertRows() + \e before inserting new rows into the data structure, and it must + call endInsertRows() \e{immediately afterwards}. + \o An insertColumns() implementation must call beginInsertColumns() + \e before inserting new columns into the data structure, and it must + call endInsertColumns() \e{immediately afterwards}. + \o A removeRows() implementation must call beginRemoveRows() + \e before the rows are removed from the data structure, and it must + call endRemoveRows() \e{immediately afterwards}. + \o A removeColumns() implementation must call beginRemoveColumns() + \e before the columns are removed from the data structure, and it must + call endRemoveColumns() \e{immediately afterwards}. + \endlist + + \sa {Model Classes}, {Model Subclassing Reference}, QAbstractItemModel, + QAbstractListModel, + {Pixelator Example} +*/ + +/*! + Constructs an abstract table model for the given \a parent. +*/ + +QAbstractTableModel::QAbstractTableModel(QObject *parent) + : QAbstractItemModel(parent) +{ + +} + +/*! + \internal + + Constructs an abstract table model with \a dd and the given \a parent. +*/ + +QAbstractTableModel::QAbstractTableModel(QAbstractItemModelPrivate &dd, QObject *parent) + : QAbstractItemModel(dd, parent) +{ + +} + +/*! + Destroys the abstract table model. +*/ + +QAbstractTableModel::~QAbstractTableModel() +{ + +} + +/*! + \fn QModelIndex QAbstractTableModel::index(int row, int column, const QModelIndex &parent = QModelIndex()) const + + Returns the index of the data in \a row and \a column with \a parent. + + \sa parent() +*/ + +QModelIndex QAbstractTableModel::index(int row, int column, const QModelIndex &parent) const +{ + return hasIndex(row, column, parent) ? createIndex(row, column, 0) : QModelIndex(); +} + +/*! + \fn QModelIndex QAbstractTableModel::parent(const QModelIndex &index) const + + Returns the parent of the model item with the given \a index. + + \sa index() hasChildren() +*/ + +QModelIndex QAbstractTableModel::parent(const QModelIndex &) const +{ + return QModelIndex(); +} + +bool QAbstractTableModel::hasChildren(const QModelIndex &parent) const +{ + if (parent.model() == this || !parent.isValid()) + return rowCount(parent) > 0 && columnCount(parent) > 0; + return false; +} + +/*! + \class QAbstractListModel + \brief The QAbstractListModel class provides an abstract model that can be + subclassed to create one-dimensional list models. + + \ingroup model-view + + QAbstractListModel provides a standard interface for models that represent + their data as a simple non-hierarchical sequence of items. It is not used + directly, but must be subclassed. + + Since the model provides a more specialized interface than + QAbstractItemModel, it is not suitable for use with tree views; you will + need to subclass QAbstractItemModel if you want to provide a model for + that purpose. If you need to use a number of list models to manage data, + it may be more appropriate to subclass QAbstractTableModel class instead. + + Simple models can be created by subclassing this class and implementing + the minimum number of required functions. For example, we could implement + a simple read-only QStringList-based model that provides a list of strings + to a QListView widget. In such a case, we only need to implement the + rowCount() function to return the number of items in the list, and the + data() function to retrieve items from the list. + + Since the model represents a one-dimensional structure, the rowCount() + function returns the total number of items in the model. The columnCount() + function is implemented for interoperability with all kinds of views, but + by default informs views that the model contains only one column. + + \section1 Subclassing + + \bold{Note:} Some general guidelines for subclassing models are + available in the \l{Model Subclassing Reference}. + + When subclassing QAbstractListModel, you must provide implementations + of the rowCount() and data() functions. Well behaved models also provide + a headerData() implementation. + + For editable list models, you must also provide an implementation of + setData(), implement the flags() function so that it returns a value + containing \l{Qt::ItemFlags}{Qt::ItemIsEditable}. + + Note that QAbstractListModel provides a default implementation of + columnCount() that informs views that there is only a single column + of items in this model. + + Models that provide interfaces to resizable list-like data structures + can provide implementations of insertRows() and removeRows(). When + implementing these functions, it is important to call the appropriate + functions so that all connected views are aware of any changes: + + \list + \o An insertRows() implementation must call beginInsertRows() + \e before inserting new rows into the data structure, and it must + call endInsertRows() \e{immediately afterwards}. + \o A removeRows() implementation must call beginRemoveRows() + \e before the rows are removed from the data structure, and it must + call endRemoveRows() \e{immediately afterwards}. + \endlist + + \sa {Model Classes}, {Model Subclassing Reference}, QAbstractItemView, + QAbstractTableModel, {Item Views Puzzle Example} +*/ + +/*! + Constructs an abstract list model with the given \a parent. +*/ + +QAbstractListModel::QAbstractListModel(QObject *parent) + : QAbstractItemModel(parent) +{ + +} + +/*! + \internal + + Constructs an abstract list model with \a dd and the given \a parent. +*/ + +QAbstractListModel::QAbstractListModel(QAbstractItemModelPrivate &dd, QObject *parent) + : QAbstractItemModel(dd, parent) +{ + +} + +/*! + Destroys the abstract list model. +*/ + +QAbstractListModel::~QAbstractListModel() +{ + +} + +/*! + \fn QModelIndex QAbstractListModel::index(int row, int column, const QModelIndex &parent = QModelIndex()) const + + Returns the index of the data in \a row and \a column with \a parent. + + \sa parent() +*/ + +QModelIndex QAbstractListModel::index(int row, int column, const QModelIndex &parent) const +{ + return hasIndex(row, column, parent) ? createIndex(row, column, 0) : QModelIndex(); +} + +/*! + Returns the parent of the model item with the given \a index. + + \sa index() hasChildren() +*/ + +QModelIndex QAbstractListModel::parent(const QModelIndex & /* index */) const +{ + return QModelIndex(); +} + +/*! + \internal + + Returns the number of columns in the list with the given \a parent. + + \sa rowCount() +*/ + +int QAbstractListModel::columnCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : 1; +} + +bool QAbstractListModel::hasChildren(const QModelIndex &parent) const +{ + return parent.isValid() ? false : (rowCount() > 0); +} + +/*! + \typedef QModelIndexList + \relates QModelIndex + + Synonym for QList<QModelIndex>. +*/ + +/*! + \reimp +*/ +bool QAbstractTableModel::dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) +{ + if (!data || !(action == Qt::CopyAction || action == Qt::MoveAction)) + return false; + + QStringList types = mimeTypes(); + if (types.isEmpty()) + return false; + QString format = types.at(0); + if (!data->hasFormat(format)) + return false; + + QByteArray encoded = data->data(format); + QDataStream stream(&encoded, QIODevice::ReadOnly); + + // if the drop is on an item, replace the data in the items + if (parent.isValid() && row == -1 && column == -1) { + int top = INT_MAX; + int left = INT_MAX; + QVector<int> rows, columns; + QVector<QMap<int, QVariant> > data; + + while (!stream.atEnd()) { + int r, c; + QMap<int, QVariant> v; + stream >> r >> c >> v; + rows.append(r); + columns.append(c); + data.append(v); + top = qMin(r, top); + left = qMin(c, left); + } + + for (int i = 0; i < data.size(); ++i) { + int r = (rows.at(i) - top) + parent.row(); + int c = (columns.at(i) - left) + parent.column(); + if (hasIndex(r, c)) + setItemData(index(r, c), data.at(i)); + } + + return true; + } + + // otherwise insert new rows for the data + return decodeData(row, column, parent, stream); +} + +/*! + \reimp +*/ +bool QAbstractListModel::dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) +{ + if (!data || !(action == Qt::CopyAction || action == Qt::MoveAction)) + return false; + + QStringList types = mimeTypes(); + if (types.isEmpty()) + return false; + QString format = types.at(0); + if (!data->hasFormat(format)) + return false; + + QByteArray encoded = data->data(format); + QDataStream stream(&encoded, QIODevice::ReadOnly); + + // if the drop is on an item, replace the data in the items + if (parent.isValid() && row == -1 && column == -1) { + int top = INT_MAX; + int left = INT_MAX; + QVector<int> rows, columns; + QVector<QMap<int, QVariant> > data; + + while (!stream.atEnd()) { + int r, c; + QMap<int, QVariant> v; + stream >> r >> c >> v; + rows.append(r); + columns.append(c); + data.append(v); + top = qMin(r, top); + left = qMin(c, left); + } + + for (int i = 0; i < data.size(); ++i) { + int r = (rows.at(i) - top) + parent.row(); + if (columns.at(i) == left && hasIndex(r, 0)) + setItemData(index(r), data.at(i)); + } + + return true; + } + + if (row == -1) + row = rowCount(parent); + + // otherwise insert new rows for the data + return decodeData(row, column, parent, stream); +} + +/*! + \fn QAbstractItemModel::modelAboutToBeReset() + \since 4.2 + + This signal is emitted when reset() is called, before the model's internal + state (e.g. persistent model indexes) has been invalidated. + + \sa reset(), modelReset() +*/ + +/*! + \fn QAbstractItemModel::modelReset() + \since 4.1 + + This signal is emitted when reset() is called, after the model's internal + state (e.g. persistent model indexes) has been invalidated. + + \sa reset(), modelAboutToBeReset() +*/ + +/*! + \fn bool QModelIndex::operator<(const QModelIndex &other) const + \since 4.1 + + Returns true if this model index is smaller than the \a other + model index; otherwise returns false. +*/ + +/*! + \fn uint qHash(const QPersistentModelIndex &index) + \since 4.5 + + Returns a hash of the QPersistentModelIndex + */ + + +/*! + \internal + QHash::insertMulti insert the value before the old value. and find() return the new value. + We need insertMultiAtEnd because we don't want to overwrite the old one, which should be removed later + + There should be only one instance QPersistentModelIndexData per index, but in some intermediate state there may be + severals of PersistantModelIndex pointing to the same index, but one is already updated, and the other one is not. + This make sure than when updating the first one we don't overwrite the second one in the hash, and the second one + will be updated right later. + */ +void QAbstractItemModelPrivate::Persistent::insertMultiAtEnd(const QModelIndex& key, QPersistentModelIndexData *data) +{ + QHash<QModelIndex,QPersistentModelIndexData *>::iterator newIt = + indexes.insertMulti(key, data); + QHash<QModelIndex,QPersistentModelIndexData *>::iterator it = newIt + 1; + while (it != indexes.end() && it.key() == key) { + qSwap(*newIt,*it); + newIt = it; + ++it; + } +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qabstractitemmodel.h b/src/corelib/kernel/qabstractitemmodel.h new file mode 100644 index 0000000..b062768 --- /dev/null +++ b/src/corelib/kernel/qabstractitemmodel.h @@ -0,0 +1,390 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTITEMMODEL_H +#define QABSTRACTITEMMODEL_H + +#include <QtCore/qvariant.h> +#include <QtCore/qobject.h> +#include <QtCore/qhash.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QAbstractItemModel; +class QPersistentModelIndex; + +class Q_CORE_EXPORT QModelIndex +{ + friend class QAbstractItemModel; + friend class QProxyModel; +public: + inline QModelIndex() : r(-1), c(-1), p(0), m(0) {} + inline QModelIndex(const QModelIndex &other) + : r(other.r), c(other.c), p(other.p), m(other.m) {} + inline ~QModelIndex() { p = 0; m = 0; } + inline int row() const { return r; } + inline int column() const { return c; } + inline void *internalPointer() const { return p; } + inline qint64 internalId() const { return reinterpret_cast<qint64>(p); } + inline QModelIndex parent() const; + inline QModelIndex sibling(int row, int column) const; + inline QModelIndex child(int row, int column) const; + inline QVariant data(int role = Qt::DisplayRole) const; + inline Qt::ItemFlags flags() const; + inline const QAbstractItemModel *model() const { return m; } + inline bool isValid() const { return (r >= 0) && (c >= 0) && (m != 0); } + inline bool operator==(const QModelIndex &other) const + { return (other.r == r) && (other.p == p) && (other.c == c) && (other.m == m); } + inline bool operator!=(const QModelIndex &other) const + { return !(*this == other); } + inline bool operator<(const QModelIndex &other) const + { + if (r < other.r) return true; + if (r == other.r) { + if (c < other.c) return true; + if (c == other.c) { + if (p < other.p) return true; + if (p == other.p) return m < other.m; + } + } + return false; } +private: + inline QModelIndex(int row, int column, void *ptr, const QAbstractItemModel *model); + int r, c; + void *p; + const QAbstractItemModel *m; +}; +Q_DECLARE_TYPEINFO(QModelIndex, Q_MOVABLE_TYPE); + +#ifndef QT_NO_DEBUG_STREAM +Q_CORE_EXPORT QDebug operator<<(QDebug, const QModelIndex &); +#endif + +class QPersistentModelIndexData; + +class Q_CORE_EXPORT QPersistentModelIndex +{ +public: + QPersistentModelIndex(); + QPersistentModelIndex(const QModelIndex &index); + QPersistentModelIndex(const QPersistentModelIndex &other); + ~QPersistentModelIndex(); + bool operator<(const QPersistentModelIndex &other) const; + bool operator==(const QPersistentModelIndex &other) const; + inline bool operator!=(const QPersistentModelIndex &other) const + { return !operator==(other); } + QPersistentModelIndex &operator=(const QPersistentModelIndex &other); + bool operator==(const QModelIndex &other) const; + bool operator!=(const QModelIndex &other) const; + QPersistentModelIndex &operator=(const QModelIndex &other); + operator const QModelIndex&() const; + int row() const; + int column() const; + void *internalPointer() const; + qint64 internalId() const; + QModelIndex parent() const; + QModelIndex sibling(int row, int column) const; + QModelIndex child(int row, int column) const; + QVariant data(int role = Qt::DisplayRole) const; + Qt::ItemFlags flags() const; + const QAbstractItemModel *model() const; + bool isValid() const; +private: + QPersistentModelIndexData *d; + friend uint qHash(const QPersistentModelIndex &); +#ifndef QT_NO_DEBUG_STREAM + friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QPersistentModelIndex &); +#endif +}; +Q_DECLARE_TYPEINFO(QPersistentModelIndex, Q_MOVABLE_TYPE); + +inline uint qHash(const QPersistentModelIndex &index) +{ return qHash(index.d); } + + +#ifndef QT_NO_DEBUG_STREAM +Q_CORE_EXPORT QDebug operator<<(QDebug, const QPersistentModelIndex &); +#endif + +template<typename T> class QList; +typedef QList<QModelIndex> QModelIndexList; + +class QMimeData; +class QAbstractItemModelPrivate; +template <class Key, class T> class QMap; + + +class Q_CORE_EXPORT QAbstractItemModel : public QObject +{ + Q_OBJECT + + friend class QPersistentModelIndexData; + friend class QAbstractItemViewPrivate; +public: + + explicit QAbstractItemModel(QObject *parent = 0); + virtual ~QAbstractItemModel(); + + bool hasIndex(int row, int column, const QModelIndex &parent = QModelIndex()) const; + virtual QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const = 0; + virtual QModelIndex parent(const QModelIndex &child) const = 0; + + inline QModelIndex sibling(int row, int column, const QModelIndex &idx) const + { return index(row, column, parent(idx)); } + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const = 0; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const = 0; + virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const; + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const = 0; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, + int role = Qt::EditRole); + + virtual QMap<int, QVariant> itemData(const QModelIndex &index) const; + virtual bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles); + + virtual QStringList mimeTypes() const; + virtual QMimeData *mimeData(const QModelIndexList &indexes) const; + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent); + virtual Qt::DropActions supportedDropActions() const; + + Qt::DropActions supportedDragActions() const; + void setSupportedDragActions(Qt::DropActions); + + virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()); + virtual bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()); + virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + virtual bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()); + + inline bool insertRow(int row, const QModelIndex &parent = QModelIndex()); + inline bool insertColumn(int column, const QModelIndex &parent = QModelIndex()); + inline bool removeRow(int row, const QModelIndex &parent = QModelIndex()); + inline bool removeColumn(int column, const QModelIndex &parent = QModelIndex()); + + virtual void fetchMore(const QModelIndex &parent); + virtual bool canFetchMore(const QModelIndex &parent) const; + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); + virtual QModelIndex buddy(const QModelIndex &index) const; + virtual QModelIndexList match(const QModelIndex &start, int role, + const QVariant &value, int hits = 1, + Qt::MatchFlags flags = + Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const; + virtual QSize span(const QModelIndex &index) const; + +#ifdef Q_NO_USING_KEYWORD + inline QObject *parent() const { return QObject::parent(); } +#else + using QObject::parent; +#endif + +Q_SIGNALS: + void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void headerDataChanged(Qt::Orientation orientation, int first, int last); + void layoutChanged(); + void layoutAboutToBeChanged(); + +#if !defined(Q_MOC_RUN) && !defined(qdoc) +private: // can only be emitted by QAbstractItemModel +#endif + void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last); + void rowsInserted(const QModelIndex &parent, int first, int last); + + void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last); + void rowsRemoved(const QModelIndex &parent, int first, int last); + + void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last); + void columnsInserted(const QModelIndex &parent, int first, int last); + + void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last); + void columnsRemoved(const QModelIndex &parent, int first, int last); + + void modelAboutToBeReset(); + void modelReset(); + +public Q_SLOTS: + virtual bool submit(); + virtual void revert(); + +protected: + QAbstractItemModel(QAbstractItemModelPrivate &dd, QObject *parent = 0); + + inline QModelIndex createIndex(int row, int column, void *data = 0) const; + inline QModelIndex createIndex(int row, int column, int id) const; + inline QModelIndex createIndex(int row, int column, quint32 id) const; + + void encodeData(const QModelIndexList &indexes, QDataStream &stream) const; + bool decodeData(int row, int column, const QModelIndex &parent, QDataStream &stream); + + void beginInsertRows(const QModelIndex &parent, int first, int last); + void endInsertRows(); + + void beginRemoveRows(const QModelIndex &parent, int first, int last); + void endRemoveRows(); + + void beginInsertColumns(const QModelIndex &parent, int first, int last); + void endInsertColumns(); + + void beginRemoveColumns(const QModelIndex &parent, int first, int last); + void endRemoveColumns(); + + void reset(); + + void changePersistentIndex(const QModelIndex &from, const QModelIndex &to); + void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to); + QModelIndexList persistentIndexList() const; + +private: + Q_DECLARE_PRIVATE(QAbstractItemModel) + Q_DISABLE_COPY(QAbstractItemModel) +}; + +inline bool QAbstractItemModel::insertRow(int arow, const QModelIndex &aparent) +{ return insertRows(arow, 1, aparent); } +inline bool QAbstractItemModel::insertColumn(int acolumn, const QModelIndex &aparent) +{ return insertColumns(acolumn, 1, aparent); } +inline bool QAbstractItemModel::removeRow(int arow, const QModelIndex &aparent) +{ return removeRows(arow, 1, aparent); } +inline bool QAbstractItemModel::removeColumn(int acolumn, const QModelIndex &aparent) +{ return removeColumns(acolumn, 1, aparent); } + +inline QModelIndex QAbstractItemModel::createIndex(int arow, int acolumn, void *adata) const +{ return QModelIndex(arow, acolumn, adata, this); } +inline QModelIndex QAbstractItemModel::createIndex(int arow, int acolumn, int aid) const +#if defined(Q_CC_MSVC) +#pragma warning( push ) +#pragma warning( disable : 4312 ) // avoid conversion warning on 64-bit +#endif +{ return QModelIndex(arow, acolumn, reinterpret_cast<void*>(aid), this); } +#if defined(Q_CC_MSVC) +#pragma warning( pop ) +#endif +inline QModelIndex QAbstractItemModel::createIndex(int arow, int acolumn, quint32 aid) const +#if defined(Q_CC_MSVC) +#pragma warning( push ) +#pragma warning( disable : 4312 ) // avoid conversion warning on 64-bit +#endif +{ return QModelIndex(arow, acolumn, reinterpret_cast<void*>(aid), this); } +#if defined(Q_CC_MSVC) +#pragma warning( pop ) +#endif + + +class Q_CORE_EXPORT QAbstractTableModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit QAbstractTableModel(QObject *parent = 0); + ~QAbstractTableModel(); + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent); +protected: + QAbstractTableModel(QAbstractItemModelPrivate &dd, QObject *parent); + +private: + Q_DISABLE_COPY(QAbstractTableModel) + QModelIndex parent(const QModelIndex &child) const; + bool hasChildren(const QModelIndex &parent) const; +}; + +class Q_CORE_EXPORT QAbstractListModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit QAbstractListModel(QObject *parent = 0); + ~QAbstractListModel(); + + QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent); +protected: + QAbstractListModel(QAbstractItemModelPrivate &dd, QObject *parent); + +private: + Q_DISABLE_COPY(QAbstractListModel) + QModelIndex parent(const QModelIndex &child) const; + int columnCount(const QModelIndex &parent) const; + bool hasChildren(const QModelIndex &parent) const; +}; + +// inline implementations + +inline QModelIndex::QModelIndex(int arow, int acolumn, void *adata, + const QAbstractItemModel *amodel) + : r(arow), c(acolumn), p(adata), m(amodel) {} + +inline QModelIndex QModelIndex::parent() const +{ return m ? m->parent(*this) : QModelIndex(); } + +inline QModelIndex QModelIndex::sibling(int arow, int acolumn) const +{ return m ? (r == arow && c == acolumn) ? *this : m->index(arow, acolumn, m->parent(*this)) : QModelIndex(); } + +inline QModelIndex QModelIndex::child(int arow, int acolumn) const +{ return m ? m->index(arow, acolumn, *this) : QModelIndex(); } + +inline QVariant QModelIndex::data(int arole) const +{ return m ? m->data(*this, arole) : QVariant(); } + +inline Qt::ItemFlags QModelIndex::flags() const +{ return m ? m->flags(*this) : Qt::ItemFlags(0); } + +inline uint qHash(const QModelIndex &index) +{ return uint((index.row() << 4) + index.column() + index.internalId()); } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QABSTRACTITEMMODEL_H diff --git a/src/corelib/kernel/qabstractitemmodel_p.h b/src/corelib/kernel/qabstractitemmodel_p.h new file mode 100644 index 0000000..df1a6ce --- /dev/null +++ b/src/corelib/kernel/qabstractitemmodel_p.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTITEMMODEL_P_H +#define QABSTRACTITEMMODEL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QAbstractItemModel*. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// +// + +#include "private/qobject_p.h" +#include "QtCore/qstack.h" +#include "QtCore/qset.h" +#include "QtCore/qhash.h" + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QPersistentModelIndexData +{ +public: + QPersistentModelIndexData() : model(0) {} + QPersistentModelIndexData(const QModelIndex &idx) : index(idx), model(idx.model()) {} + QModelIndex index; + QAtomicInt ref; + const QAbstractItemModel *model; + static QPersistentModelIndexData *create(const QModelIndex &index); + static void destroy(QPersistentModelIndexData *data); +}; + +class Q_CORE_EXPORT QAbstractItemModelPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QAbstractItemModel) + +public: + QAbstractItemModelPrivate() : QObjectPrivate(), supportedDragActions(-1) {} + void removePersistentIndexData(QPersistentModelIndexData *data); + void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last); + void rowsInserted(const QModelIndex &parent, int first, int last); + void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last); + void rowsRemoved(const QModelIndex &parent, int first, int last); + void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last); + void columnsInserted(const QModelIndex &parent, int first, int last); + void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last); + void columnsRemoved(const QModelIndex &parent, int first, int last); + static QAbstractItemModel *staticEmptyModel(); + + inline QModelIndex createIndex(int row, int column, void *data = 0) const { + return q_func()->createIndex(row, column, data); + } + + inline QModelIndex createIndex(int row, int column, int id) const { + return q_func()->createIndex(row, column, id); + } + + inline bool indexValid(const QModelIndex &index) const { + return (index.row() >= 0) && (index.column() >= 0) && (index.model() == q_func()); + } + + inline void invalidatePersistentIndexes() { + foreach (QPersistentModelIndexData *data, persistent.indexes) { + data->index = QModelIndex(); + data->model = 0; + } + persistent.indexes.clear(); + } + + /*! + \internal + clean the QPersistentModelIndex relative to the index if there is one. + To be used before an index is invalided + */ + inline void invalidatePersistentIndex(const QModelIndex &index) { + QHash<QModelIndex, QPersistentModelIndexData *>::iterator it = persistent.indexes.find(index); + if(it != persistent.indexes.end()) { + QPersistentModelIndexData *data = *it; + persistent.indexes.erase(it); + data->index = QModelIndex(); + data->model = 0; + } + } + + struct Change { + Change() : first(-1), last(-1) {} + Change(const Change &c) : parent(c.parent), first(c.first), last(c.last) {} + Change(const QModelIndex &p, int f, int l) : parent(p), first(f), last(l) {} + QModelIndex parent; + int first, last; + }; + QStack<Change> changes; + + struct Persistent { + Persistent() {} + QHash<QModelIndex, QPersistentModelIndexData *> indexes; + QStack<QVector<QPersistentModelIndexData *> > moved; + QStack<QVector<QPersistentModelIndexData *> > invalidated; + void insertMultiAtEnd(const QModelIndex& key, QPersistentModelIndexData *data); + } persistent; + + Qt::DropActions supportedDragActions; +}; + +QT_END_NAMESPACE + +#endif // QABSTRACTITEMMODEL_P_H diff --git a/src/corelib/kernel/qbasictimer.cpp b/src/corelib/kernel/qbasictimer.cpp new file mode 100644 index 0000000..40a12c1 --- /dev/null +++ b/src/corelib/kernel/qbasictimer.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qbasictimer.h" +#include "qcoreapplication.h" +#include "qabstracteventdispatcher.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QBasicTimer + \brief The QBasicTimer class provides timer events for objects. + + \ingroup time + \ingroup events + + This is a fast, lightweight, and low-level class used by Qt + internally. We recommend using the higher-level QTimer class + rather than this class if you want to use timers in your + applications. + + To use this class, create a QBasicTimer, and call its start() + function with a timeout interval and with a pointer to a QObject + subclass. When the timer times out it will send a timer event to + the QObject subclass. The timer can be stopped at any time using + stop(). isActive() returns true for a timer that is running; + i.e. it has been started, has not reached the timeout time, and + has not been stopped. The timer's ID can be retrieved using + timerId(). + + The \l{widgets/wiggly}{Wiggly} example uses QBasicTimer to repaint + a widget at regular intervals. + + \sa QTimer, QTimerEvent, QObject::timerEvent(), Timers, {Wiggly Example} +*/ + + +/*! + \fn QBasicTimer::QBasicTimer() + + Contructs a basic timer. + + \sa start() +*/ +/*! + \fn QBasicTimer::~QBasicTimer() + + Destroys the basic timer. +*/ + +/*! + \fn bool QBasicTimer::isActive() const + + Returns true if the timer is running, has not yet timed + out, and has not been stopped; otherwise returns false. + + \sa start() stop() +*/ + +/*! + \fn int QBasicTimer::timerId() const + + Returns the timer's ID. + + \sa QTimerEvent::timerId() +*/ + +/*! + \fn void QBasicTimer::start(int msec, QObject *object) + + Starts (or restarts) the timer with a \a msec milliseconds + timeout. + + The given \a object will receive timer events. + + \sa stop() isActive() QObject::timerEvent() + */ +void QBasicTimer::start(int msec, QObject *obj) +{ + stop(); + if (obj) + id = obj->startTimer(msec); +} + +/*! + Stops the timer. + + \sa start() isActive() +*/ +void QBasicTimer::stop() +{ + if (id) { + QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); + if (eventDispatcher) + eventDispatcher->unregisterTimer(id); + } + id = 0; +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qbasictimer.h b/src/corelib/kernel/qbasictimer.h new file mode 100644 index 0000000..1146b62 --- /dev/null +++ b/src/corelib/kernel/qbasictimer.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBASICTIMER_H +#define QBASICTIMER_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QObject; + +class Q_CORE_EXPORT QBasicTimer +{ + int id; +public: + inline QBasicTimer() : id(0) {} + inline ~QBasicTimer() { if (id) stop(); } + + inline bool isActive() const { return id != 0; } + inline int timerId() const { return id; } + + void start(int msec, QObject *obj); + void stop(); +}; +Q_DECLARE_TYPEINFO(QBasicTimer, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QBASICTIMER_H diff --git a/src/corelib/kernel/qcore_mac.cpp b/src/corelib/kernel/qcore_mac.cpp new file mode 100644 index 0000000..1681b09 --- /dev/null +++ b/src/corelib/kernel/qcore_mac.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qcore_mac_p.h> +#include <new> +#include "qvarlengtharray.h" + +QT_BEGIN_NAMESPACE + +QString QCFString::toQString(CFStringRef str) +{ + if(!str) + return QString(); + CFIndex length = CFStringGetLength(str); + const UniChar *chars = CFStringGetCharactersPtr(str); + if (chars) + return QString(reinterpret_cast<const QChar *>(chars), length); + + QVarLengthArray<UniChar> buffer(length); + CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data()); + return QString(reinterpret_cast<const QChar *>(buffer.constData()), length); +} + +QCFString::operator QString() const +{ + if (string.isEmpty() && type) + const_cast<QCFString*>(this)->string = toQString(type); + return string; +} + +CFStringRef QCFString::toCFStringRef(const QString &string) +{ + return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar *>(string.unicode()), + string.length()); +} + +QCFString::operator CFStringRef() const +{ + if (!type) + const_cast<QCFString*>(this)->type = toCFStringRef(string); + return type; +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h new file mode 100644 index 0000000..54c9aaa --- /dev/null +++ b/src/corelib/kernel/qcore_mac_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCORE_MAC_P_H +#define QCORE_MAC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef __IMAGECAPTURE__ +# define __IMAGECAPTURE__ +#endif + +#undef OLD_DEBUG +#ifdef DEBUG +# define OLD_DEBUG DEBUG +# undef DEBUG +#endif +#define DEBUG 0 +#ifdef qDebug +# define old_qDebug qDebug +# undef qDebug +#endif + +#include <ApplicationServices/ApplicationServices.h> + +#undef DEBUG +#ifdef OLD_DEBUG +# define DEBUG OLD_DEBUG +# undef OLD_DEBUG +#endif + +#ifdef old_qDebug +# undef qDebug +# define qDebug QT_NO_QDEBUG_MACRO +# undef old_qDebug +#endif + +#include "qstring.h" + +QT_BEGIN_NAMESPACE + +/* + Helper class that automates refernce counting for CFtypes. + After constructing the QCFType object, it can be copied like a + value-based type. + + Note that you must own the object you are wrapping. + This is typically the case if you get the object from a Core + Foundation function with the word "Create" or "Copy" in it. If + you got the object from a "Get" function, either retain it or use + constructFromGet(). One exception to this rule is the + HIThemeGet*Shape functions, which in reality are "Copy" functions. +*/ +template <typename T> +class Q_CORE_EXPORT QCFType +{ +public: + inline QCFType(const T &t = 0) : type(t) {} + inline QCFType(const QCFType &helper) : type(helper.type) { if (type) CFRetain(type); } + inline ~QCFType() { if (type) CFRelease(type); } + inline operator T() { return type; } + inline QCFType operator =(const QCFType &helper) + { + if (helper.type) + CFRetain(helper.type); + CFTypeRef type2 = type; + type = helper.type; + if (type2) + CFRelease(type2); + return *this; + } + inline T *operator&() { return &type; } + static QCFType constructFromGet(const T &t) + { + CFRetain(t); + return QCFType<T>(t); + } +protected: + T type; +}; + +class Q_CORE_EXPORT QCFString : public QCFType<CFStringRef> +{ +public: + inline QCFString(const QString &str) : QCFType<CFStringRef>(0), string(str) {} + inline QCFString(const CFStringRef cfstr = 0) : QCFType<CFStringRef>(cfstr) {} + inline QCFString(const QCFType<CFStringRef> &other) : QCFType<CFStringRef>(other) {} + operator QString() const; + operator CFStringRef() const; + static QString toQString(CFStringRef cfstr); + static CFStringRef toCFStringRef(const QString &str); +private: + QString string; +}; + +QT_END_NAMESPACE + +#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) +#ifndef __LP64__ + typedef float CGFloat; + typedef int NSInteger; + typedef unsigned int NSUInteger; + #define SRefCon SInt32 + #define URefCon UInt32 +#endif +#endif + +#endif // QCORE_MAC_P_H diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp new file mode 100644 index 0000000..b3f9f1a --- /dev/null +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -0,0 +1,2406 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcoreapplication.h" +#include "qcoreapplication_p.h" + +#include "qabstracteventdispatcher.h" +#include "qcoreevent.h" +#include "qeventloop.h" +#include "qcorecmdlineargs_p.h" +#include <qdatastream.h> +#include <qdatetime.h> +#include <qdebug.h> +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qhash.h> +#include <private/qprocess_p.h> +#include <qtextcodec.h> +#include <qthread.h> +#include <qthreadpool.h> +#include <qthreadstorage.h> +#include <private/qthread_p.h> +#include <qlibraryinfo.h> +#include <private/qfactoryloader_p.h> + +#ifdef Q_OS_UNIX +# if !defined(QT_NO_GLIB) +# include "qeventdispatcher_glib_p.h" +# endif +# include "qeventdispatcher_unix_p.h" +#endif + +#ifdef Q_OS_WIN +# include "qeventdispatcher_win_p.h" +#endif + +#ifdef Q_OS_MAC +# include "qcore_mac_p.h" +#endif + +#include <stdlib.h> + +#ifdef Q_OS_UNIX +# include <locale.h> +#endif + +QT_BEGIN_NAMESPACE + +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) +extern QString qAppFileName(); +#endif + +#if !defined(Q_OS_WIN) +#ifdef Q_OS_MAC +QString QCoreApplicationPrivate::macMenuBarName() +{ + QString bundleName; + CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("CFBundleName")); + if (string) + bundleName = QCFString::toQString(static_cast<CFStringRef>(string)); + return bundleName; +} +#endif +QString QCoreApplicationPrivate::appName() const +{ + static QString applName; +#ifdef Q_OS_MAC + applName = macMenuBarName(); +#endif + if (applName.isEmpty() && argv[0]) { + char *p = strrchr(argv[0], '/'); + applName = QString::fromLocal8Bit(p ? p + 1 : argv[0]); + } + return applName; +} +#endif + +bool QCoreApplicationPrivate::checkInstance(const char *function) +{ + bool b = (QCoreApplication::self != 0); + if (!b) + qWarning("QApplication::%s: Please instantiate the QApplication object first", function); + return b; +} + +// Support for introspection + +QSignalSpyCallbackSet Q_CORE_EXPORT qt_signal_spy_callback_set = { 0, 0, 0, 0 }; + +void qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet &callback_set) +{ + qt_signal_spy_callback_set = callback_set; +} + +extern "C" void Q_CORE_EXPORT qt_startup_hook() +{ +} + +typedef QList<QtCleanUpFunction> QVFuncList; +Q_GLOBAL_STATIC(QVFuncList, postRList) + +void qAddPostRoutine(QtCleanUpFunction p) +{ + QVFuncList *list = postRList(); + if (!list) + return; + list->prepend(p); +} + +void qRemovePostRoutine(QtCleanUpFunction p) +{ + QVFuncList *list = postRList(); + if (!list) + return; + list->removeAll(p); +} + +void Q_CORE_EXPORT qt_call_post_routines() +{ + QVFuncList *list = postRList(); + if (!list) + return; + while (!list->isEmpty()) + (list->takeFirst())(); +} + + +// app starting up if false +bool QCoreApplicationPrivate::is_app_running = false; + // app closing down if true +bool QCoreApplicationPrivate::is_app_closing = false; +// initialized in qcoreapplication and in qtextstream autotest when setlocale is called. +Q_CORE_EXPORT bool qt_locale_initialized = false; + + +Q_CORE_EXPORT uint qGlobalPostedEventsCount() +{ + QThreadData *currentThreadData = QThreadData::current(); + return currentThreadData->postEventList.size() - currentThreadData->postEventList.startOffset; +} + + +void qt_set_current_thread_to_main_thread() +{ + QCoreApplicationPrivate::theMainThread = QThread::currentThread(); +} + + + +QCoreApplication *QCoreApplication::self = 0; +QAbstractEventDispatcher *QCoreApplicationPrivate::eventDispatcher = 0; +uint QCoreApplicationPrivate::attribs; + +#ifdef Q_OS_UNIX +Qt::HANDLE qt_application_thread_id = 0; +#endif + +struct QCoreApplicationData { + QCoreApplicationData() { +#ifndef QT_NO_LIBRARY + app_libpaths = 0; +#endif + } + ~QCoreApplicationData() { +#ifndef QT_NO_LIBRARY + delete app_libpaths; +#endif + + // cleanup the QAdoptedThread created for the main() thread + if (QCoreApplicationPrivate::theMainThread) { + QThreadData *data = QThreadData::get2(QCoreApplicationPrivate::theMainThread); + QCoreApplicationPrivate::theMainThread = 0; + data->deref(); // deletes the data and the adopted thread + } + } + QString orgName, orgDomain, application; + QString applicationVersion; + +#ifndef QT_NO_LIBRARY + QStringList *app_libpaths; +#endif + +}; + +Q_GLOBAL_STATIC(QCoreApplicationData, coreappdata) + +QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv) + : QObjectPrivate(), argc(aargc), argv(aargv), application_type(0), eventFilter(0), + in_exec(false), aboutToQuitEmitted(false) +{ + static const char *const empty = ""; + if (argc == 0 || argv == 0) { + argc = 0; + argv = (char **)∅ // ouch! careful with QCoreApplication::argv()! + } + QCoreApplicationPrivate::is_app_closing = false; + +#ifdef Q_OS_UNIX + qt_application_thread_id = QThread::currentThreadId(); +#endif + + // note: this call to QThread::currentThread() may end up setting theMainThread! + if (QThread::currentThread() != theMainThread) + qWarning("WARNING: QApplication was not created in the main() thread."); +} + +QCoreApplicationPrivate::~QCoreApplicationPrivate() +{ +#ifndef QT_NO_THREAD + void *data = &threadData->tls; + QThreadStorageData::finish((void **)data); +#endif + + // need to clear the state of the mainData, just in case a new QCoreApplication comes along. + QMutexLocker locker(&threadData->postEventList.mutex); + for (int i = 0; i < threadData->postEventList.size(); ++i) { + const QPostEvent &pe = threadData->postEventList.at(i); + if (pe.event) { + --pe.receiver->d_func()->postedEvents; + pe.event->posted = false; + delete pe.event; + } + } + threadData->postEventList.clear(); + threadData->postEventList.recursion = 0; + threadData->quitNow = false; +} + +void QCoreApplicationPrivate::createEventDispatcher() +{ + Q_Q(QCoreApplication); +#if defined(Q_OS_UNIX) +# if !defined(QT_NO_GLIB) + if (qgetenv("QT_NO_GLIB").isEmpty() && QEventDispatcherGlib::versionSupported()) + eventDispatcher = new QEventDispatcherGlib(q); + else +# endif + eventDispatcher = new QEventDispatcherUNIX(q); +#elif defined(Q_OS_WIN) + eventDispatcher = new QEventDispatcherWin32(q); +#else +# error "QEventDispatcher not yet ported to this platform" +#endif +} + +QThread *QCoreApplicationPrivate::theMainThread = 0; +QThread *QCoreApplicationPrivate::mainThread() +{ + Q_ASSERT(theMainThread != 0); + return theMainThread; +} + +#if !defined (QT_NO_DEBUG) || defined (QT_MAC_FRAMEWORK_BUILD) +void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) +{ + QThread *currentThread = QThread::currentThread(); + QThread *thr = receiver->thread(); + Q_ASSERT_X(currentThread == thr || !thr, + "QCoreApplication::sendEvent", + QString::fromLatin1("Cannot send events to objects owned by a different thread. " + "Current thread %1. Receiver '%2' (of type '%3') was created in thread %4") + .arg(QString::number((quintptr) currentThread, 16)) + .arg(receiver->objectName()) + .arg(QLatin1String(receiver->metaObject()->className())) + .arg(QString::number((quintptr) thr, 16)) + .toLocal8Bit().data()); + Q_UNUSED(currentThread); + Q_UNUSED(thr); +} +#endif + +void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths() +{ +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QStringList *app_libpaths = coreappdata()->app_libpaths; + Q_ASSERT(app_libpaths); + QString app_location( QCoreApplication::applicationFilePath() ); + app_location.truncate(app_location.lastIndexOf(QLatin1Char('/'))); + app_location = QDir(app_location).canonicalPath(); + if (app_location != QLibraryInfo::location(QLibraryInfo::PluginsPath) && QFile::exists(app_location) && !app_libpaths->contains(app_location)) + app_libpaths->append(app_location); +#endif +} + +QString qAppName() +{ + if (!QCoreApplicationPrivate::checkInstance("qAppName")) + return QString(); + return QCoreApplication::instance()->d_func()->appName(); +} + +/*! + \class QCoreApplication + \brief The QCoreApplication class provides an event loop for console Qt + applications. + + \ingroup application + \mainclass + + This class is used by non-GUI applications to provide their event + loop. For non-GUI application that uses Qt, there should be exactly + one QCoreApplication object. For GUI applications, see + QApplication. + + QCoreApplication contains the main event loop, where all events + from the operating system (e.g., timer and network events) and + other sources are processed and dispatched. It also handles the + application's initialization and finalization, as well as + system-wide and application-wide settings. + + The command line arguments which QCoreApplication's constructor + should be called with are accessible using arguments(). The + event loop is started with a call to exec(). Long running + operations can call processEvents() to keep the application + responsive. + + Some Qt classes, such as QString, can be used without a + QCoreApplication object. However, in general, we recommend that + you create a QCoreApplication or a QApplication object in your \c + main() function as early as possible. The application will enter + the event loop when exec() is called. exit() will not return + until the event loop exits, e.g., when quit() is called. + + An application has an applicationDirPath() and an + applicationFilePath(). Translation files can be added or removed + using installTranslator() and removeTranslator(). Application + strings can be translated using translate(). The QObject::tr() + and QObject::trUtf8() functions are implemented in terms of + translate(). + + The class provides a quit() slot and an aboutToQuit() signal. + + Several static convenience functions are also provided. The + QCoreApplication object is available from instance(). Events can + be sent or posted using sendEvent(), postEvent(), and + sendPostedEvents(). Pending events can be removed with + removePostedEvents() or flushed with flush(). Library paths (see + QLibrary) can be retrieved with libraryPaths() and manipulated by + setLibraryPaths(), addLibraryPath(), and removeLibraryPath(). + + \sa QApplication, QAbstractEventDispatcher, QEventLoop, + {Semaphores Example}, {Wait Conditions Example} +*/ + +/*! + \fn static QCoreApplication *QCoreApplication::instance() + + Returns a pointer to the application's QCoreApplication (or + QApplication) instance. + + If no instance has been allocated, \c null is returned. +*/ + +/*!\internal + */ +QCoreApplication::QCoreApplication(QCoreApplicationPrivate &p) + : QObject(p, 0) +{ + init(); + // note: it is the subclasses' job to call + // QCoreApplicationPrivate::eventDispatcher->startingUp(); +} + +/*! + Flushes the platform specific event queues. + + If you are doing graphical changes inside a loop that does not + return to the event loop on asynchronous window systems like X11 + or double buffered window systems like Mac OS X, and you want to + visualize these changes immediately (e.g. Splash Screens), call + this function. + + \sa sendPostedEvents() +*/ +void QCoreApplication::flush() +{ + if (self && self->d_func()->eventDispatcher) + self->d_func()->eventDispatcher->flush(); +} + +/*! + Constructs a Qt kernel application. Kernel applications are + applications without a graphical user interface. These type of + applications are used at the console or as server processes. + + The \a argc and \a argv arguments are processed by the application, + and made available in a more convenient form by the arguments() + function. + + \warning The data referred to by \a argc and \a argv must stay valid + for the entire lifetime of the QCoreApplication object. In addition, + \a argc must be greater than zero and \a argv must contain at least + one valid character string. +*/ +QCoreApplication::QCoreApplication(int &argc, char **argv) + : QObject(*new QCoreApplicationPrivate(argc, argv)) +{ + init(); + QCoreApplicationPrivate::eventDispatcher->startingUp(); +} + +extern void set_winapp_name(); + +// ### move to QCoreApplicationPrivate constructor? +void QCoreApplication::init() +{ + Q_D(QCoreApplication); + +#ifdef Q_OS_UNIX + setlocale(LC_ALL, ""); // use correct char set mapping + qt_locale_initialized = true; +#endif + +#ifdef Q_WS_WIN + // Get the application name/instance if qWinMain() was not invoked + set_winapp_name(); +#endif + + Q_ASSERT_X(!self, "QCoreApplication", "there should be only one application object"); + QCoreApplication::self = this; + +#ifndef QT_NO_THREAD + QThread::initialize(); +#endif + + // use the event dispatcher created by the app programmer (if any) + if (!QCoreApplicationPrivate::eventDispatcher) + QCoreApplicationPrivate::eventDispatcher = d->threadData->eventDispatcher; + // otherwise we create one + if (!QCoreApplicationPrivate::eventDispatcher) + d->createEventDispatcher(); + Q_ASSERT(QCoreApplicationPrivate::eventDispatcher != 0); + + if (!QCoreApplicationPrivate::eventDispatcher->parent()) + QCoreApplicationPrivate::eventDispatcher->moveToThread(d->threadData->thread); + + d->threadData->eventDispatcher = QCoreApplicationPrivate::eventDispatcher; + +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + if (!coreappdata()->app_libpaths) { + // make sure that library paths is initialized + libraryPaths(); + } else { + d->appendApplicationPathToLibraryPaths(); + } +#endif + +#if defined(Q_OS_UNIX) && !(defined(QT_NO_PROCESS)) + // Make sure the process manager thread object is created in the main + // thread. + QProcessPrivate::initializeProcessManager(); +#endif + +#ifdef QT_EVAL + extern void qt_core_eval_init(uint); + qt_core_eval_init(d->application_type); +#endif + + qt_startup_hook(); +} + +/*! + Destroys the QCoreApplication object. +*/ +QCoreApplication::~QCoreApplication() +{ + qt_call_post_routines(); + + self = 0; + QCoreApplicationPrivate::is_app_closing = true; + QCoreApplicationPrivate::is_app_running = false; + +#if !defined(QT_NO_THREAD) +#if !defined(QT_NO_CONCURRENT) + // Synchronize and stop the global thread pool threads. + QThreadPool::globalInstance()->waitForDone(); +#endif + QThread::cleanup(); +#endif + + d_func()->threadData->eventDispatcher = 0; + if (QCoreApplicationPrivate::eventDispatcher) + QCoreApplicationPrivate::eventDispatcher->closingDown(); + QCoreApplicationPrivate::eventDispatcher = 0; + +#ifndef QT_NO_LIBRARY + delete coreappdata()->app_libpaths; + coreappdata()->app_libpaths = 0; +#endif +} + + +/*! + Sets the attribute \a attribute if \a on is true; + otherwise clears the attribute. + + One of the attributes that can be set with this method is + Qt::AA_ImmediateWidgetCreation. It tells Qt to create toplevel + windows immediately. Normally, resources for widgets are allocated + on demand to improve efficiency and minimize resource usage. + Therefore, if it is important to minimize resource consumption, do + not set this attribute. + + \sa testAttribute() +*/ +void QCoreApplication::setAttribute(Qt::ApplicationAttribute attribute, bool on) +{ + if (on) + QCoreApplicationPrivate::attribs |= 1 << attribute; + else + QCoreApplicationPrivate::attribs &= ~(1 << attribute); +} + +/*! + Returns true if attribute \a attribute is set; + otherwise returns false. + + \sa setAttribute() + */ +bool QCoreApplication::testAttribute(Qt::ApplicationAttribute attribute) +{ + return QCoreApplicationPrivate::testAttribute(attribute); +} + + +/*! + \internal + + This function is here to make it possible for Qt extensions to + hook into event notification without subclassing QApplication +*/ +bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) +{ + // Make it possible for Qt Jambi and QSA to hook into events even + // though QApplication is subclassed... + bool result = false; + void *cbdata[] = { receiver, event, &result }; + if (QInternal::activateCallbacks(QInternal::EventNotifyCallback, cbdata)) { + return result; + } + + // Qt enforces the rule that events can only be sent to objects in + // the current thread, so receiver->d_func()->threadData is + // equivalent to QThreadData::current(), just without the function + // call overhead. + QObjectPrivate *d = receiver->d_func(); + QThreadData *threadData = d->threadData; + ++threadData->loopLevel; + +#ifdef QT_JAMBI_BUILD + int deleteWatch = 0; + int *oldDeleteWatch = QObjectPrivate::setDeleteWatch(d, &deleteWatch); + + bool inEvent = d->inEventHandler; + d->inEventHandler = true; +#endif + +#if defined(QT_NO_EXCEPTIONS) + bool returnValue = notify(receiver, event); +#else + bool returnValue; + try { + returnValue = notify(receiver, event); + } catch(...) { + --threadData->loopLevel; + throw; + } +#endif + +#ifdef QT_JAMBI_BUILD + // Restore the previous state if the object was not deleted.. + if (!deleteWatch) { + d->inEventHandler = inEvent; + } + QObjectPrivate::resetDeleteWatch(d, oldDeleteWatch, deleteWatch); +#endif + --threadData->loopLevel; + return returnValue; +} + + +/*! + Sends \a event to \a receiver: \a {receiver}->event(\a event). + Returns the value that is returned from the receiver's event + handler. Note that this function is called for all events send to + any object is all threads. + + For certain types of events (e.g. mouse and key events), + the event will be propagated to the receiver's parent and so on up to + the top-level object if the receiver is not interested in the event + (i.e., it returns false). + + There are five different ways that events can be processed; + reimplementing this virtual function is just one of them. All five + approaches are listed below: + \list 1 + \i Reimplementing paintEvent(), mousePressEvent() and so + on. This is the commonest, easiest and least powerful way. + + \i Reimplementing this function. This is very powerful, providing + complete control; but only one subclass can be active at a time. + + \i Installing an event filter on QCoreApplication::instance(). Such + an event filter is able to process all events for all widgets, so + it's just as powerful as reimplementing notify(); furthermore, it's + possible to have more than one application-global event filter. + Global event filters even see mouse events for + \l{QWidget::isEnabled()}{disabled widgets}. Note that application + event filters are only called for objects that live in the main + thread. + + \i Reimplementing QObject::event() (as QWidget does). If you do + this you get Tab key presses, and you get to see the events before + any widget-specific event filters. + + \i Installing an event filter on the object. Such an event filter gets all + the events, including Tab and Shift+Tab key press events, as long as they + do not change the focus widget. + \endlist + + \sa QObject::event(), installEventFilter() +*/ + +bool QCoreApplication::notify(QObject *receiver, QEvent *event) +{ + Q_D(QCoreApplication); + // no events are delivered after ~QCoreApplication() has started + if (QCoreApplicationPrivate::is_app_closing) + return true; + + if (receiver == 0) { // serious error + qWarning("QCoreApplication::notify: Unexpected null receiver"); + return true; + } + +#ifndef QT_NO_DEBUG + d->checkReceiverThread(receiver); +#endif + +#ifdef QT3_SUPPORT + if (event->type() == QEvent::ChildRemoved && !receiver->d_func()->pendingChildInsertedEvents.isEmpty()) + receiver->d_func()->removePendingChildInsertedEvents(static_cast<QChildEvent *>(event)->child()); +#endif // QT3_SUPPORT + + return receiver->isWidgetType() ? false : d->notify_helper(receiver, event); +} + +bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event) +{ + if (receiver->d_func()->threadData == this->threadData) { + // application event filters are only called for objects in the GUI thread + for (int i = 0; i < eventFilters.size(); ++i) { + register QObject *obj = eventFilters.at(i); + if (!obj) + continue; + if (obj->d_func()->threadData != threadData) { + qWarning("QCoreApplication: Application event filter cannot be in a different thread."); + continue; + } + if (obj->eventFilter(receiver, event)) + return true; + } + } + return false; +} + +bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, QEvent *event) +{ + Q_Q(QCoreApplication); + if (receiver != q) { + for (int i = 0; i < receiver->d_func()->eventFilters.size(); ++i) { + register QObject *obj = receiver->d_func()->eventFilters.at(i); + if (!obj) + continue; + if (obj->d_func()->threadData != receiver->d_func()->threadData) { + qWarning("QCoreApplication: Object event filter cannot be in a different thread."); + continue; + } + if (obj->eventFilter(receiver, event)) + return true; + } + } + return false; +} + +/*!\internal + + Helper function called by notify() + */ +bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event) +{ + // send to all application event filters + if (sendThroughApplicationEventFilters(receiver, event)) + return true; + // send to all receiver event filters + if (sendThroughObjectEventFilters(receiver, event)) + return true; + // deliver the event + return receiver->event(event); +} + +/*! + Returns true if an application object has not been created yet; + otherwise returns false. + + \sa closingDown() +*/ + +bool QCoreApplication::startingUp() +{ + return !QCoreApplicationPrivate::is_app_running; +} + +/*! + Returns true if the application objects are being destroyed; + otherwise returns false. + + \sa startingUp() +*/ + +bool QCoreApplication::closingDown() +{ + return QCoreApplicationPrivate::is_app_closing; +} + + +/*! + Processes all pending events for the calling thread according to + the specified \a flags until there are no more events to process. + + You can call this function occasionally when your program is busy + performing a long operation (e.g. copying a file). + + In event you are running a local loop which calls this function + continuously, without an event loop, the + \l{QEvent::DeferredDelete}{DeferredDelete} events will + not be processed. This can affect the behaviour of widgets, + e.g. QToolTip, that rely on \l{QEvent::DeferredDelete}{DeferredDelete} + events to function properly. An alternative would be to call + \l{QCoreApplication::sendPostedEvents()}{sendPostedEvents()} from + within that local loop. + + Calling this function processes events only for the calling thread. + + \threadsafe + + \sa exec(), QTimer, QEventLoop::processEvents(), flush(), sendPostedEvents() +*/ +void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + QThreadData *data = QThreadData::current(); + if (!data->eventDispatcher) + return; + if (flags & QEventLoop::DeferredDeletion) + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + data->eventDispatcher->processEvents(flags); +} + +/*! + \overload processEvents() + + Processes pending events for the calling thread for \a maxtime + milliseconds or until there are no more events to process, + whichever is shorter. + + You can call this function occasionally when you program is busy + doing a long operation (e.g. copying a file). + + Calling this function processes events only for the calling thread. + + \threadsafe + + \sa exec(), QTimer, QEventLoop::processEvents() +*/ +void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime) +{ + QThreadData *data = QThreadData::current(); + if (!data->eventDispatcher) + return; + QTime start; + start.start(); + if (flags & QEventLoop::DeferredDeletion) + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + while (data->eventDispatcher->processEvents(flags & ~QEventLoop::WaitForMoreEvents)) { + if (start.elapsed() > maxtime) + break; + if (flags & QEventLoop::DeferredDeletion) + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + } +} + +/***************************************************************************** + Main event loop wrappers + *****************************************************************************/ + +/*! + Enters the main event loop and waits until exit() is called. + Returns the value that was set to exit() (which is 0 if exit() is + called via quit()). + + It is necessary to call this function to start event handling. The + main event loop receives events from the window system and + dispatches these to the application widgets. + + To make your application perform idle processing (i.e. executing a + special function whenever there are no pending events), use a + QTimer with 0 timeout. More advanced idle processing schemes can + be achieved using processEvents(). + + We recommend that you connect clean-up code to the + \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in + your application's \c{main()} function because on some platforms the + QCoreApplication::exec() call may not return. For example, on Windows + when the user logs off, the system terminates the process after Qt + closes all top-level windows. Hence, there is no guarantee that the + application will have time to exit its event loop and execute code at + the end of the \c{main()} function after the QCoreApplication::exec() + call. + + \sa quit(), exit(), processEvents(), QApplication::exec() +*/ +int QCoreApplication::exec() +{ + if (!QCoreApplicationPrivate::checkInstance("exec")) + return -1; + + QThreadData *threadData = self->d_func()->threadData; + if (threadData != QThreadData::current()) { + qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className()); + return -1; + } + if (!threadData->eventLoops.isEmpty()) { + qWarning("QCoreApplication::exec: The event loop is already running"); + return -1; + } + + threadData->quitNow = false; + QEventLoop eventLoop; + self->d_func()->in_exec = true; + self->d_func()->aboutToQuitEmitted = false; + int returnCode = eventLoop.exec(); + threadData->quitNow = false; + if (self) { + self->d_func()->in_exec = false; + if (!self->d_func()->aboutToQuitEmitted) + emit self->aboutToQuit(); + self->d_func()->aboutToQuitEmitted = true; + sendPostedEvents(0, QEvent::DeferredDelete); + } + + return returnCode; +} + +/*! + Tells the application to exit with a return code. + + After this function has been called, the application leaves the + main event loop and returns from the call to exec(). The exec() + function returns \a returnCode. If the event loop is not running, + this function does nothing. + + By convention, a \a returnCode of 0 means success, and any non-zero + value indicates an error. + + Note that unlike the C library function of the same name, this + function \e does return to the caller -- it is event processing that + stops. + + \sa quit(), exec() +*/ +void QCoreApplication::exit(int returnCode) +{ + if (!self) + return; + QThreadData *data = self->d_func()->threadData; + data->quitNow = true; + for (int i = 0; i < data->eventLoops.size(); ++i) { + QEventLoop *eventLoop = data->eventLoops.at(i); + eventLoop->exit(returnCode); + } +} + +/***************************************************************************** + QCoreApplication management of posted events + *****************************************************************************/ + +/*! + \fn bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event) + + Sends event \a event directly to receiver \a receiver, using the + notify() function. Returns the value that was returned from the + event handler. + + The event is \e not deleted when the event has been sent. The normal + approach is to create the event on the stack, for example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 0 + + \sa postEvent(), notify() +*/ + +/*! + Adds the event \a event, with the object \a receiver as the + receiver of the event, to an event queue and returns immediately. + + The event must be allocated on the heap since the post event queue + will take ownership of the event and delete it once it has been + posted. It is \e {not safe} to modify or delete the event after + it has been posted. + + When control returns to the main event loop, all events that are + stored in the queue will be sent using the notify() function. + + Events are processed in the order posted. For more control over + the processing order, use the postEvent() overload below, which + takes a priority argument. This function posts all event with a + Qt::NormalEventPriority. + + \threadsafe + + \sa sendEvent(), notify(), sendPostedEvents() +*/ + +void QCoreApplication::postEvent(QObject *receiver, QEvent *event) +{ + postEvent(receiver, event, Qt::NormalEventPriority); +} + + +/*! + \overload postEvent() + \since 4.3 + + Adds the event \a event, with the object \a receiver as the + receiver of the event, to an event queue and returns immediately. + + The event must be allocated on the heap since the post event queue + will take ownership of the event and delete it once it has been + posted. It is \e {not safe} to modify or delete the event after + it has been posted. + + When control returns to the main event loop, all events that are + stored in the queue will be sent using the notify() function. + + Events are sorted in descending \a priority order, i.e. events + with a high \a priority are queued before events with a lower \a + priority. The \a priority can be any integer value, i.e. between + INT_MAX and INT_MIN, inclusive; see Qt::EventPriority for more + details. Events with equal \a priority will be processed in the + order posted. + + \threadsafe + + \sa sendEvent(), notify(), sendPostedEvents(), Qt::EventPriority +*/ +void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority) +{ + if (receiver == 0) { + qWarning("QCoreApplication::postEvent: Unexpected null receiver"); + delete event; + return; + } + + QThreadData * volatile * pdata = &receiver->d_func()->threadData; + QThreadData *data = *pdata; + if (!data) { + // posting during destruction? just delete the event to prevent a leak + delete event; + return; + } + + // lock the post event mutex + data->postEventList.mutex.lock(); + + // if object has moved to another thread, follow it + while (data != *pdata) { + data->postEventList.mutex.unlock(); + + data = *pdata; + if (!data) { + // posting during destruction? just delete the event to prevent a leak + delete event; + return; + } + + data->postEventList.mutex.lock(); + } + + // if this is one of the compressible events, do compression + if (receiver->d_func()->postedEvents + && self && self->compressEvent(event, receiver, &data->postEventList)) { + data->postEventList.mutex.unlock(); + return; + } + + event->posted = true; + ++receiver->d_func()->postedEvents; + if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) { + // remember the current running eventloop for DeferredDelete + // events posted in the receiver's thread + event->d = reinterpret_cast<QEventPrivate *>(quintptr(data->loopLevel)); + } + + if (data->postEventList.isEmpty() || data->postEventList.last().priority >= priority) { + // optimization: we can simply append if the last event in + // the queue has higher or equal priority + data->postEventList.append(QPostEvent(receiver, event, priority)); + } else { + // insert event in descending priority order, using upper + // bound for a given priority (to ensure proper ordering + // of events with the same priority) + QPostEventList::iterator begin = data->postEventList.begin() + + data->postEventList.insertionOffset, + end = data->postEventList.end(); + QPostEventList::iterator at = qUpperBound(begin, end, priority); + data->postEventList.insert(at, QPostEvent(receiver, event, priority)); + } + data->canWait = false; + data->postEventList.mutex.unlock(); + + if (data->eventDispatcher) + data->eventDispatcher->wakeUp(); +} + +/*! + \internal + Returns true if \a event was compressed away (possibly deleted) and should not be added to the list. +*/ +bool QCoreApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents) +{ +#ifdef Q_WS_WIN + Q_ASSERT(event); + Q_ASSERT(receiver); + Q_ASSERT(postedEvents); + + // compress posted timers to this object. + if (event->type() == QEvent::Timer && receiver->d_func()->postedEvents > 0) { + int timerId = ((QTimerEvent *) event)->timerId(); + for (int i=0; i<postedEvents->size(); ++i) { + const QPostEvent &e = postedEvents->at(i); + if (e.receiver == receiver && e.event && e.event->type() == QEvent::Timer + && ((QTimerEvent *) e.event)->timerId() == timerId) { + delete event; + return true; + } + } + } else +#endif + if ((event->type() == QEvent::DeferredDelete + || event->type() == QEvent::Quit) + && receiver->d_func()->postedEvents > 0) { + for (int i = 0; i < postedEvents->size(); ++i) { + const QPostEvent &cur = postedEvents->at(i); + if (cur.receiver != receiver + || cur.event == 0 + || cur.event->type() != event->type()) + continue; + // found an event for this receiver + delete event; + return true; + } + } + return false; +} + +/*! + \fn void QCoreApplication::sendPostedEvents() + \overload sendPostedEvents() + + Dispatches all posted events, i.e. empties the event queue. +*/ + +/*! + Immediately dispatches all events which have been previously queued + with QCoreApplication::postEvent() and which are for the object \a receiver + and have the event type \a event_type. + + Events from the window system are \e not dispatched by this + function, but by processEvents(). + + If \a receiver is null, the events of \a event_type are sent for all + objects. If \a event_type is 0, all the events are sent for \a receiver. + + \note This method must be called from the same thread as its QObject parameter, \a receiver. + + \sa flush(), postEvent() +*/ + +void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type) +{ + QThreadData *data = QThreadData::current(); + + QCoreApplicationPrivate::sendPostedEvents(receiver, event_type, data); +} + +void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type, + QThreadData *data) +{ + if (event_type == -1) { + // we were called by an obsolete event dispatcher. + event_type = 0; + } + + if (receiver && receiver->d_func()->threadData != data) { + qWarning("QCoreApplication::sendPostedEvents: Cannot send " + "posted events for objects in another thread"); + return; + } + + ++data->postEventList.recursion; + +#ifdef QT3_SUPPORT + if (event_type == QEvent::ChildInserted) { + if (receiver) { + // optimize sendPostedEvents(w, QEvent::ChildInserted) calls away + receiver->d_func()->sendPendingChildInsertedEvents(); + --data->postEventList.recursion; + return; + } + + // ChildInserted events are sent in response to *Request + event_type = QEvent::ChildInsertedRequest; + } +#endif + + QMutexLocker locker(&data->postEventList.mutex); + + // by default, we assume that the event dispatcher can go to sleep after + // processing all events. if any new events are posted while we send + // events, canWait will be set to false. + data->canWait = (data->postEventList.size() == 0); + + if (data->postEventList.size() == 0 || (receiver && !receiver->d_func()->postedEvents)) { + --data->postEventList.recursion; + return; + } + + data->canWait = true; + + // okay. here is the tricky loop. be careful about optimizing + // this, it looks the way it does for good reasons. + int startOffset = data->postEventList.startOffset; + int &i = (!event_type && !receiver) ? data->postEventList.startOffset : startOffset; + data->postEventList.insertionOffset = data->postEventList.size(); + + while (i < data->postEventList.size()) { + // avoid live-lock + if (i >= data->postEventList.insertionOffset) + break; + + const QPostEvent &pe = data->postEventList.at(i); + ++i; + + if (!pe.event) + continue; + if ((receiver && receiver != pe.receiver) || (event_type && event_type != pe.event->type())) { + data->canWait = false; + continue; + } + + if (pe.event->type() == QEvent::DeferredDelete) { + // DeferredDelete events are only sent when we are explicitly asked to + // (s.a. QEvent::DeferredDelete), and then only if the event loop that + // posted the event has returned. + const bool allowDeferredDelete = + (quintptr(pe.event->d) > unsigned(data->loopLevel) + || (!quintptr(pe.event->d) && data->loopLevel > 0) + || (event_type == QEvent::DeferredDelete + && quintptr(pe.event->d) == unsigned(data->loopLevel))); + if (!allowDeferredDelete) { + // cannot send deferred delete + if (!event_type && !receiver) { + // don't lose the event + data->postEventList.append(pe); + const_cast<QPostEvent &>(pe).event = 0; + } + continue; + } + } + + // first, we diddle the event so that we can deliver + // it, and that no one will try to touch it later. + pe.event->posted = false; + QEvent * e = pe.event; + QObject * r = pe.receiver; + + --r->d_func()->postedEvents; + Q_ASSERT(r->d_func()->postedEvents >= 0); + + // next, update the data structure so that we're ready + // for the next event. + const_cast<QPostEvent &>(pe).event = 0; + + locker.unlock(); + // after all that work, it's time to deliver the event. +#ifdef QT_NO_EXCEPTIONS + QCoreApplication::sendEvent(r, e); +#else + try { + QCoreApplication::sendEvent(r, e); + } catch (...) { + delete e; + locker.relock(); + + // since we were interrupted, we need another pass to make sure we clean everything up + data->canWait = false; + + // uglehack: copied from below + --data->postEventList.recursion; + if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher) + data->eventDispatcher->wakeUp(); + throw; // rethrow + } +#endif + + delete e; + locker.relock(); + + // careful when adding anything below this point - the + // sendEvent() call might invalidate any invariants this + // function depends on. + } + + --data->postEventList.recursion; + if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher) + data->eventDispatcher->wakeUp(); + + // clear the global list, i.e. remove everything that was + // delivered. + if (!event_type && !receiver && data->postEventList.startOffset >= 0) { + const QPostEventList::iterator it = data->postEventList.begin(); + data->postEventList.erase(it, it + data->postEventList.startOffset); + data->postEventList.insertionOffset -= data->postEventList.startOffset; + Q_ASSERT(data->postEventList.insertionOffset >= 0); + data->postEventList.startOffset = 0; + } +} + +/*! + Removes all events posted using postEvent() for \a receiver. + + The events are \e not dispatched, instead they are removed from the + queue. You should never need to call this function. If you do call it, + be aware that killing events may cause \a receiver to break one or + more invariants. + + \threadsafe +*/ + +void QCoreApplication::removePostedEvents(QObject *receiver) +{ + removePostedEvents(receiver, 0); +} + +/*! + \overload removePostedEvents() + \since 4.3 + + Removes all events of the given \a eventType that were posted + using postEvent() for \a receiver. + + The events are \e not dispatched, instead they are removed from + the queue. You should never need to call this function. If you do + call it, be aware that killing events may cause \a receiver to + break one or more invariants. + + If \a receiver is null, the events of \a eventType are removed for + all objects. If \a eventType is 0, all the events are removed for + \a receiver. + + \threadsafe +*/ + +void QCoreApplication::removePostedEvents(QObject *receiver, int eventType) +{ +#ifdef QT3_SUPPORT + if (eventType == QEvent::ChildInserted) + eventType = QEvent::ChildInsertedRequest; +#endif + + QThreadData *data = receiver ? receiver->d_func()->threadData : QThreadData::current(); + QMutexLocker locker(&data->postEventList.mutex); + + // the QObject destructor calls this function directly. this can + // happen while the event loop is in the middle of posting events, + // and when we get here, we may not have any more posted events + // for this object. + if (receiver && !receiver->d_func()->postedEvents) + return; + QCoreApplicationPrivate::removePostedEvents_unlocked(receiver, eventType, data); +} + +void QCoreApplicationPrivate::removePostedEvents_unlocked(QObject *receiver, + int eventType, + QThreadData *data) +{ + int n = data->postEventList.size(); + int j = 0; + + for (int i = 0; i < n; ++i) { + const QPostEvent &pe = data->postEventList.at(i); + + if ((!receiver || pe.receiver == receiver) + && (pe.event && (eventType == 0 || pe.event->type() == eventType))) { + --pe.receiver->d_func()->postedEvents; +#ifdef QT3_SUPPORT + if (pe.event->type() == QEvent::ChildInsertedRequest) + pe.receiver->d_func()->removePendingChildInsertedEvents(0); +#endif + pe.event->posted = false; + delete pe.event; + const_cast<QPostEvent &>(pe).event = 0; + } else if (!data->postEventList.recursion) { + if (i != j) + data->postEventList.swap(i, j); + ++j; + } + } + +#ifdef QT_DEBUG + if (receiver && eventType == 0) { + Q_ASSERT(!receiver->d_func()->postedEvents); + } +#endif + + if (!data->postEventList.recursion) { + // truncate list + data->postEventList.erase(data->postEventList.begin() + j, data->postEventList.end()); + } +} + + +/*! + Removes \a event from the queue of posted events, and emits a + warning message if appropriate. + + \warning This function can be \e really slow. Avoid using it, if + possible. + + \threadsafe +*/ + +void QCoreApplicationPrivate::removePostedEvent(QEvent * event) +{ + if (!event || !event->posted) + return; + + QThreadData *data = QThreadData::current(); + + QMutexLocker locker(&data->postEventList.mutex); + + if (data->postEventList.size() == 0) { +#if defined(QT_DEBUG) + qDebug("QCoreApplication::removePostedEvent: Internal error: %p %d is posted", + (void*)event, event->type()); + return; +#endif + } + + for (int i = 0; i < data->postEventList.size(); ++i) { + const QPostEvent & pe = data->postEventList.at(i); + if (pe.event == event) { +#ifndef QT_NO_DEBUG + qWarning("QCoreApplication::removePostedEvent: Event of type %d deleted while posted to %s %s", + event->type(), + pe.receiver->metaObject()->className(), + pe.receiver->objectName().toLocal8Bit().data()); +#endif + --pe.receiver->d_func()->postedEvents; + pe.event->posted = false; + delete pe.event; + const_cast<QPostEvent &>(pe).event = 0; + return; + } + } +} + +/*!\reimp + +*/ +bool QCoreApplication::event(QEvent *e) +{ + if (e->type() == QEvent::Quit) { + quit(); + return true; + } + return QObject::event(e); +} + +/*! \enum QCoreApplication::Encoding + + This enum type defines the 8-bit encoding of character string + arguments to translate(): + + \value CodecForTr The encoding specified by + QTextCodec::codecForTr() (Latin-1 if none has + been set). + \value UnicodeUTF8 UTF-8. + \value DefaultCodec (Obsolete) Use CodecForTr instead. + + \sa QObject::tr(), QObject::trUtf8(), QString::fromUtf8() +*/ + +/*! + Tells the application to exit with return code 0 (success). + Equivalent to calling QCoreApplication::exit(0). + + It's common to connect the QApplication::lastWindowClosed() signal + to quit(), and you also often connect e.g. QAbstractButton::clicked() or + signals in QAction, QMenu, or QMenuBar to it. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 1 + + \sa exit(), aboutToQuit(), QApplication::lastWindowClosed() +*/ + +void QCoreApplication::quit() +{ + exit(0); +} + +/*! + \fn void QCoreApplication::aboutToQuit() + + This signal is emitted when the application is about to quit the + main event loop, e.g. when the event loop level drops to zero. + This may happen either after a call to quit() from inside the + application or when the users shuts down the entire desktop session. + + The signal is particularly useful if your application has to do some + last-second cleanup. Note that no user interaction is possible in + this state. + + \sa quit() +*/ + +#ifndef QT_NO_TRANSLATION +/*! + Adds the translation file \a translationFile to the list of + translation files to be used for translations. + + Multiple translation files can be installed. Translations are + searched for in the reverse order in which they were installed, + so the most recently installed translation file is searched first + and the first translation file installed is searched last. + The search stops as soon as a translation containing a matching + string is found. + + Installing or removing a QTranslator, or changing an installed QTranslator + generates a \l{QEvent::LanguageChange}{LanguageChange} event for the + QCoreApplication instance. A QApplication instance will propagate the event + to all toplevel windows, where a reimplementation of changeEvent can + re-translate the user interface by passing user-visible strings via the + tr() function to the respective property setters. User-interface classes + generated by \l{Qt Designer} provide a \c retranslateUi() function that can be + called. + + \sa removeTranslator() translate() QTranslator::load() {Dynamic Translation} +*/ + +void QCoreApplication::installTranslator(QTranslator *translationFile) +{ + if (!translationFile) + return; + + if (!QCoreApplicationPrivate::checkInstance("installTranslator")) + return; + QCoreApplicationPrivate *d = self->d_func(); + d->translators.prepend(translationFile); + +#ifndef QT_NO_TRANSLATION_BUILDER + if (translationFile->isEmpty()) + return; +#endif + + QEvent ev(QEvent::LanguageChange); + QCoreApplication::sendEvent(self, &ev); +} + +/*! + Removes the translation file \a translationFile from the list of + translation files used by this application. (It does not delete the + translation file from the file system.) + + \sa installTranslator() translate(), QObject::tr() +*/ + +void QCoreApplication::removeTranslator(QTranslator *translationFile) +{ + if (!translationFile) + return; + if (!QCoreApplicationPrivate::checkInstance("removeTranslator")) + return; + QCoreApplicationPrivate *d = self->d_func(); + if (d->translators.removeAll(translationFile) && !self->closingDown()) { + QEvent ev(QEvent::LanguageChange); + QCoreApplication::sendEvent(self, &ev); + } +} + +/*! + \overload translate() +*/ +QString QCoreApplication::translate(const char *context, const char *sourceText, + const char *disambiguation, Encoding encoding) +{ + return translate(context, sourceText, disambiguation, encoding, -1); +} + +static void replacePercentN(QString *result, int n) +{ + if (n >= 0) { + int percentPos = 0; + int len = 0; + while ((percentPos = result->indexOf(QLatin1Char('%'), percentPos + len)) != -1) { + len = 1; + QString fmt; + if (result->at(percentPos + len) == QLatin1Char('L')) { + ++len; + fmt = QLatin1String("%L1"); + } else { + fmt = QLatin1String("%1"); + } + if (result->at(percentPos + len) == QLatin1Char('n')) { + fmt = fmt.arg(n); + ++len; + result->replace(percentPos, len, fmt); + len = fmt.length(); + } + } + } +} + +/*! + \reentrant + \since 4.5 + + Returns the translation text for \a sourceText, by querying the + installed translation files. The translation files are searched + from the most recently installed file back to the first + installed file. + + QObject::tr() and QObject::trUtf8() provide this functionality + more conveniently. + + \a context is typically a class name (e.g., "MyDialog") and \a + sourceText is either English text or a short identifying text. + + \a disambiguation is an identifying string, for when the same \a + sourceText is used in different roles within the same context. By + default, it is null. + + See the \l QTranslator and \l QObject::tr() documentation for + more information about contexts, disambiguations and comments. + + \a encoding indicates the 8-bit encoding of character strings. + + \a n is used in conjunction with \c %n to support plural forms. + See QObject::tr() for details. + + If none of the translation files contain a translation for \a + sourceText in \a context, this function returns a QString + equivalent of \a sourceText. The encoding of \a sourceText is + specified by \e encoding; it defaults to CodecForTr. + + This function is not virtual. You can use alternative translation + techniques by subclassing \l QTranslator. + + \warning This method is reentrant only if all translators are + installed \e before calling this method. Installing or removing + translators while performing translations is not supported. Doing + so will most likely result in crashes or other undesirable + behavior. + + \sa QObject::tr() installTranslator() QTextCodec::codecForTr() +*/ + + +QString QCoreApplication::translate(const char *context, const char *sourceText, + const char *disambiguation, Encoding encoding, int n) +{ + QString result; + + if (!sourceText) + return result; + + if (self && !self->d_func()->translators.isEmpty()) { + QList<QTranslator*>::ConstIterator it; + QTranslator *translationFile; + for (it = self->d_func()->translators.constBegin(); it != self->d_func()->translators.constEnd(); ++it) { + translationFile = *it; + result = translationFile->translate(context, sourceText, disambiguation, n); + if (!result.isEmpty()) + break; + } + } + + if (result.isEmpty()) { +#ifdef QT_NO_TEXTCODEC + Q_UNUSED(encoding) +#else + if (encoding == UnicodeUTF8) + result = QString::fromUtf8(sourceText); + else if (QTextCodec::codecForTr() != 0) + result = QTextCodec::codecForTr()->toUnicode(sourceText); + else +#endif + result = QString::fromLatin1(sourceText); + } + + replacePercentN(&result, n); + return result; +} + +bool QCoreApplicationPrivate::isTranslatorInstalled(QTranslator *translator) +{ + return QCoreApplication::self + && QCoreApplication::self->d_func()->translators.contains(translator); +} + +#endif //QT_NO_TRANSLATE + +/*! + Returns the directory that contains the application executable. + + For example, if you have installed Qt in the \c{C:\Trolltech\Qt} + directory, and you run the \c{regexp} example, this function will + return "C:/Trolltech/Qt/examples/tools/regexp". + + On Mac OS X this will point to the directory actually containing the + executable, which may be inside of an application bundle (if the + application is bundled). + + \warning On Linux, this function will try to get the path from the + \c {/proc} file system. If that fails, it assumes that \c + {argv[0]} contains the absolute file name of the executable. The + function also assumes that the current directory has not been + changed by the application. + + \sa applicationFilePath() +*/ +QString QCoreApplication::applicationDirPath() +{ + if (!self) { + qWarning("QCoreApplication::applicationDirPath: Please instantiate the QApplication object first"); + return QString(); + } + + QCoreApplicationPrivate *d = self->d_func(); + if (d->cachedApplicationDirPath == QString()) + d->cachedApplicationDirPath = QFileInfo(applicationFilePath()).path(); + return d->cachedApplicationDirPath; +} + +/*! + Returns the file path of the application executable. + + For example, if you have installed Qt in the \c{/usr/local/qt} + directory, and you run the \c{regexp} example, this function will + return "/usr/local/qt/examples/tools/regexp/regexp". + + \warning On Linux, this function will try to get the path from the + \c {/proc} file system. If that fails, it assumes that \c + {argv[0]} contains the absolute file name of the executable. The + function also assumes that the current directory has not been + changed by the application. + + \sa applicationDirPath() +*/ +QString QCoreApplication::applicationFilePath() +{ + if (!self) { + qWarning("QCoreApplication::applicationFilePath: Please instantiate the QApplication object first"); + return QString(); + } + + QCoreApplicationPrivate *d = self->d_func(); + if (d->cachedApplicationFilePath != QString()) + return d->cachedApplicationFilePath; + +#if defined( Q_WS_WIN ) + QFileInfo filePath; + QT_WA({ + wchar_t module_name[MAX_PATH+1]; + GetModuleFileNameW(0, module_name, MAX_PATH); + module_name[MAX_PATH] = 0; + filePath = QString::fromUtf16((ushort *)module_name); + }, { + char module_name[MAX_PATH+1]; + GetModuleFileNameA(0, module_name, MAX_PATH); + module_name[MAX_PATH] = 0; + filePath = QString::fromLocal8Bit(module_name); + }); + + d->cachedApplicationFilePath = filePath.filePath(); + return d->cachedApplicationFilePath; +#elif defined(Q_WS_MAC) + QString qAppFileName_str = qAppFileName(); + if(!qAppFileName_str.isEmpty()) { + QFileInfo fi(qAppFileName_str); + d->cachedApplicationFilePath = fi.exists() ? fi.canonicalFilePath() : QString(); + return d->cachedApplicationFilePath; + } +#endif +#if defined( Q_OS_UNIX ) +# ifdef Q_OS_LINUX + // Try looking for a /proc/<pid>/exe symlink first which points to + // the absolute path of the executable + QFileInfo pfi(QString::fromLatin1("/proc/%1/exe").arg(getpid())); + if (pfi.exists() && pfi.isSymLink()) { + d->cachedApplicationFilePath = pfi.canonicalFilePath(); + return d->cachedApplicationFilePath; + } +# endif + + QString argv0 = QFile::decodeName(QByteArray(argv()[0])); + QString absPath; + + if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) { + /* + If argv0 starts with a slash, it is already an absolute + file path. + */ + absPath = argv0; + } else if (argv0.contains(QLatin1Char('/'))) { + /* + If argv0 contains one or more slashes, it is a file path + relative to the current directory. + */ + absPath = QDir::current().absoluteFilePath(argv0); + } else { + /* + Otherwise, the file path has to be determined using the + PATH environment variable. + */ + QByteArray pEnv = qgetenv("PATH"); + QDir currentDir = QDir::current(); + QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1String(":")); + for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) { + if ((*p).isEmpty()) + continue; + QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0); + QFileInfo candidate_fi(candidate); + if (candidate_fi.exists() && !candidate_fi.isDir()) { + absPath = candidate; + break; + } + } + } + + absPath = QDir::cleanPath(absPath); + + QFileInfo fi(absPath); + d->cachedApplicationFilePath = fi.exists() ? fi.canonicalFilePath() : QString(); + return d->cachedApplicationFilePath; +#endif +} + +/*! + \since 4.4 + + Returns the current process ID for the application. +*/ +qint64 QCoreApplication::applicationPid() +{ +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) + return GetCurrentProcessId(); +#else + // UNIX + return getpid(); +#endif +} + +/*! + \obsolete + + Use arguments().size() instead. +*/ +int QCoreApplication::argc() +{ + if (!self) { + qWarning("QCoreApplication::argc: Please instantiate the QApplication object first"); + return 0; + } + return self->d_func()->argc; +} + + +/*! + \obsolete + + Use arguments() instead. +*/ +char **QCoreApplication::argv() +{ + if (!self) { + qWarning("QCoreApplication::argv: Please instantiate the QApplication object first"); + return 0; + } + return self->d_func()->argv; +} + +/*! + \since 4.1 + + Returns the list of command-line arguments. + + Usually arguments().at(0) is the program name, arguments().at(1) + is the first argument, and arguments().last() is the last + argument. See the note below about Windows. + + Calling this function is slow - you should store the result in a variable + when parsing the command line. + + \warning On Unix, this list is built from the argc and argv parameters passed + to the constructor in the main() function. The string-data in argv is + interpreted using QString::fromLocal8Bit(); hence it is not possible to + pass i.e. Japanese command line arguments on a system that runs in a latin1 + locale. Most modern Unix systems do not have this limitation, as they are + Unicode based. + + On NT-based Windows, this limitation does not apply either. + On Windows, the arguments() are not built from the contents of argv/argc, as + the content does not support Unicode. Instead, the arguments() are constructed + from the return value of + \l{http://msdn2.microsoft.com/en-us/library/ms683156(VS.85).aspx}{GetCommandLine()}. + As a result of this, the string given by arguments().at(0) might not be + the program name on Windows, depending on how the application was started. + + \sa applicationFilePath() +*/ + +QStringList QCoreApplication::arguments() +{ + QStringList list; + + if (!self) { + qWarning("QCoreApplication::arguments: Please instantiate the QApplication object first"); + return list; + } +#ifdef Q_OS_WIN + QString cmdline = QT_WA_INLINE(QString::fromUtf16((unsigned short *)GetCommandLineW()), QString::fromLocal8Bit(GetCommandLineA())); + +#if defined(Q_OS_WINCE) + wchar_t tempFilename[MAX_PATH+1]; + if (GetModuleFileNameW(0, tempFilename, MAX_PATH)) { + tempFilename[MAX_PATH] = 0; + cmdline.prepend(QString(QLatin1String("\"")) + QString::fromUtf16((unsigned short *)tempFilename) + QString(QLatin1String("\" "))); + } +#endif // Q_OS_WINCE + + list = qWinCmdArgs(cmdline); + if (self->d_func()->application_type) { // GUI app? Skip known - see qapplication.cpp + QStringList stripped; + for (int a = 0; a < list.count(); ++a) { + QString arg = list.at(a); + QByteArray l1arg = arg.toLatin1(); + if (l1arg == "-qdevel" || + l1arg == "-qdebug" || + l1arg == "-reverse" || + l1arg == "-stylesheet" || + l1arg == "-widgetcount" || + l1arg == "-direct3d") + ; + else if (l1arg.startsWith("-style=")) + ; + else if (l1arg == "-style" || + l1arg == "-session" || + l1arg == "-graphicssystem") + ++a; + else + stripped += arg; + } + list = stripped; + } +#else + const int ac = self->d_func()->argc; + char ** const av = self->d_func()->argv; + for (int a = 0; a < ac; ++a) { + list << QString::fromLocal8Bit(av[a]); + } +#endif + + return list; +} + +/*! + \property QCoreApplication::organizationName + \brief the name of the organization that wrote this application + + The value is used by the QSettings class when it is constructed + using the empty constructor. This saves having to repeat this + information each time a QSettings object is created. + + On Mac, QSettings uses organizationDomain() as the organization + if it's not an empty string; otherwise it uses + organizationName(). On all other platforms, QSettings uses + organizationName() as the organization. + + \sa organizationDomain applicationName +*/ + +void QCoreApplication::setOrganizationName(const QString &orgName) +{ + coreappdata()->orgName = orgName; +} + +QString QCoreApplication::organizationName() +{ + return coreappdata()->orgName; +} + +/*! + \property QCoreApplication::organizationDomain + \brief the Internet domain of the organization that wrote this application + + The value is used by the QSettings class when it is constructed + using the empty constructor. This saves having to repeat this + information each time a QSettings object is created. + + On Mac, QSettings uses organizationDomain() as the organization + if it's not an empty string; otherwise it uses organizationName(). + On all other platforms, QSettings uses organizationName() as the + organization. + + \sa organizationName applicationName applicationVersion +*/ +void QCoreApplication::setOrganizationDomain(const QString &orgDomain) +{ + coreappdata()->orgDomain = orgDomain; +} + +QString QCoreApplication::organizationDomain() +{ + return coreappdata()->orgDomain; +} + +/*! + \property QCoreApplication::applicationName + \brief the name of this application + + The value is used by the QSettings class when it is constructed + using the empty constructor. This saves having to repeat this + information each time a QSettings object is created. + + \sa organizationName organizationDomain applicationVersion +*/ +void QCoreApplication::setApplicationName(const QString &application) +{ + coreappdata()->application = application; +} + +QString QCoreApplication::applicationName() +{ + return coreappdata()->application; +} + +/*! + \property QCoreApplication::applicationVersion + \since 4.4 + \brief the version of this application + + \sa applicationName organizationName organizationDomain +*/ +void QCoreApplication::setApplicationVersion(const QString &version) +{ + coreappdata()->applicationVersion = version; +} + +QString QCoreApplication::applicationVersion() +{ + return coreappdata()->applicationVersion; +} + +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + +Q_GLOBAL_STATIC_WITH_ARGS(QMutex, libraryPathMutex, (QMutex::Recursive)) + +/*! + Returns a list of paths that the application will search when + dynamically loading libraries. + + Qt provides default library paths, but they can also be set using + a \l{Using qt.conf}{qt.conf} file. Paths specified in this file + will override default values. + + This list will include the installation directory for plugins if + it exists (the default installation directory for plugins is \c + INSTALL/plugins, where \c INSTALL is the directory where Qt was + installed). The directory of the application executable (NOT the + working directory) is always added, as well as the colon separated + entries of the QT_PLUGIN_PATH environment variable. + + If you want to iterate over the list, you can use the \l foreach + pseudo-keyword: + + \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 2 + + \sa setLibraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary, + {How to Create Qt Plugins} +*/ +QStringList QCoreApplication::libraryPaths() +{ + QMutexLocker locker(libraryPathMutex()); + if (!coreappdata()->app_libpaths) { + QStringList *app_libpaths = coreappdata()->app_libpaths = new QStringList; + QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); + if (QFile::exists(installPathPlugins)) { + // Make sure we convert from backslashes to slashes. + installPathPlugins = QDir(installPathPlugins).canonicalPath(); + if (!app_libpaths->contains(installPathPlugins)) + app_libpaths->append(installPathPlugins); + } + + // If QCoreApplication is not yet instantiated, + // make sure we add the application path when we construct the QCoreApplication + if (self) self->d_func()->appendApplicationPathToLibraryPaths(); + + const QByteArray libPathEnv = qgetenv("QT_PLUGIN_PATH"); + if (!libPathEnv.isEmpty()) { +#ifdef Q_OS_WIN + QLatin1Char pathSep(';'); +#else + QLatin1Char pathSep(':'); +#endif + QStringList paths = QString::fromLatin1(libPathEnv).split(pathSep, QString::SkipEmptyParts); + for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) { + QString canonicalPath = QDir(*it).canonicalPath(); + if (!canonicalPath.isEmpty() + && !app_libpaths->contains(canonicalPath)) { + app_libpaths->append(canonicalPath); + } + } + } + } + return *(coreappdata()->app_libpaths); +} + + + +/*! + + Sets the list of directories to search when loading libraries to + \a paths. All existing paths will be deleted and the path list + will consist of the paths given in \a paths. + + \sa libraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary + */ +void QCoreApplication::setLibraryPaths(const QStringList &paths) +{ +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QMutexLocker locker(libraryPathMutex()); + if (!coreappdata()->app_libpaths) + coreappdata()->app_libpaths = new QStringList; + *(coreappdata()->app_libpaths) = paths; + QFactoryLoader::refreshAll(); +#endif +} + +/*! + Prepends \a path to the beginning of the library path list, ensuring that + it is searched for libraries first. If \a path is empty or already in the + path list, the path list is not changed. + + The default path list consists of a single entry, the installation + directory for plugins. The default installation directory for plugins + is \c INSTALL/plugins, where \c INSTALL is the directory where Qt was + installed. + + \sa removeLibraryPath(), libraryPaths(), setLibraryPaths() + */ +void QCoreApplication::addLibraryPath(const QString &path) +{ +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + if (path.isEmpty()) + return; + + QMutexLocker locker(libraryPathMutex()); + + // make sure that library paths is initialized + libraryPaths(); + + QString canonicalPath = QDir(path).canonicalPath(); + if (!canonicalPath.isEmpty() + && !coreappdata()->app_libpaths->contains(canonicalPath)) { + coreappdata()->app_libpaths->prepend(canonicalPath); + QFactoryLoader::refreshAll(); + } +#endif +} + +/*! + Removes \a path from the library path list. If \a path is empty or not + in the path list, the list is not changed. + + \sa addLibraryPath(), libraryPaths(), setLibraryPaths() +*/ +void QCoreApplication::removeLibraryPath(const QString &path) +{ +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + if (path.isEmpty()) + return; + + QMutexLocker locker(libraryPathMutex()); + + // make sure that library paths is initialized + libraryPaths(); + + QString canonicalPath = QDir(path).canonicalPath(); + coreappdata()->app_libpaths->removeAll(canonicalPath); + QFactoryLoader::refreshAll(); +#endif +} + +#endif //QT_NO_LIBRARY + +/*! + \typedef QCoreApplication::EventFilter + + A function with the following signature that can be used as an + event filter: + + \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 3 + + \sa setEventFilter() +*/ + +/*! + \fn EventFilter QCoreApplication::setEventFilter(EventFilter filter) + + Sets the event filter \a filter. Returns a pointer to the filter + function previously defined. + + The event filter is a function that is called for every message + received in all threads. This does \e not include messages to + objects that are not handled by Qt. + + The function can return true to stop the event to be processed by + Qt, or false to continue with the standard event processing. + + Only one filter can be defined, but the filter can use the return + value to call the previously set event filter. By default, no + filter is set (i.e., the function returns 0). + + \sa installEventFilter() +*/ +QCoreApplication::EventFilter +QCoreApplication::setEventFilter(QCoreApplication::EventFilter filter) +{ + Q_D(QCoreApplication); + EventFilter old = d->eventFilter; + d->eventFilter = filter; + return old; +} + +/*! + Sends \a message through the event filter that was set by + setEventFilter(). If no event filter has been set, this function + returns false; otherwise, this function returns the result of the + event filter function in the \a result parameter. + + \sa setEventFilter() +*/ +bool QCoreApplication::filterEvent(void *message, long *result) +{ + Q_D(QCoreApplication); + if (result) + *result = 0; + if (d->eventFilter) + return d->eventFilter(message, result); +#ifdef Q_OS_WIN + return winEventFilter(reinterpret_cast<MSG *>(message), result); +#else + return false; +#endif +} + +/*! + This function returns true if there are pending events; otherwise + returns false. Pending events can be either from the window + system or posted events using postEvent(). + + \sa QAbstractEventDispatcher::hasPendingEvents() +*/ +bool QCoreApplication::hasPendingEvents() +{ + QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); + if (eventDispatcher) + return eventDispatcher->hasPendingEvents(); + return false; +} + +#ifdef QT3_SUPPORT +/*! \fn void QCoreApplication::lock() + + In Qt 3, this function locked the Qt library mutex, allowing + non-GUI threads to perform basic printing operations using + QPainter. + + In Qt 4, this is no longer supported, since painting is only + supported from within a paint event handler. This function does + nothing. + + \sa QWidget::paintEvent() +*/ + +/*! \fn void QCoreApplication::unlock(bool wakeUpGui) + + In Qt 3, this function unlocked the Qt library mutex. The mutex + allowed non-GUI threads to perform basic printing operations + using QPainter. + + In Qt 4, this is no longer supported, since painting is only + supported from within a paint event handler. This function does + nothing. +*/ + +/*! \fn bool QCoreApplication::locked() + + This function does nothing. It is there to keep old code working. + It always returns false. + + See lock() for details. +*/ + +/*! \fn bool QCoreApplication::tryLock() + + This function does nothing. It is there to keep old code working. + It always returns false. + + See lock() for details. +*/ + +/*! \fn void QCoreApplication::processOneEvent() + \obsolete + + Waits for an event to occur, processes it, then returns. + + This function is useful for adapting Qt to situations where the + event processing must be grafted onto existing program loops. + + Using this function in new applications may be an indication of design + problems. + + \sa processEvents(), exec(), QTimer +*/ + +/*! \obsolete + + This function enters the main event loop (recursively). Do not call + it unless you really know what you are doing. +*/ +int QCoreApplication::enter_loop() +{ + if (!QCoreApplicationPrivate::checkInstance("enter_loop")) + return -1; + if (QThreadData::current() != self->d_func()->threadData) { + qWarning("QCoreApplication::enter_loop: Must be called from the main thread"); + return -1; + } + QEventLoop eventLoop; + int returnCode = eventLoop.exec(); + return returnCode; +} + +/*! \obsolete + + This function exits from a recursive call to the main event loop. + Do not call it unless you are an expert. +*/ +void QCoreApplication::exit_loop() +{ + if (!QCoreApplicationPrivate::checkInstance("exit_loop")) + return; + QThreadData *data = QThreadData::current(); + if (data != self->d_func()->threadData) { + qWarning("QCoreApplication::exit_loop: Must be called from the main thread"); + return; + } + if (!data->eventLoops.isEmpty()) + data->eventLoops.top()->exit(); +} + +/*! \obsolete + + Returns the current loop level. +*/ +int QCoreApplication::loopLevel() +{ + if (!QCoreApplicationPrivate::checkInstance("loopLevel")) + return -1; + return self->d_func()->threadData->eventLoops.size(); +} +#endif + +/*! + \fn void QCoreApplication::watchUnixSignal(int signal, bool watch) + \internal +*/ + +/*! + \fn void QCoreApplication::unixSignal(int number) + \internal + + This signal is emitted whenever a Unix signal is received by the + application. The Unix signal received is specified by its \a number. +*/ + +/*! + \fn void qAddPostRoutine(QtCleanUpFunction ptr) + \relates QCoreApplication + + Adds a global routine that will be called from the QApplication + destructor. This function is normally used to add cleanup routines + for program-wide functionality. + + The function specified by \a ptr should take no arguments and should + return nothing. For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 4 + + Note that for an application- or module-wide cleanup, + qAddPostRoutine() is often not suitable. For example, if the + program is split into dynamically loaded modules, the relevant + module may be unloaded long before the QApplication destructor is + called. + + For modules and libraries, using a reference-counted + initialization manager or Qt's parent-child deletion mechanism may + be better. Here is an example of a private class that uses the + parent-child mechanism to call a cleanup function at the right + time: + + \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 5 + + By selecting the right parent object, this can often be made to + clean up the module's data at the right moment. +*/ + +/*! + \macro Q_DECLARE_TR_FUNCTIONS(context) + \relates QCoreApplication + + The Q_DECLARE_TR_FUNCTIONS() macro declares and implements two + translation functions, \c tr() and \c trUtf8(), with these + signatures: + + \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 6 + + This macro is useful if you want to use QObject::tr() or + QObject::trUtf8() in classes that don't inherit from QObject. + + Q_DECLARE_TR_FUNCTIONS() must appear at the very top of the + class definition (before the first \c{public:} or \c{protected:}). + For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 7 + + The \a context parameter is normally the class name, but it can + be any string. + + \sa Q_OBJECT, QObject::tr(), QObject::trUtf8() +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h new file mode 100644 index 0000000..f7175ae --- /dev/null +++ b/src/corelib/kernel/qcoreapplication.h @@ -0,0 +1,279 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOREAPPLICATION_H +#define QCOREAPPLICATION_H + +#include <QtCore/qobject.h> +#include <QtCore/qcoreevent.h> +#include <QtCore/qeventloop.h> + +#ifdef QT_INCLUDE_COMPAT +#include <QtCore/qstringlist.h> +#endif + +#if defined(Q_WS_WIN) && !defined(tagMSG) +typedef struct tagMSG MSG; +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QCoreApplicationPrivate; +class QTextCodec; +class QTranslator; +class QPostEventList; +class QStringList; + +#define qApp QCoreApplication::instance() + +class Q_CORE_EXPORT QCoreApplication : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString applicationName READ applicationName WRITE setApplicationName) + Q_PROPERTY(QString applicationVersion READ applicationVersion WRITE setApplicationVersion) + Q_PROPERTY(QString organizationName READ organizationName WRITE setOrganizationName) + Q_PROPERTY(QString organizationDomain READ organizationDomain WRITE setOrganizationDomain) + + Q_DECLARE_PRIVATE(QCoreApplication) +public: + QCoreApplication(int &argc, char **argv); + ~QCoreApplication(); + +#ifdef QT_DEPRECATED + QT_DEPRECATED static int argc(); + QT_DEPRECATED static char **argv(); +#endif + static QStringList arguments(); + + static void setAttribute(Qt::ApplicationAttribute attribute, bool on = true); + static bool testAttribute(Qt::ApplicationAttribute attribute); + + static void setOrganizationDomain(const QString &orgDomain); + static QString organizationDomain(); + static void setOrganizationName(const QString &orgName); + static QString organizationName(); + static void setApplicationName(const QString &application); + static QString applicationName(); + static void setApplicationVersion(const QString &version); + static QString applicationVersion(); + + static QCoreApplication *instance() { return self; } + + static int exec(); + static void processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents); + static void processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime); + static void exit(int retcode=0); + + static bool sendEvent(QObject *receiver, QEvent *event); + static void postEvent(QObject *receiver, QEvent *event); + static void postEvent(QObject *receiver, QEvent *event, int priority); + static void sendPostedEvents(QObject *receiver, int event_type); + static void sendPostedEvents(); + static void removePostedEvents(QObject *receiver); + static void removePostedEvents(QObject *receiver, int eventType); + static bool hasPendingEvents(); + + virtual bool notify(QObject *, QEvent *); + + static bool startingUp(); + static bool closingDown(); + + static QString applicationDirPath(); + static QString applicationFilePath(); + static qint64 applicationPid(); + +#ifndef QT_NO_LIBRARY + static void setLibraryPaths(const QStringList &); + static QStringList libraryPaths(); + static void addLibraryPath(const QString &); + static void removeLibraryPath(const QString &); +#endif // QT_NO_LIBRARY + +#ifndef QT_NO_TRANSLATION + static void installTranslator(QTranslator * messageFile); + static void removeTranslator(QTranslator * messageFile); +#endif + enum Encoding { CodecForTr, UnicodeUTF8, DefaultCodec = CodecForTr }; + // ### Qt 5: merge + static QString translate(const char * context, + const char * key, + const char * disambiguation = 0, + Encoding encoding = CodecForTr); + static QString translate(const char * context, + const char * key, + const char * disambiguation, + Encoding encoding, int n); + + static void flush(); + +#if defined(QT3_SUPPORT) + inline QT3_SUPPORT void lock() {} + inline QT3_SUPPORT void unlock(bool = true) {} + inline QT3_SUPPORT bool locked() { return false; } + inline QT3_SUPPORT bool tryLock() { return false; } + + static inline QT3_SUPPORT void processOneEvent() + { processEvents(QEventLoop::WaitForMoreEvents); } + static QT3_SUPPORT int enter_loop(); + static QT3_SUPPORT void exit_loop(); + static QT3_SUPPORT int loopLevel(); +#endif + +#if defined(Q_WS_WIN) + virtual bool winEventFilter(MSG *message, long *result); +#endif + +#ifdef Q_OS_UNIX + static void watchUnixSignal(int signal, bool watch); +#endif + + typedef bool (*EventFilter)(void *message, long *result); + EventFilter setEventFilter(EventFilter filter); + bool filterEvent(void *message, long *result); + +public Q_SLOTS: + static void quit(); + +Q_SIGNALS: + void aboutToQuit(); + void unixSignal(int); + +protected: + bool event(QEvent *); + + virtual bool compressEvent(QEvent *, QObject *receiver, QPostEventList *); + +protected: + QCoreApplication(QCoreApplicationPrivate &p); + +private: + static bool sendSpontaneousEvent(QObject *receiver, QEvent *event); + bool notifyInternal(QObject *receiver, QEvent *event); + + void init(); + + static QCoreApplication *self; + + friend class QEventDispatcherUNIXPrivate; + friend class QApplication; + friend class QApplicationPrivate; + friend class QETWidget; + friend class Q3AccelManager; + friend class QShortcutMap; + friend class QWidget; + friend class QWidgetPrivate; + friend bool qt_sendSpontaneousEvent(QObject*, QEvent*); + friend Q_CORE_EXPORT QString qAppName(); + friend class QClassFactory; +}; + +inline bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event) +{ if (event) event->spont = false; return self ? self->notifyInternal(receiver, event) : false; } + +inline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event) +{ if (event) event->spont = true; return self ? self->notifyInternal(receiver, event) : false; } + +inline void QCoreApplication::sendPostedEvents() { sendPostedEvents(0, 0); } + +#ifdef QT_NO_TRANSLATION +// Simple versions +inline QString QCoreApplication::translate(const char *, const char *sourceText, + const char *, Encoding encoding) +{ +#ifndef QT_NO_TEXTCODEC + if (encoding == UnicodeUTF8) + return QString::fromUtf8(sourceText); +#else + Q_UNUSED(encoding) +#endif + return QString::fromLatin1(sourceText); +} + +// Simple versions +inline QString QCoreApplication::translate(const char *, const char *sourceText, + const char *, Encoding encoding, int) +{ +#ifndef QT_NO_TEXTCODEC + if (encoding == UnicodeUTF8) + return QString::fromUtf8(sourceText); +#else + Q_UNUSED(encoding) +#endif + return QString::fromLatin1(sourceText); +} +#endif + +// ### merge the four functions into two (using "int n = -1") +#define Q_DECLARE_TR_FUNCTIONS(context) \ +public: \ + static inline QString tr(const char *sourceText, const char *disambiguation = 0) \ + { return QCoreApplication::translate(#context, sourceText, disambiguation); } \ + static inline QString trUtf8(const char *sourceText, const char *disambiguation = 0) \ + { return QCoreApplication::translate(#context, sourceText, disambiguation, \ + QCoreApplication::UnicodeUTF8); } \ + static inline QString tr(const char *sourceText, const char *disambiguation, int n) \ + { return QCoreApplication::translate(#context, sourceText, disambiguation, \ + QCoreApplication::CodecForTr, n); } \ + static inline QString trUtf8(const char *sourceText, const char *disambiguation, int n) \ + { return QCoreApplication::translate(#context, sourceText, disambiguation, \ + QCoreApplication::UnicodeUTF8, n); } \ +private: + +typedef void (*QtCleanUpFunction)(); + +Q_CORE_EXPORT void qAddPostRoutine(QtCleanUpFunction); +Q_CORE_EXPORT void qRemovePostRoutine(QtCleanUpFunction); +Q_CORE_EXPORT QString qAppName(); // get application name + +#if defined(Q_WS_WIN) && !defined(QT_NO_DEBUG_STREAM) +Q_CORE_EXPORT QString decodeMSG(const MSG &); +Q_CORE_EXPORT QDebug operator<<(QDebug, const MSG &); +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QCOREAPPLICATION_H diff --git a/src/corelib/kernel/qcoreapplication_mac.cpp b/src/corelib/kernel/qcoreapplication_mac.cpp new file mode 100644 index 0000000..4e34a10 --- /dev/null +++ b/src/corelib/kernel/qcoreapplication_mac.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcoreapplication.h" +#include "private/qcoreapplication_p.h" +#include <private/qcore_mac_p.h> + +QT_BEGIN_NAMESPACE + +/***************************************************************************** + QCoreApplication utility functions + *****************************************************************************/ +QString qAppFileName() +{ + static QString appFileName; + if (appFileName.isEmpty()) { + QCFType<CFURLRef> bundleURL(CFBundleCopyExecutableURL(CFBundleGetMainBundle())); + if(bundleURL) { + QCFString cfPath(CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle)); + if(cfPath) + appFileName = cfPath; + } + } + return appFileName; +} + + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h new file mode 100644 index 0000000..9490ad7 --- /dev/null +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOREAPPLICATION_P_H +#define QCOREAPPLICATION_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. +// + +#include "QtCore/qcoreapplication.h" +#include "QtCore/qtranslator.h" +#include "private/qobject_p.h" + +QT_BEGIN_NAMESPACE + +typedef QList<QTranslator*> QTranslatorList; + +class QAbstractEventDispatcher; + +class Q_CORE_EXPORT QCoreApplicationPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QCoreApplication) + +public: + QCoreApplicationPrivate(int &aargc, char **aargv); + ~QCoreApplicationPrivate(); + + bool sendThroughApplicationEventFilters(QObject *, QEvent *); + bool sendThroughObjectEventFilters(QObject *, QEvent *); + bool notify_helper(QObject *, QEvent *); + + virtual QString appName() const; + virtual void createEventDispatcher(); + static void removePostedEvent(QEvent *); +#ifdef Q_OS_WIN + static void removePostedTimerEvent(QObject *object, int timerId); +#endif + +#ifdef Q_OS_MAC + static QString macMenuBarName(); +#endif + + static QThread *theMainThread; + static QThread *mainThread(); + static bool checkInstance(const char *method); + static void sendPostedEvents(QObject *receiver, int event_type, QThreadData *data); + static void removePostedEvents_unlocked(QObject *receiver, int type, QThreadData *data); + +#if !defined (QT_NO_DEBUG) || defined (QT_MAC_FRAMEWORK_BUILD) + void checkReceiverThread(QObject *receiver); +#endif + int &argc; + char **argv; + void appendApplicationPathToLibraryPaths(void); + +#ifndef QT_NO_TRANSLATION + QTranslatorList translators; +#endif + uint application_type; + + QCoreApplication::EventFilter eventFilter; + + bool in_exec; + bool aboutToQuitEmitted; + QString cachedApplicationDirPath; + QString cachedApplicationFilePath; + + static bool isTranslatorInstalled(QTranslator *translator); + + static QAbstractEventDispatcher *eventDispatcher; + static bool is_app_running; + static bool is_app_closing; + + static uint attribs; + static inline bool testAttribute(uint flag) { return attribs & (1 << flag); } +}; + +QT_END_NAMESPACE + +#endif // QCOREAPPLICATION_P_H diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp new file mode 100644 index 0000000..225821f --- /dev/null +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -0,0 +1,1042 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcoreapplication.h" +#include "qcoreapplication_p.h" +#include "qstringlist.h" +#include "qt_windows.h" +#include "qvector.h" +#include "qmutex.h" +#include "qcorecmdlineargs_p.h" +#include <private/qthread_p.h> +#include <ctype.h> + +QT_BEGIN_NAMESPACE + +// ############### DON'T EXPORT HERE!!! +Q_CORE_EXPORT char appFileName[MAX_PATH+1]; // application file name +Q_CORE_EXPORT char theAppName[MAX_PATH+1]; // application name +Q_CORE_EXPORT HINSTANCE appInst = 0; // handle to app instance +Q_CORE_EXPORT HINSTANCE appPrevInst = 0; // handle to prev app instance +Q_CORE_EXPORT int appCmdShow = 0; +bool usingWinMain = false; // whether the qWinMain() is used or not + +Q_CORE_EXPORT HINSTANCE qWinAppInst() // get Windows app handle +{ + return appInst; +} + +Q_CORE_EXPORT HINSTANCE qWinAppPrevInst() // get Windows prev app handle +{ + return appPrevInst; +} + +void set_winapp_name() +{ + static bool already_set = false; + if (!already_set) { + already_set = true; +#ifndef Q_OS_WINCE + GetModuleFileNameA(0, appFileName, sizeof(appFileName)); + appFileName[sizeof(appFileName)-1] = 0; +#else + QString afm; + afm.resize(sizeof(appFileName)); + afm.resize(GetModuleFileName(0, (wchar_t *) (afm.unicode()), sizeof(appFileName))); + memcpy(appFileName, afm.toLatin1(), sizeof(appFileName)); +#endif + const char *p = strrchr(appFileName, '\\'); // skip path + if (p) + memcpy(theAppName, p+1, qstrlen(p)); + int l = qstrlen(theAppName); + if ((l > 4) && !qstricmp(theAppName + l - 4, ".exe")) + theAppName[l-4] = '\0'; // drop .exe extension + } +} + +Q_CORE_EXPORT QString qAppFileName() // get application file name +{ + return QString::fromLatin1(appFileName); +} + +QString QCoreApplicationPrivate::appName() const +{ + if (!theAppName[0]) + set_winapp_name(); + return QString::fromLatin1(theAppName); +} + +class QWinMsgHandlerCriticalSection +{ + CRITICAL_SECTION cs; +public: + QWinMsgHandlerCriticalSection() + { InitializeCriticalSection(&cs); } + ~QWinMsgHandlerCriticalSection() + { DeleteCriticalSection(&cs); } + + void lock() + { EnterCriticalSection(&cs); } + void unlock() + { LeaveCriticalSection(&cs); } +}; + +Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char* str) +{ + Q_UNUSED(t); + // OutputDebugString is not threadsafe. + + // cannot use QMutex here, because qWarning()s in the QMutex + // implementation may cause this function to recurse + static QWinMsgHandlerCriticalSection staticCriticalSection; + + if (!str) + str = "(null)"; + + staticCriticalSection.lock(); + QT_WA({ + QString s(QString::fromLocal8Bit(str)); + s += QLatin1String("\n"); + OutputDebugStringW((TCHAR*)s.utf16()); + }, { + QByteArray s(str); + s += "\n"; + OutputDebugStringA(s.data()); + }) + staticCriticalSection.unlock(); +} + + +/***************************************************************************** + qWinMain() - Initializes Windows. Called from WinMain() in qtmain_win.cpp + *****************************************************************************/ + +#if defined(Q_OS_WINCE) +Q_CORE_EXPORT void __cdecl qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam, + int cmdShow, int &argc, QVector<char *> &argv) +#else +Q_CORE_EXPORT +void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam, + int cmdShow, int &argc, QVector<char *> &argv) +#endif +{ + static bool already_called = false; + + if (already_called) { + qWarning("Qt: Internal error: qWinMain should be called only once"); + return; + } + already_called = true; + usingWinMain = true; + + // Install default debug handler + + qInstallMsgHandler(qWinMsgHandler); + + // Create command line + + set_winapp_name(); + + argv = qWinCmdLine<char>(cmdParam, int(strlen(cmdParam)), argc); + // Get Windows parameters + + appInst = instance; + appPrevInst = prevInstance; + appCmdShow = cmdShow; +} + +/*! + The message procedure calls this function for every message + received. Reimplement this function if you want to process window + messages \a msg that are not processed by Qt. If you don't want + the event to be processed by Qt, then return true and set \a result + to the value that the window procedure should return. Otherwise + return false. + + It is only directly addressed messages that are filtered. To + handle system wide messages, such as messages from a registered + hot key, you need to install an event filter on the event + dispatcher, which is returned from + QAbstractEventDispatcher::instance(). +*/ +bool QCoreApplication::winEventFilter(MSG *msg, long *result) // Windows event filter +{ + Q_UNUSED(msg); + Q_UNUSED(result); + return false; +} + +void QCoreApplicationPrivate::removePostedTimerEvent(QObject *object, int timerId) +{ + QThreadData *data = object->d_func()->threadData; + + QMutexLocker locker(&data->postEventList.mutex); + if (data->postEventList.size() == 0) + return; + for (int i = 0; i < data->postEventList.size(); ++i) { + const QPostEvent & pe = data->postEventList.at(i); + if (pe.receiver == object + && pe.event + && (pe.event->type() == QEvent::Timer || pe.event->type() == QEvent::ZeroTimerEvent) + && static_cast<QTimerEvent *>(pe.event)->timerId() == timerId) { + --pe.receiver->d_func()->postedEvents; + pe.event->posted = false; + delete pe.event; + const_cast<QPostEvent &>(pe).event = 0; + return; + } + } +} + +#if defined(Q_WS_WIN) && !defined(QT_NO_DEBUG_STREAM) +/***************************************************************************** + Convenience functions for convert WM_* messages into human readable strings, + including a nifty QDebug operator<< for simpel QDebug() << msg output. + *****************************************************************************/ +QT_BEGIN_INCLUDE_NAMESPACE +#include <windowsx.h> +#include "qdebug.h" +QT_END_INCLUDE_NAMESPACE + +#if !defined(GET_X_LPARAM) +# define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) +# define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) +#endif +#ifdef _WIN32_WCE +# ifndef WM_NCACTIVATE +# define WM_NCACTIVATE 0x86 +# endif +#endif + +// The values below should never change. Note that none of the usual +// WM_...FIRST & WM_...LAST values are in the list, as they normally have other +// WM_... representations +struct { + uint WM; + const char* str; +} knownWM[] = +{{ 0x0000, "WM_NULL" }, + { 0x0001, "WM_CREATE" }, + { 0x0002, "WM_DESTROY" }, + { 0x0003, "WM_MOVE" }, + { 0x0005, "WM_SIZE" }, + { 0x0006, "WM_ACTIVATE" }, + { 0x0007, "WM_SETFOCUS" }, + { 0x0008, "WM_KILLFOCUS" }, + { 0x000A, "WM_ENABLE" }, + { 0x000B, "WM_SETREDRAW" }, + { 0x000C, "WM_SETTEXT" }, + { 0x000D, "WM_GETTEXT" }, + { 0x000E, "WM_GETTEXTLENGTH" }, + { 0x000F, "WM_PAINT" }, + { 0x0010, "WM_CLOSE" }, + { 0x0011, "WM_QUERYENDSESSION" }, + { 0x0013, "WM_QUERYOPEN" }, + { 0x0016, "WM_ENDSESSION" }, + { 0x0012, "WM_QUIT" }, + { 0x0014, "WM_ERASEBKGND" }, + { 0x0015, "WM_SYSCOLORCHANGE" }, + { 0x0018, "WM_SHOWWINDOW" }, + { 0x001A, "WM_WININICHANGE" }, + { 0x001B, "WM_DEVMODECHANGE" }, + { 0x001C, "WM_ACTIVATEAPP" }, + { 0x001D, "WM_FONTCHANGE" }, + { 0x001E, "WM_TIMECHANGE" }, + { 0x001F, "WM_CANCELMODE" }, + { 0x0020, "WM_SETCURSOR" }, + { 0x0021, "WM_MOUSEACTIVATE" }, + { 0x0022, "WM_CHILDACTIVATE" }, + { 0x0023, "WM_QUEUESYNC" }, + { 0x0024, "WM_GETMINMAXINFO" }, + { 0x0026, "WM_PAINTICON" }, + { 0x0027, "WM_ICONERASEBKGND" }, + { 0x0028, "WM_NEXTDLGCTL" }, + { 0x002A, "WM_SPOOLERSTATUS" }, + { 0x002B, "WM_DRAWITEM" }, + { 0x002C, "WM_MEASUREITEM" }, + { 0x002D, "WM_DELETEITEM" }, + { 0x002E, "WM_VKEYTOITEM" }, + { 0x002F, "WM_CHARTOITEM" }, + { 0x0030, "WM_SETFONT" }, + { 0x0031, "WM_GETFONT" }, + { 0x0032, "WM_SETHOTKEY" }, + { 0x0033, "WM_GETHOTKEY" }, + { 0x0037, "WM_QUERYDRAGICON" }, + { 0x0039, "WM_COMPAREITEM" }, + { 0x003D, "WM_GETOBJECT" }, + { 0x0041, "WM_COMPACTING" }, + { 0x0044, "WM_COMMNOTIFY" }, + { 0x0046, "WM_WINDOWPOSCHANGING" }, + { 0x0047, "WM_WINDOWPOSCHANGED" }, + { 0x0048, "WM_POWER" }, + { 0x004A, "WM_COPYDATA" }, + { 0x004B, "WM_CANCELJOURNAL" }, + { 0x004E, "WM_NOTIFY" }, + { 0x0050, "WM_INPUTLANGCHANGEREQUEST" }, + { 0x0051, "WM_INPUTLANGCHANGE" }, + { 0x0052, "WM_TCARD" }, + { 0x0053, "WM_HELP" }, + { 0x0054, "WM_USERCHANGED" }, + { 0x0055, "WM_NOTIFYFORMAT" }, + { 0x007B, "WM_CONTEXTMENU" }, + { 0x007C, "WM_STYLECHANGING" }, + { 0x007D, "WM_STYLECHANGED" }, + { 0x007E, "WM_DISPLAYCHANGE" }, + { 0x007F, "WM_GETICON" }, + { 0x0080, "WM_SETICON" }, + { 0x0081, "WM_NCCREATE" }, + { 0x0082, "WM_NCDESTROY" }, + { 0x0083, "WM_NCCALCSIZE" }, + { 0x0084, "WM_NCHITTEST" }, + { 0x0085, "WM_NCPAINT" }, + { 0x0086, "WM_NCACTIVATE" }, + { 0x0087, "WM_GETDLGCODE" }, + { 0x0088, "WM_SYNCPAINT" }, + { 0x00A0, "WM_NCMOUSEMOVE" }, + { 0x00A1, "WM_NCLBUTTONDOWN" }, + { 0x00A2, "WM_NCLBUTTONUP" }, + { 0x00A3, "WM_NCLBUTTONDBLCLK" }, + { 0x00A4, "WM_NCRBUTTONDOWN" }, + { 0x00A5, "WM_NCRBUTTONUP" }, + { 0x00A6, "WM_NCRBUTTONDBLCLK" }, + { 0x00A7, "WM_NCMBUTTONDOWN" }, + { 0x00A8, "WM_NCMBUTTONUP" }, + { 0x00A9, "WM_NCMBUTTONDBLCLK" }, + { 0x00AB, "WM_NCXBUTTONDOWN" }, + { 0x00AC, "WM_NCXBUTTONUP" }, + { 0x00AD, "WM_NCXBUTTONDBLCLK" }, + { 0x00FF, "WM_INPUT" }, + { 0x0100, "WM_KEYDOWN" }, + { 0x0101, "WM_KEYUP" }, + { 0x0102, "WM_CHAR" }, + { 0x0103, "WM_DEADCHAR" }, + { 0x0104, "WM_SYSKEYDOWN" }, + { 0x0105, "WM_SYSKEYUP" }, + { 0x0106, "WM_SYSCHAR" }, + { 0x0107, "WM_SYSDEADCHAR" }, + { 0x0109, "WM_UNICHAR" }, + { 0x010D, "WM_IME_STARTCOMPOSITION" }, + { 0x010E, "WM_IME_ENDCOMPOSITION" }, + { 0x010F, "WM_IME_COMPOSITION" }, + { 0x0110, "WM_INITDIALOG" }, + { 0x0111, "WM_COMMAND" }, + { 0x0112, "WM_SYSCOMMAND" }, + { 0x0113, "WM_TIMER" }, + { 0x0114, "WM_HSCROLL" }, + { 0x0115, "WM_VSCROLL" }, + { 0x0116, "WM_INITMENU" }, + { 0x0117, "WM_INITMENUPOPUP" }, + { 0x011F, "WM_MENUSELECT" }, + { 0x0120, "WM_MENUCHAR" }, + { 0x0121, "WM_ENTERIDLE" }, + { 0x0122, "WM_MENURBUTTONUP" }, + { 0x0123, "WM_MENUDRAG" }, + { 0x0124, "WM_MENUGETOBJECT" }, + { 0x0125, "WM_UNINITMENUPOPUP" }, + { 0x0126, "WM_MENUCOMMAND" }, + { 0x0127, "WM_CHANGEUISTATE" }, + { 0x0128, "WM_UPDATEUISTATE" }, + { 0x0129, "WM_QUERYUISTATE" }, + { 0x0132, "WM_CTLCOLORMSGBOX" }, + { 0x0133, "WM_CTLCOLOREDIT" }, + { 0x0134, "WM_CTLCOLORLISTBOX" }, + { 0x0135, "WM_CTLCOLORBTN" }, + { 0x0136, "WM_CTLCOLORDLG" }, + { 0x0137, "WM_CTLCOLORSCROLLBAR" }, + { 0x0138, "WM_CTLCOLORSTATIC" }, + { 0x0200, "WM_MOUSEMOVE" }, + { 0x0201, "WM_LBUTTONDOWN" }, + { 0x0202, "WM_LBUTTONUP" }, + { 0x0203, "WM_LBUTTONDBLCLK" }, + { 0x0204, "WM_RBUTTONDOWN" }, + { 0x0205, "WM_RBUTTONUP" }, + { 0x0206, "WM_RBUTTONDBLCLK" }, + { 0x0207, "WM_MBUTTONDOWN" }, + { 0x0208, "WM_MBUTTONUP" }, + { 0x0209, "WM_MBUTTONDBLCLK" }, + { 0x020A, "WM_MOUSEWHEEL" }, + { 0x020B, "WM_XBUTTONDOWN" }, + { 0x020C, "WM_XBUTTONUP" }, + { 0x020D, "WM_XBUTTONDBLCLK" }, + { 0x0210, "WM_PARENTNOTIFY" }, + { 0x0211, "WM_ENTERMENULOOP" }, + { 0x0212, "WM_EXITMENULOOP" }, + { 0x0213, "WM_NEXTMENU" }, + { 0x0214, "WM_SIZING" }, + { 0x0215, "WM_CAPTURECHANGED" }, + { 0x0216, "WM_MOVING" }, + { 0x0218, "WM_POWERBROADCAST" }, + { 0x0219, "WM_DEVICECHANGE" }, + { 0x0220, "WM_MDICREATE" }, + { 0x0221, "WM_MDIDESTROY" }, + { 0x0222, "WM_MDIACTIVATE" }, + { 0x0223, "WM_MDIRESTORE" }, + { 0x0224, "WM_MDINEXT" }, + { 0x0225, "WM_MDIMAXIMIZE" }, + { 0x0226, "WM_MDITILE" }, + { 0x0227, "WM_MDICASCADE" }, + { 0x0228, "WM_MDIICONARRANGE" }, + { 0x0229, "WM_MDIGETACTIVE" }, + { 0x0230, "WM_MDISETMENU" }, + { 0x0231, "WM_ENTERSIZEMOVE" }, + { 0x0232, "WM_EXITSIZEMOVE" }, + { 0x0233, "WM_DROPFILES" }, + { 0x0234, "WM_MDIREFRESHMENU" }, + { 0x0281, "WM_IME_SETCONTEXT" }, + { 0x0282, "WM_IME_NOTIFY" }, + { 0x0283, "WM_IME_CONTROL" }, + { 0x0284, "WM_IME_COMPOSITIONFULL" }, + { 0x0285, "WM_IME_SELECT" }, + { 0x0286, "WM_IME_CHAR" }, + { 0x0288, "WM_IME_REQUEST" }, + { 0x0290, "WM_IME_KEYDOWN" }, + { 0x0291, "WM_IME_KEYUP" }, + { 0x02A0, "WM_NCMOUSEHOVER" }, + { 0x02A1, "WM_MOUSEHOVER" }, + { 0x02A2, "WM_NCMOUSELEAVE" }, + { 0x02A3, "WM_MOUSELEAVE" }, + { 0x02B1, "WM_WTSSESSION_CHANGE" }, + { 0x02C0, "WM_TABLET_FIRST" }, + { 0x02C1, "WM_TABLET_FIRST + 1" }, + { 0x02C2, "WM_TABLET_FIRST + 2" }, + { 0x02C3, "WM_TABLET_FIRST + 3" }, + { 0x02C4, "WM_TABLET_FIRST + 4" }, + { 0x02C5, "WM_TABLET_FIRST + 5" }, + { 0x02C6, "WM_TABLET_FIRST + 6" }, + { 0x02C7, "WM_TABLET_FIRST + 7" }, + { 0x02C8, "WM_TABLET_FIRST + 8" }, + { 0x02C9, "WM_TABLET_FIRST + 9" }, + { 0x02CA, "WM_TABLET_FIRST + 10" }, + { 0x02CB, "WM_TABLET_FIRST + 11" }, + { 0x02CC, "WM_TABLET_FIRST + 12" }, + { 0x02CD, "WM_TABLET_FIRST + 13" }, + { 0x02CE, "WM_TABLET_FIRST + 14" }, + { 0x02CF, "WM_TABLET_FIRST + 15" }, + { 0x02D0, "WM_TABLET_FIRST + 16" }, + { 0x02D1, "WM_TABLET_FIRST + 17" }, + { 0x02D2, "WM_TABLET_FIRST + 18" }, + { 0x02D3, "WM_TABLET_FIRST + 19" }, + { 0x02D4, "WM_TABLET_FIRST + 20" }, + { 0x02D5, "WM_TABLET_FIRST + 21" }, + { 0x02D6, "WM_TABLET_FIRST + 22" }, + { 0x02D7, "WM_TABLET_FIRST + 23" }, + { 0x02D8, "WM_TABLET_FIRST + 24" }, + { 0x02D9, "WM_TABLET_FIRST + 25" }, + { 0x02DA, "WM_TABLET_FIRST + 26" }, + { 0x02DB, "WM_TABLET_FIRST + 27" }, + { 0x02DC, "WM_TABLET_FIRST + 28" }, + { 0x02DD, "WM_TABLET_FIRST + 29" }, + { 0x02DE, "WM_TABLET_FIRST + 30" }, + { 0x02DF, "WM_TABLET_LAST" }, + { 0x0300, "WM_CUT" }, + { 0x0301, "WM_COPY" }, + { 0x0302, "WM_PASTE" }, + { 0x0303, "WM_CLEAR" }, + { 0x0304, "WM_UNDO" }, + { 0x0305, "WM_RENDERFORMAT" }, + { 0x0306, "WM_RENDERALLFORMATS" }, + { 0x0307, "WM_DESTROYCLIPBOARD" }, + { 0x0308, "WM_DRAWCLIPBOARD" }, + { 0x0309, "WM_PAINTCLIPBOARD" }, + { 0x030A, "WM_VSCROLLCLIPBOARD" }, + { 0x030B, "WM_SIZECLIPBOARD" }, + { 0x030C, "WM_ASKCBFORMATNAME" }, + { 0x030D, "WM_CHANGECBCHAIN" }, + { 0x030E, "WM_HSCROLLCLIPBOARD" }, + { 0x030F, "WM_QUERYNEWPALETTE" }, + { 0x0310, "WM_PALETTEISCHANGING" }, + { 0x0311, "WM_PALETTECHANGED" }, + { 0x0312, "WM_HOTKEY" }, + { 0x0317, "WM_PRINT" }, + { 0x0318, "WM_PRINTCLIENT" }, + { 0x0319, "WM_APPCOMMAND" }, + { 0x031A, "WM_THEMECHANGED" }, + { 0x0358, "WM_HANDHELDFIRST" }, + { 0x0359, "WM_HANDHELDFIRST + 1" }, + { 0x035A, "WM_HANDHELDFIRST + 2" }, + { 0x035B, "WM_HANDHELDFIRST + 3" }, + { 0x035C, "WM_HANDHELDFIRST + 4" }, + { 0x035D, "WM_HANDHELDFIRST + 5" }, + { 0x035E, "WM_HANDHELDFIRST + 6" }, + { 0x035F, "WM_HANDHELDLAST" }, + { 0x0360, "WM_AFXFIRST" }, + { 0x0361, "WM_AFXFIRST + 1" }, + { 0x0362, "WM_AFXFIRST + 2" }, + { 0x0363, "WM_AFXFIRST + 3" }, + { 0x0364, "WM_AFXFIRST + 4" }, + { 0x0365, "WM_AFXFIRST + 5" }, + { 0x0366, "WM_AFXFIRST + 6" }, + { 0x0367, "WM_AFXFIRST + 7" }, + { 0x0368, "WM_AFXFIRST + 8" }, + { 0x0369, "WM_AFXFIRST + 9" }, + { 0x036A, "WM_AFXFIRST + 10" }, + { 0x036B, "WM_AFXFIRST + 11" }, + { 0x036C, "WM_AFXFIRST + 12" }, + { 0x036D, "WM_AFXFIRST + 13" }, + { 0x036E, "WM_AFXFIRST + 14" }, + { 0x036F, "WM_AFXFIRST + 15" }, + { 0x0370, "WM_AFXFIRST + 16" }, + { 0x0371, "WM_AFXFIRST + 17" }, + { 0x0372, "WM_AFXFIRST + 18" }, + { 0x0373, "WM_AFXFIRST + 19" }, + { 0x0374, "WM_AFXFIRST + 20" }, + { 0x0375, "WM_AFXFIRST + 21" }, + { 0x0376, "WM_AFXFIRST + 22" }, + { 0x0377, "WM_AFXFIRST + 23" }, + { 0x0378, "WM_AFXFIRST + 24" }, + { 0x0379, "WM_AFXFIRST + 25" }, + { 0x037A, "WM_AFXFIRST + 26" }, + { 0x037B, "WM_AFXFIRST + 27" }, + { 0x037C, "WM_AFXFIRST + 28" }, + { 0x037D, "WM_AFXFIRST + 29" }, + { 0x037E, "WM_AFXFIRST + 30" }, + { 0x037F, "WM_AFXLAST" }, + { 0x0380, "WM_PENWINFIRST" }, + { 0x0381, "WM_PENWINFIRST + 1" }, + { 0x0382, "WM_PENWINFIRST + 2" }, + { 0x0383, "WM_PENWINFIRST + 3" }, + { 0x0384, "WM_PENWINFIRST + 4" }, + { 0x0385, "WM_PENWINFIRST + 5" }, + { 0x0386, "WM_PENWINFIRST + 6" }, + { 0x0387, "WM_PENWINFIRST + 7" }, + { 0x0388, "WM_PENWINFIRST + 8" }, + { 0x0389, "WM_PENWINFIRST + 9" }, + { 0x038A, "WM_PENWINFIRST + 10" }, + { 0x038B, "WM_PENWINFIRST + 11" }, + { 0x038C, "WM_PENWINFIRST + 12" }, + { 0x038D, "WM_PENWINFIRST + 13" }, + { 0x038E, "WM_PENWINFIRST + 14" }, + { 0x038F, "WM_PENWINLAST" }, + { 0x0400, "WM_USER" }, + { 0x8000, "WM_APP" }, + { 0,0 }}; // End of known messages + +// Looks up the WM_ message in the table above +const char* findWMstr(uint msg) +{ + uint i = 0; + const char* result = 0; + // Known WM_'s + while (knownWM[i].str && (knownWM[i].WM != msg)) + ++i; + result = knownWM[i].str; + return result; +}; + +// Convenience function for converting flags and values into readable strings +struct FLAG_STRING_STRUCT +{ + uint value; + const char* str; +}; + +FLAG_STRING_STRUCT FLAG_STRING(int value = 0, const char *c = 0) +{ + FLAG_STRING_STRUCT s = {value, c}; + return s; +} + +#define FLGSTR(x) FLAG_STRING(x, #x) + +// Returns an ORed (" | ") together string for the flags active in the actual +// value. (...) must consist of FLAG_STRING, with a FLAG_STRING() as the last +// value in the list passed to the function +QString flagCheck(uint actual, ...) +{ + va_list ap; + va_start(ap, actual); + + QString result; + int count = 0; + FLAG_STRING_STRUCT v; + while((v=va_arg(ap,FLAG_STRING_STRUCT)).str) { + if ((actual & v.value) == v.value) { + if (count++) + result += QLatin1String(" | "); + result += QString::fromLatin1(v.str); + } + } + va_end(ap); + return result; +}; + +// Returns the string representation of the value in 'actual'. (...) must +// consist of FLAG_STRING, with a FLAG_STRING() as the last value in the list +// passed to the function +QString valueCheck(uint actual, ...) +{ + va_list ap; + va_start(ap, actual); + + QString result; + FLAG_STRING_STRUCT v; + while((v=va_arg(ap,FLAG_STRING_STRUCT)).str && (actual != v.value)) + ; + result = QString::fromLatin1(v.str); + + va_end(ap); + return result; +}; + +#ifdef Q_CC_BOR + +Q_CORE_EXPORT QString decodeMSG(const MSG& msg) +{ + return QString::fromLatin1("THis is not supported on Borland"); +} + +#else + +// Returns a "human readable" string representation of the MSG and the +// information it points to +QString decodeMSG(const MSG& msg) +{ + const WPARAM wParam = msg.wParam; + const LPARAM lParam = msg.lParam; + QString wmmsg = QString::fromLatin1(findWMstr(msg.message)); + // Unknown WM_, so use number + if (wmmsg.isEmpty()) + wmmsg = QString::fromLatin1("WM_(%1)").arg(msg.message); + + QString rawParameters; + rawParameters.sprintf("hwnd(0x%p) ", (void *)msg.hwnd); + + // Custom WM_'s + if (msg.message > WM_APP) + wmmsg = QString::fromLatin1("WM_APP + %1").arg(msg.message - WM_APP); + else if (msg.message > WM_USER) + wmmsg = QString::fromLatin1("WM_USER + %1").arg(msg.message - WM_USER); + + QString parameters; + switch (msg.message) { +#ifdef WM_ACTIVATE + case WM_ACTIVATE: + { + QString activation = valueCheck(wParam, + FLAG_STRING(WA_ACTIVE, "Activate"), + FLAG_STRING(WA_INACTIVE, "Deactivate"), + FLAG_STRING(WA_CLICKACTIVE, "Activate by mouseclick"), + FLAG_STRING()); + parameters.sprintf("%s Hwnd (0x%p)", activation.toLatin1().data(), (void *)msg.hwnd); + } + break; +#endif +#ifdef WM_CAPTURECHANGED + case WM_CAPTURECHANGED: + parameters.sprintf("Hwnd gaining capture (0x%p)", (void *)lParam); + break; +#endif +#ifdef WM_CREATE + case WM_CREATE: + { + LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam; + QString styles = flagCheck(lpcs->style, + FLGSTR(WS_BORDER), + FLGSTR(WS_CAPTION), + FLGSTR(WS_CHILD), + FLGSTR(WS_CLIPCHILDREN), + FLGSTR(WS_CLIPSIBLINGS), + FLGSTR(WS_DISABLED), + FLGSTR(WS_DLGFRAME), + FLGSTR(WS_GROUP), + FLGSTR(WS_HSCROLL), + FLGSTR(WS_OVERLAPPED), +#if defined(WS_OVERLAPPEDWINDOW) && (WS_OVERLAPPEDWINDOW != 0) + FLGSTR(WS_OVERLAPPEDWINDOW), +#endif +#ifdef WS_ICONIC + FLGSTR(WS_ICONIC), +#endif + FLGSTR(WS_MAXIMIZE), + FLGSTR(WS_MAXIMIZEBOX), + FLGSTR(WS_MINIMIZE), + FLGSTR(WS_MINIMIZEBOX), + FLGSTR(WS_OVERLAPPEDWINDOW), + FLGSTR(WS_POPUP), +#ifdef WS_POPUPWINDOW + FLGSTR(WS_POPUPWINDOW), +#endif + FLGSTR(WS_SIZEBOX), + FLGSTR(WS_SYSMENU), + FLGSTR(WS_TABSTOP), + FLGSTR(WS_THICKFRAME), +#ifdef WS_TILED + FLGSTR(WS_TILED), +#endif +#ifdef WS_TILEDWINDOW + FLGSTR(WS_TILEDWINDOW), +#endif + FLGSTR(WS_VISIBLE), + FLGSTR(WS_VSCROLL), + FLAG_STRING()); + + QString exStyles = flagCheck(lpcs->dwExStyle, +#ifdef WS_EX_ACCEPTFILES + FLGSTR(WS_EX_ACCEPTFILES), +#endif +#ifdef WS_EX_APPWINDOW + FLGSTR(WS_EX_APPWINDOW), +#endif + FLGSTR(WS_EX_CLIENTEDGE), + FLGSTR(WS_EX_DLGMODALFRAME), +#ifdef WS_EX_LEFT + FLGSTR(WS_EX_LEFT), +#endif + FLGSTR(WS_EX_LEFTSCROLLBAR), +#ifdef WS_EX_LTRREADING + FLGSTR(WS_EX_LTRREADING), +#endif +#ifdef WS_EX_MDICHILD + FLGSTR(WS_EX_MDICHILD), +#endif +#ifdef WS_EX_NOACTIVATE + FLGSTR(WS_EX_NOACTIVATE), +#endif +#ifdef WS_EX_NOANIMATION + FLGSTR(WS_EX_NOANIMATION), +#endif + FLGSTR(WS_EX_NOPARENTNOTIFY), + FLGSTR(WS_EX_OVERLAPPEDWINDOW), +#ifdef WS_EX_PALETTEWINDOW + FLGSTR(WS_EX_PALETTEWINDOW), +#endif +#ifdef WS_EX_RIGHT + FLGSTR(WS_EX_RIGHT), +#endif +#ifdef WS_EX_RIGHTSCROLLBAR + FLGSTR(WS_EX_RIGHTSCROLLBAR), +#endif +#ifdef WS_EX_RTLREADING + FLGSTR(WS_EX_RTLREADING), +#endif + FLGSTR(WS_EX_STATICEDGE), + FLGSTR(WS_EX_TOOLWINDOW), + FLGSTR(WS_EX_TOPMOST), +#ifdef WS_EX_TRANSPARENT + FLGSTR(WS_EX_TRANSPARENT), +#endif + FLGSTR(WS_EX_WINDOWEDGE), +#ifdef WS_EX_CAPTIONOKBTN + FLGSTR(WS_EX_CAPTIONOKBTN), +#endif + FLAG_STRING()); + + QString className; + if (lpcs->lpszClass != 0) { + if (HIWORD(lpcs->lpszClass) == 0) // Atom + className = QString::number(LOWORD(lpcs->lpszClass), 16); + else // String + className = QString((QChar*)lpcs->lpszClass, + (int)wcslen(reinterpret_cast<const wchar_t *>(lpcs->lpszClass))); + } + + QString windowName; + if (lpcs->lpszName != 0) + windowName = QString((QChar*)lpcs->lpszName, + (int)wcslen(reinterpret_cast<const wchar_t *>(lpcs->lpszName))); + + parameters.sprintf("x,y(%4d,%4d) w,h(%4d,%4d) className(%s) windowName(%s) parent(0x%p) style(%s) exStyle(%s)", + lpcs->x, lpcs->y, lpcs->cx, lpcs->cy, className.toLatin1().data(), + windowName.toLatin1().data(), (void *)lpcs->hwndParent, + styles.toLatin1().data(), exStyles.toLatin1().data()); + } + break; +#endif +#ifdef WM_DESTROY + case WM_DESTROY: + parameters.sprintf("Destroy hwnd (0x%p)", (void *)msg.hwnd); + break; +#endif +#ifdef WM_IME_NOTIFY + case WM_IME_NOTIFY: + { + QString imnCommand = valueCheck(wParam, + FLGSTR(IMN_CHANGECANDIDATE), + FLGSTR(IMN_CLOSECANDIDATE), + FLGSTR(IMN_CLOSESTATUSWINDOW), + FLGSTR(IMN_GUIDELINE), + FLGSTR(IMN_OPENCANDIDATE), + FLGSTR(IMN_OPENSTATUSWINDOW), + FLGSTR(IMN_SETCANDIDATEPOS), + FLGSTR(IMN_SETCOMPOSITIONFONT), + FLGSTR(IMN_SETCOMPOSITIONWINDOW), + FLGSTR(IMN_SETCONVERSIONMODE), + FLGSTR(IMN_SETOPENSTATUS), + FLGSTR(IMN_SETSENTENCEMODE), + FLGSTR(IMN_SETSTATUSWINDOWPOS), + FLAG_STRING()); + parameters.sprintf("Command(%s : 0x%p)", imnCommand.toLatin1().data(), (void *)lParam); + } + break; +#endif +#ifdef WM_IME_SETCONTEXT + case WM_IME_SETCONTEXT: + { + bool fSet = (BOOL)wParam; + DWORD fShow = (DWORD)lParam; + QString showFlgs = flagCheck(fShow, +#ifdef ISC_SHOWUICOMPOSITIONWINDOW + FLGSTR(ISC_SHOWUICOMPOSITIONWINDOW), +#endif +#ifdef ISC_SHOWUIGUIDWINDOW + FLGSTR(ISC_SHOWUIGUIDWINDOW), +#endif +#ifdef ISC_SHOWUISOFTKBD + FLGSTR(ISC_SHOWUISOFTKBD), +#endif + FLGSTR(ISC_SHOWUICANDIDATEWINDOW), + FLGSTR(ISC_SHOWUICANDIDATEWINDOW << 1), + FLGSTR(ISC_SHOWUICANDIDATEWINDOW << 2), + FLGSTR(ISC_SHOWUICANDIDATEWINDOW << 3), + FLAG_STRING()); + parameters.sprintf("Input context(%s) Show flags(%s)", (fSet?"Active":"Inactive"), showFlgs.toLatin1().data()); + } + break; +#endif +#ifdef WM_KILLFOCUS + case WM_KILLFOCUS: + parameters.sprintf("Hwnd gaining keyboard focus (0x%p)", (void *)wParam); + break; +#endif +#ifdef WM_CHAR + case WM_CHAR: +#endif +#ifdef WM_IME_CHAR + case WM_IME_CHAR: +#endif +#ifdef WM_KEYDOWN + case WM_KEYDOWN: +#endif +#ifdef WM_KEYUP + case WM_KEYUP: + { + int nVirtKey = (int)wParam; + long lKeyData = (long)lParam; + int repCount = (lKeyData & 0xffff); // Bit 0-15 + int scanCode = (lKeyData & 0xf0000) >> 16; // Bit 16-23 + bool contextCode = (lKeyData && 0x20000000); // Bit 29 + bool prevState = (lKeyData && 0x40000000); // Bit 30 + bool transState = (lKeyData && 0x80000000); // Bit 31 + parameters.sprintf("Virual-key(0x%x) Scancode(%d) Rep(%d) Contextcode(%d), Prev state(%d), Trans state(%d)", + nVirtKey, scanCode, repCount, contextCode, prevState, transState); + } + break; +#endif +#ifdef WM_NCACTIVATE + case WM_NCACTIVATE: + { + parameters = (msg.wParam? QLatin1String("Active Titlebar") : QLatin1String("Inactive Titlebar")); + } + break; +#endif +#ifdef WM_MOUSEACTIVATE + case WM_MOUSEACTIVATE: + { + QString mouseMsg = QString::fromLatin1(findWMstr(HIWORD(lParam))); + parameters.sprintf("TLW(0x%p) HittestCode(0x%x) MouseMsg(%s)", (void *)wParam, LOWORD(lParam), mouseMsg.toLatin1().data()); + } + break; +#endif +#ifdef WM_MOUSELEAVE + case WM_MOUSELEAVE: + break; // wParam & lParam not used +#endif +#ifdef WM_MOUSEHOVER + case WM_MOUSEHOVER: +#endif +#ifdef WM_MOUSEWHEEL + case WM_MOUSEWHEEL: +#endif +#ifdef WM_LBUTTONDBLCLK + case WM_LBUTTONDBLCLK: +#endif +#ifdef WM_LBUTTONDOWN + case WM_LBUTTONDOWN: +#endif +#ifdef WM_LBUTTONUP + case WM_LBUTTONUP: +#endif +#ifdef WM_MBUTTONDBLCLK + case WM_MBUTTONDBLCLK: +#endif +#ifdef WM_MBUTTONDOWN + case WM_MBUTTONDOWN: +#endif +#ifdef WM_MBUTTONUP + case WM_MBUTTONUP: +#endif +#ifdef WM_RBUTTONDBLCLK + case WM_RBUTTONDBLCLK: +#endif +#ifdef WM_RBUTTONDOWN + case WM_RBUTTONDOWN: +#endif +#ifdef WM_RBUTTONUP + case WM_RBUTTONUP: +#endif +#ifdef WM_MOUSEMOVE + case WM_MOUSEMOVE: + { + QString vrtKeys = flagCheck(wParam, + FLGSTR(MK_CONTROL), + FLGSTR(MK_LBUTTON), + FLGSTR(MK_MBUTTON), + FLGSTR(MK_RBUTTON), + FLGSTR(MK_SHIFT), +#ifdef MK_XBUTTON1 + FLGSTR(MK_XBUTTON1), +#endif +#ifdef MK_XBUTTON2 + FLGSTR(MK_XBUTTON2), +#endif + FLAG_STRING()); + parameters.sprintf("x,y(%4d,%4d) Virtual Keys(%s)", GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), vrtKeys.toLatin1().data()); + } + break; +#endif +#ifdef WM_MOVE + case WM_MOVE: + parameters.sprintf("x,y(%4d,%4d)", LOWORD(lParam), HIWORD(lParam)); + break; +#endif +#if defined(WM_PAINT) && defined(WM_ERASEBKGND) + case WM_ERASEBKGND: + case WM_PAINT: + parameters.sprintf("hdc(0x%p)", (void *)wParam); + break; +#endif +#ifdef WM_QUERYNEWPALETTE + case WM_QUERYNEWPALETTE: + break; // lParam & wParam are unused +#endif +#ifdef WM_SETCURSOR + case WM_SETCURSOR: + { + QString mouseMsg = QString::fromLatin1(findWMstr(HIWORD(lParam))); + parameters.sprintf("HitTestCode(0x%x) MouseMsg(%s)", LOWORD(lParam), mouseMsg.toLatin1().data()); + } + break; +#endif +#ifdef WM_SETFOCUS + case WM_SETFOCUS: + parameters.sprintf("Lost Focus (0x%p)", (void *)wParam); + break; +#endif +#ifdef WM_SETTEXT + case WM_SETTEXT: + parameters.sprintf("Set Text (%s)", QString((QChar*)lParam, (int)wcslen(reinterpret_cast<const wchar_t *>(lParam))).toLatin1().data()); //Unicode string + break; +#endif +#ifdef WM_SIZE + case WM_SIZE: + { + QString showMode = valueCheck(wParam, + FLGSTR(SIZE_MAXHIDE), + FLGSTR(SIZE_MAXIMIZED), + FLGSTR(SIZE_MAXSHOW), + FLGSTR(SIZE_MINIMIZED), + FLGSTR(SIZE_RESTORED), + FLAG_STRING()); + + parameters.sprintf("w,h(%4d,%4d) showmode(%s)", LOWORD(lParam), HIWORD(lParam), showMode.toLatin1().data()); + } + break; +#endif +#ifdef WM_WINDOWPOSCHANGED + case WM_WINDOWPOSCHANGED: + { + LPWINDOWPOS winPos = (LPWINDOWPOS)lParam; + if (!winPos) + break; + QString hwndAfter = valueCheck((uint)winPos->hwndInsertAfter, + FLAG_STRING((uint)HWND_BOTTOM, "HWND_BOTTOM"), + FLAG_STRING((int)HWND_NOTOPMOST, "HWND_NOTOPMOST"), + FLAG_STRING((uint)HWND_TOP, "HWND_TOP"), + FLAG_STRING((int)HWND_TOPMOST, "HWND_TOPMOST"), + FLAG_STRING()); + if (hwndAfter.size() == 0) + hwndAfter = QString::number((uint)winPos->hwndInsertAfter, 16); + QString flags = flagCheck(winPos->flags, + FLGSTR(SWP_DRAWFRAME), + FLGSTR(SWP_FRAMECHANGED), + FLGSTR(SWP_HIDEWINDOW), + FLGSTR(SWP_NOACTIVATE), +#ifdef SWP_NOCOPYBITS + FLGSTR(SWP_NOCOPYBITS), +#endif + FLGSTR(SWP_NOMOVE), + FLGSTR(SWP_NOOWNERZORDER), + FLGSTR(SWP_NOREDRAW), + FLGSTR(SWP_NOREPOSITION), +#ifdef SWP_NOSENDCHANGING + FLGSTR(SWP_NOSENDCHANGING), +#endif + FLGSTR(SWP_NOSIZE), + FLGSTR(SWP_NOZORDER), + FLGSTR(SWP_SHOWWINDOW), + FLAG_STRING()); + parameters.sprintf("x,y(%4d,%4d) w,h(%4d,%4d) flags(%s) hwndAfter(%s)", winPos->x, winPos->y, winPos->cx, winPos->cy, flags.toLatin1().data(), hwndAfter.toLatin1().data()); + } + break; +#endif + default: + parameters.sprintf("wParam(0x%p) lParam(0x%p)", (void *)wParam, (void *)lParam); + break; + } + // Yes, we want to give the WM_ names 20 chars of space before showing the + // decoded message, since some of the common messages are quite long, and + // we don't want the decoded information to vary in output position + QString message = QString::fromLatin1("%1: ").arg(wmmsg, 20); + message += rawParameters; + message += parameters; + return message; +} + +#endif + +QDebug operator<<(QDebug dbg, const MSG &msg) +{ + dbg << decodeMSG(msg); + return dbg.nospace(); +} +#endif + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcorecmdlineargs_p.h b/src/corelib/kernel/qcorecmdlineargs_p.h new file mode 100644 index 0000000..d1ca3f8 --- /dev/null +++ b/src/corelib/kernel/qcorecmdlineargs_p.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCORECMDLINEARGS_P_H +#define QCORECMDLINEARGS_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. +// + +#include "QtCore/qstring.h" +#include "QtCore/qstringlist.h" + +QT_BEGIN_NAMESPACE + +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) + +QT_BEGIN_INCLUDE_NAMESPACE +#include "QtCore/qvector.h" +#include "qt_windows.h" +QT_END_INCLUDE_NAMESPACE + +// template implementation of the parsing algorithm +// this is used from qcoreapplication_win.cpp and the tools (rcc, uic...) + +template<typename Char> +static QVector<Char*> qWinCmdLine(Char *cmdParam, int length, int &argc) +{ + QVector<Char*> argv(8); + Char *p = cmdParam; + Char *p_end = p + length; + + argc = 0; + + while (*p && p < p_end) { // parse cmd line arguments + while (QChar((short)(*p)).isSpace()) // skip white space + p++; + if (*p && p < p_end) { // arg starts + int quote; + Char *start, *r; + if (*p == Char('\"') || *p == Char('\'')) { // " or ' quote + quote = *p; + start = ++p; + } else { + quote = 0; + start = p; + } + r = start; + while (*p && p < p_end) { + if (quote) { + if (*p == quote) { + p++; + if (QChar((short)(*p)).isSpace()) + break; + quote = 0; + } + } + if (*p == '\\') { // escape char? + p++; + if (*p == Char('\"') || *p == Char('\'')) + ; // yes + else + p--; // treat \ literally + } else { + if (!quote && (*p == Char('\"') || *p == Char('\''))) { // " or ' quote + quote = *p++; + continue; + } else if (QChar((short)(*p)).isSpace() && !quote) + break; + } + if (*p) + *r++ = *p++; + } + if (*p && p < p_end) + p++; + *r = Char('\0'); + + if (argc >= (int)argv.size()-1) // expand array + argv.resize(argv.size()*2); + argv[argc++] = start; + } + } + argv[argc] = 0; + + return argv; +} + +static inline QStringList qWinCmdArgs(QString cmdLine) // not const-ref: this might be modified +{ + QStringList args; + + int argc = 0; + QVector<ushort*> argv = qWinCmdLine<ushort>((ushort*)cmdLine.utf16(), cmdLine.length(), argc); + for (int a = 0; a < argc; ++a) { + args << QString::fromUtf16(argv[a]); + } + + return args; +} + +static inline QStringList qCmdLineArgs(int argc, char *argv[]) +{ + Q_UNUSED(argc) + Q_UNUSED(argv) + QString cmdLine = QT_WA_INLINE( + QString::fromUtf16((unsigned short*)GetCommandLineW()), + QString::fromLocal8Bit(GetCommandLineA()) + ); + return qWinCmdArgs(cmdLine); +} + +#else // !Q_OS_WIN + +static inline QStringList qCmdLineArgs(int argc, char *argv[]) +{ + QStringList args; + for (int i = 0; i != argc; ++i) + args += QString::fromLocal8Bit(argv[i]); + return args; +} + +#endif // Q_OS_WIN + +QT_END_NAMESPACE + +#endif // QCORECMDLINEARGS_WIN_P_H diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp new file mode 100644 index 0000000..3fcfc98 --- /dev/null +++ b/src/corelib/kernel/qcoreevent.cpp @@ -0,0 +1,599 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcoreevent.h" +#include "qcoreapplication.h" +#include "qcoreapplication_p.h" + +#include "qmutex.h" +#include "qset.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QEvent + \brief The QEvent class is the base class of all + event classes. Event objects contain event parameters. + + \ingroup events + \ingroup environment + + Qt's main event loop (QCoreApplication::exec()) fetches native + window system events from the event queue, translates them into + QEvents, and sends the translated events to \l{QObject}s. + + In general, events come from the underlying window system + (spontaneous() returns true), but it is also possible to manually + send events using QCoreApplication::sendEvent() and + QCoreApplication::postEvent() (spontaneous() returns false). + + QObjects receive events by having their QObject::event() function + called. The function can be reimplemented in subclasses to + customize event handling and add additional event types; + QWidget::event() is a notable example. By default, events are + dispatched to event handlers like QObject::timerEvent() and + QWidget::mouseMoveEvent(). QObject::installEventFilter() allows an + object to intercept events destined for another object. + + The basic QEvent contains only an event type parameter and an + "accept" flag. The accept flag set with accept(), and cleared + with ignore(). It is set by default, but don't rely on this as + subclasses may choose to clear it in their constructor. + + Subclasses of QEvent contain additional parameters that describe + the particular event. + + \sa QObject::event(), QObject::installEventFilter(), + QWidget::event(), QCoreApplication::sendEvent(), + QCoreApplication::postEvent(), QCoreApplication::processEvents() +*/ + + +/*! + \enum QEvent::Type + + This enum type defines the valid event types in Qt. The event + types and the specialized classes for each type are as follows: + + \value None Not an event. + \value AccessibilityDescription Used to query accessibility description texts (QAccessibleEvent). + \value AccessibilityHelp Used to query accessibility help texts (QAccessibleEvent). + \value AccessibilityPrepare Accessibility information is requested. + \value ActionAdded A new action has been added (QActionEvent). + \value ActionChanged An action has been changed (QActionEvent). + \value ActionRemoved An action has been removed (QActionEvent). + \value ActivationChange A widget's top-level window activation state has changed. + \value ApplicationActivate The application has been made available to the user. + \value ApplicationActivated This enum has been deprecated. Use ApplicationActivate instead. + \value ApplicationDeactivate The application has been suspended, and is unavailable to the user. + \value ApplicationFontChange The default application font has changed. + \value ApplicationLayoutDirectionChange The default application layout direction has changed. + \value ApplicationPaletteChange The default application palette has changed. + \value ApplicationWindowIconChange The application's icon has changed. + \value ChildAdded An object gets a child (QChildEvent). + \value ChildInserted An object gets a child (QChildEvent). Qt3Support only, use ChildAdded instead. + \value ChildPolished A widget child gets polished (QChildEvent). + \value ChildRemoved An object loses a child (QChildEvent). + \value Clipboard The clipboard contents have changed (QClipboardEvent). + \value Close Widget was closed (QCloseEvent). + \value ContentsRectChange The margins of the widget's content rect changed. + \value ContextMenu Context popup menu (QContextMenuEvent). + \value CursorChange The widget's cursor has changed. + \value DeferredDelete The object will be deleted after it has cleaned up. + \value DragEnter The cursor enters a widget during a drag and drop operation (QDragEnterEvent). + \value DragLeave The cursor leaves a widget during a drag and drop operation (QDragLeaveEvent). + \value DragMove A drag and drop operation is in progress (QDragMoveEvent). + \value Drop A drag and drop operation is completed (QDropEvent). + \value EnabledChange Widget's enabled state has changed. + \value Enter Mouse enters widget's boundaries. + \value EnterEditFocus An editor widget gains focus for editing. + \value EnterWhatsThisMode Send to toplevel widgets when the application enters "What's This?" mode. + \value FileOpen File open request (QFileOpenEvent). + \value FocusIn Widget gains keyboard focus (QFocusEvent). + \value FocusOut Widget loses keyboard focus (QFocusEvent). + \value FontChange Widget's font has changed. + \value GrabKeyboard Item gains keyboard grab (QGraphicsItem only). + \value GrabMouse Item gains mouse grab (QGraphicsItem only). + \value GraphicsSceneContextMenu Context popup menu over a graphics scene (QGraphicsSceneContextMenuEvent). + \value GraphicsSceneDragEnter The cursor enters a graphics scene during a drag and drop operation. + \value GraphicsSceneDragLeave The cursor leaves a graphics scene during a drag and drop operation. + \value GraphicsSceneDragMove A drag and drop operation is in progress over a scene. + \value GraphicsSceneDrop A drag and drop operation is completed over a scene. + \value GraphicsSceneHelp The user requests help for a graphics scene (QHelpEvent). + \value GraphicsSceneHoverEnter The mouse cursor enters a hover item in a graphics scene (QGraphicsSceneHoverEvent). + \value GraphicsSceneHoverLeave The mouse cursor leaves a hover item in a graphics scene (QGraphicsSceneHoverEvent). + \value GraphicsSceneHoverMove The mouse cursor moves inside a hover item in a graphics scene (QGraphicsSceneHoverEvent). + \value GraphicsSceneMouseDoubleClick Mouse press again (double click) in a graphics scene (QGraphicsSceneMouseEvent). + \value GraphicsSceneMouseMove Move mouse in a graphics scene (QGraphicsSceneMouseEvent). + \value GraphicsSceneMousePress Mouse press in a graphics scene (QGraphicsSceneMouseEvent). + \value GraphicsSceneMouseRelease Mouse release in a graphics scene (QGraphicsSceneMouseEvent). + \value GraphicsSceneMove Widget was moved (QGraphicsSceneMoveEvent). + \value GraphicsSceneResize Widget was resized (QGraphicsSceneResizeEvent). + \value GraphicsSceneWheel Mouse wheel rolled in a graphics scene (QGraphicsSceneWheelEvent). + \value Hide Widget was hidden (QHideEvent). + \value HideToParent A child widget has been hidden. + \value HoverEnter The mouse cursor enters a hover widget (QHoverEvent). + \value HoverLeave The mouse cursor leaves a hover widget (QHoverEvent). + \value HoverMove The mouse cursor moves inside a hover widget (QHoverEvent). + \value IconDrag The main icon of a window has been dragged away (QIconDragEvent). + \value IconTextChange Widget's icon text has been changed. + \value InputMethod An input method is being used (QInputMethodEvent). + \value KeyPress Key press (QKeyEvent). + \value KeyRelease Key release (QKeyEvent). + \value LanguageChange The application translation changed. + \value LayoutDirectionChange The direction of layouts changed. + \value LayoutRequest Widget layout needs to be redone. + \value Leave Mouse leaves widget's boundaries. + \value LeaveEditFocus An editor widget loses focus for editing. + \value LeaveWhatsThisMode Send to toplevel widgets when the application leaves "What's This?" mode. + \value LocaleChange The system locale has changed. + \value NonClientAreaMouseButtonDblClick A mouse double click occurred outside the client area. + \value NonClientAreaMouseButtonPress A mouse button press occurred outside the client area. + \value NonClientAreaMouseButtonRelease A mouse button release occurred outside the client area. + \value NonClientAreaMouseMove A mouse move occurred outside the client area. + \value MacSizeChange The user changed his widget sizes (Mac OS X only). + \value MenubarUpdated The window's menu bar has been updated. + \value MetaCall An asynchronous method invocation via QMetaObject::invokeMethod(). + \value ModifiedChange Widgets modification state has been changed. + \value MouseButtonDblClick Mouse press again (QMouseEvent). + \value MouseButtonPress Mouse press (QMouseEvent). + \value MouseButtonRelease Mouse release (QMouseEvent). + \value MouseMove Mouse move (QMouseEvent). + \value MouseTrackingChange The mouse tracking state has changed. + \value Move Widget's position changed (QMoveEvent). + \value Paint Screen update necessary (QPaintEvent). + \value PaletteChange Palette of the widget changed. + \value ParentAboutToChange The widget parent is about to change. + \value ParentChange The widget parent has changed. + \value Polish The widget is polished. + \value PolishRequest The widget should be polished. + \value QueryWhatsThis The widget should accept the event if it has "What's This?" help. + \value Resize Widget's size changed (QResizeEvent). + \value Shortcut Key press in child for shortcut key handling (QShortcutEvent). + \value ShortcutOverride Key press in child, for overriding shortcut key handling (QKeyEvent). + \value Show Widget was shown on screen (QShowEvent). + \value ShowToParent A child widget has been shown. + \value SockAct Socket activated, used to implement QSocketNotifier. + \value StatusTip A status tip is requested (QStatusTipEvent). + \value StyleChange Widget's style has been changed. + \value TabletMove Wacom tablet move (QTabletEvent). + \value TabletPress Wacom tablet press (QTabletEvent). + \value TabletRelease Wacom tablet release (QTabletEvent). + \value OkRequest Ok button in decoration pressed. Supported only for Windows CE. + \value TabletEnterProximity Wacom tablet enter proximity event (QTabletEvent), sent to QApplication. + \value TabletLeaveProximity Wacom tablet leave proximity event (QTabletEvent), sent to QApplication. + \value Timer Regular timer events (QTimerEvent). + \value ToolBarChange The toolbar button is toggled on Mac OS X. + \value ToolTip A tooltip was requested (QHelpEvent). + \value ToolTipChange The widget's tooltip has changed. + \value UngrabKeyboard Item loses keyboard grab (QGraphicsItem only). + \value UngrabMouse Item loses mouse grab (QGraphicsItem only). + \value UpdateLater The widget should be queued to be repainted at a later time. + \value UpdateRequest The widget should be repainted. + \value WhatsThis The widget should reveal "What's This?" help (QHelpEvent). + \value WhatsThisClicked A link in a widget's "What's This?" help was clicked. + \value Wheel Mouse wheel rolled (QWheelEvent). + \value WinEventAct A Windows-specific activation event has occurred. + \value WindowActivate Window was activated. + \value WindowBlocked The window is blocked by a modal dialog. + \value WindowDeactivate Window was deactivated. + \value WindowIconChange The window's icon has changed. + \value WindowStateChange The \l{QWidget::windowState()}{window's state} (minimized, maximized or full-screen) has changed (QWindowStateChangeEvent). + \value WindowTitleChange The window title has changed. + \value WindowUnblocked The window is unblocked after a modal dialog exited. + \value ZOrderChange The widget's z-order has changed. This event is never sent to top level windows. + \value KeyboardLayoutChange The keyboard layout has changed. + \value DynamicPropertyChange A dynamic property was added, changed or removed from the object. + + User events should have values between \c User and \c{MaxUser}: + + \value User User-defined event. + \value MaxUser Last user event ID. + + For convenience, you can use the registerEventType() function to + register and reserve a custom event type for your + application. Doing so will allow you to avoid accidentally + re-using a custom event type already in use elsewhere in your + application. + + \omitvalue Accel + \omitvalue AccelAvailable + \omitvalue AccelOverride + \omitvalue AcceptDropsChange + \omitvalue ActivateControl + \omitvalue CaptionChange + \omitvalue ChildInsertedRequest + \omitvalue ChildInserted + \omitvalue Create + \omitvalue DeactivateControl + \omitvalue Destroy + \omitvalue DragResponse + \omitvalue EmbeddingControl + \omitvalue HelpRequest + \omitvalue IconChange + \omitvalue LayoutHint + \omitvalue Quit + \omitvalue Reparent + \omitvalue ShowWindowRequest + \omitvalue Speech + \omitvalue Style + \omitvalue ThreadChange + \omitvalue ZeroTimerEvent + \omitvalue ApplicationActivated + \omitvalue ApplicationDeactivated + \omitvalue MacGLWindowChange + \omitvalue NetworkReplyUpdated + \omitvalue FutureCallOut + \omitvalue CocoaRequestModal +*/ + +/*! + Contructs an event object of type \a type. +*/ +QEvent::QEvent(Type type) + : d(0), t(type), posted(false), spont(false), m_accept(true) +{} + +/*! + Destroys the event. If it was \link + QCoreApplication::postEvent() posted \endlink, + it will be removed from the list of events to be posted. +*/ + +QEvent::~QEvent() +{ + if (posted && QCoreApplication::instance()) + QCoreApplicationPrivate::removePostedEvent(this); +} + + +/*! + \property QEvent::accepted + the accept flag of the event object + + Setting the accept parameter indicates that the event receiver + wants the event. Unwanted events might be propagated to the parent + widget. By default, isAccepted() is set to true, but don't rely on + this as subclasses may choose to clear it in their constructor. + + For convenience, the accept flag can also be set with accept(), + and cleared with ignore(). +*/ + +/*! + \fn void QEvent::accept() + + Sets the accept flag of the event object, the equivalent of + calling setAccepted(true). + + Setting the accept parameter indicates that the event receiver + wants the event. Unwanted events might be propagated to the parent + widget. + + \sa ignore() +*/ + + +/*! + \fn void QEvent::ignore() + + Clears the accept flag parameter of the event object, the + equivalent of calling setAccepted(false). + + Clearing the accept parameter indicates that the event receiver + does not want the event. Unwanted events might be propgated to the + parent widget. + + \sa accept() +*/ + + +/*! + \fn QEvent::Type QEvent::type() const + + Returns the event type. +*/ + +/*! + \fn bool QEvent::spontaneous() const + + Returns true if the event originated outside the application (a + system event); otherwise returns false. + + The return value of this function is not defined for paint events. +*/ + +class QEventUserEventRegistration +{ +public: + QMutex mutex; + QSet<int> set; +}; +Q_GLOBAL_STATIC(QEventUserEventRegistration, userEventRegistrationHelper) + +/*! + \since 4.4 + \threadsafe + + Registers and returns a custom event type. The \a hint provided + will be used if it is available, otherwise it will return a value + between QEvent::User and QEvent::MaxUser that has not yet been + registered. The \a hint is ignored if its value is not between + QEvent::User and QEvent::MaxUser. +*/ +int QEvent::registerEventType(int hint) +{ + QEventUserEventRegistration *userEventRegistration + = userEventRegistrationHelper(); + if (!userEventRegistration) + return -1; + + QMutexLocker locker(&userEventRegistration->mutex); + + // if the type hint hasn't been registered yet, take it + if (hint >= QEvent::User && hint <= QEvent::MaxUser && !userEventRegistration->set.contains(hint)) { + userEventRegistration->set.insert(hint); + return hint; + } + + // find a free event type, starting at MaxUser and decreasing + int id = QEvent::MaxUser; + while (userEventRegistration->set.contains(id) && id >= QEvent::User) + --id; + if (id >= QEvent::User) { + userEventRegistration->set.insert(id); + return id; + } + return -1; +} + +/*! + \class QTimerEvent + \brief The QTimerEvent class contains parameters that describe a + timer event. + + \ingroup events + + Timer events are sent at regular intervals to objects that have + started one or more timers. Each timer has a unique identifier. A + timer is started with QObject::startTimer(). + + The QTimer class provides a high-level programming interface that + uses signals instead of events. It also provides single-shot timers. + + The event handler QObject::timerEvent() receives timer events. + + \sa QTimer, QObject::timerEvent(), QObject::startTimer(), + QObject::killTimer() +*/ + +/*! + Constructs a timer event object with the timer identifier set to + \a timerId. +*/ +QTimerEvent::QTimerEvent(int timerId) + : QEvent(Timer), id(timerId) +{} + +/*! \internal +*/ +QTimerEvent::~QTimerEvent() +{ +} + +/*! + \fn int QTimerEvent::timerId() const + + Returns the unique timer identifier, which is the same identifier + as returned from QObject::startTimer(). +*/ + +/*! + \class QChildEvent + \brief The QChildEvent class contains event parameters for child object + events. + + \ingroup events + + Child events are sent immediately to objects when children are + added or removed. + + In both cases you can only rely on the child being a QObject (or, + if QObject::isWidgetType() returns true, a QWidget). This is + because in the QEvent::ChildAdded case the child is not yet fully + constructed; in the QEvent::ChildRemoved case it might have + already been destructed. + + The handler for these events is QObject::childEvent(). +*/ + +/*! + Constructs a child event object of a particular \a type for the + \a child. + + \a type can be QEvent::ChildAdded, QEvent::ChildRemoved, + QEvent::ChildPolished, or QEvent::ChildRemoved. + + \sa child() +*/ +QChildEvent::QChildEvent(Type type, QObject *child) + : QEvent(type), c(child) +{} + +/*! \internal +*/ +QChildEvent::~QChildEvent() +{ +} + +/*! + \fn QObject *QChildEvent::child() const + + Returns the child object that was added or removed. +*/ + +/*! + \fn bool QChildEvent::added() const + + Returns true if type() is QEvent::ChildAdded; otherwise returns + false. +*/ + +/*! + \fn bool QChildEvent::removed() const + + Returns true if type() is QEvent::ChildRemoved; otherwise returns + false. +*/ + +/*! + \fn bool QChildEvent::polished() const + + Returns true if type() is QEvent::ChildPolished; otherwise returns + false. +*/ + +/*! + \class QCustomEvent + \brief The QCustomEvent class provides support for custom events. + + \compat + + QCustomEvent has a \c{void *} that can be used to store custom + data. + + In Qt 3, QObject::customEvent() took a QCustomEvent pointer. We + found out that this approach was unsatisfactory, because + there was often no safe way of deleting the data held in the + \c{void *}. + + In Qt 4, QObject::customEvent() takes a plain QEvent pointer. + You can add custom data by subclassing. + + \sa QObject::customEvent(), QCoreApplication::notify() +*/ + +/*! + \fn QCustomEvent::QCustomEvent(int type, void *data) + + Constructs a custom event object with the event \a type and a + pointer to \a data. The value of \a type must be at least as + large as QEvent::User. By default, the data pointer is set to 0. +*/ +#ifdef QT3_SUPPORT +QCustomEvent::QCustomEvent(int type, void *data) + : QEvent(static_cast<Type>(type)) +{ + d = reinterpret_cast<QEventPrivate *>(data); +} + +/*! \internal +*/ +QCustomEvent::~QCustomEvent() +{ +} +#endif +/*! + \fn void QCustomEvent::setData(void *data) + + \compat + + Sets the generic data pointer to \a data. + + \sa data() +*/ + +/*! + \fn void *QCustomEvent::data() const + + \compat + + Returns a pointer to the generic event data. + + \sa setData() +*/ + +/*! + \fn bool QChildEvent::inserted() const + + \compat + + A child has been inserted if the event's type() is ChildInserted. +*/ + +/*! + \class QDynamicPropertyChangeEvent + \since 4.2 + \brief The QDynamicPropertyChangeEvent class contains event parameters for dynamic + property change events. + + \ingroup events + + Dynamic property change events are sent to objects when properties are + dynamically added, changed or removed using QObject::setProperty(). +*/ + +/*! + Constructs a dynamic property change event object with the property name set to + \a name. +*/ +QDynamicPropertyChangeEvent::QDynamicPropertyChangeEvent(const QByteArray &name) + : QEvent(QEvent::DynamicPropertyChange), n(name) +{ +} + +/*! + \internal +*/ +QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent() +{ +} + +/*! + \fn QByteArray QDynamicPropertyChangeEvent::propertyName() const + + Returns the name of the dynamic property that was added, changed or + removed. + + \sa QObject::setProperty(), QObject::dynamicPropertyNames() +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h new file mode 100644 index 0000000..1bddbe5 --- /dev/null +++ b/src/corelib/kernel/qcoreevent.h @@ -0,0 +1,370 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOREEVENT_H +#define QCOREEVENT_H + +#include <QtCore/qnamespace.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qobjectdefs.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QEventPrivate; +class Q_CORE_EXPORT QEvent // event base class +{ + Q_GADGET + QDOC_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) + Q_ENUMS(Type) +public: + enum Type { + /* + If you get a strange compiler error on the line with None, + it's probably because you're also including X11 headers, + which #define the symbol None. Put the X11 includes after + the Qt includes to solve this problem. + */ + None = 0, // invalid event + Timer = 1, // timer event + MouseButtonPress = 2, // mouse button pressed + MouseButtonRelease = 3, // mouse button released + MouseButtonDblClick = 4, // mouse button double click + MouseMove = 5, // mouse move + KeyPress = 6, // key pressed + KeyRelease = 7, // key released + FocusIn = 8, // keyboard focus received + FocusOut = 9, // keyboard focus lost + Enter = 10, // mouse enters widget + Leave = 11, // mouse leaves widget + Paint = 12, // paint widget + Move = 13, // move widget + Resize = 14, // resize widget + Create = 15, // after widget creation + Destroy = 16, // during widget destruction + Show = 17, // widget is shown + Hide = 18, // widget is hidden + Close = 19, // request to close widget + Quit = 20, // request to quit application + ParentChange = 21, // widget has been reparented + ParentAboutToChange = 131, // sent just before the parent change is done +#ifdef QT3_SUPPORT + Reparent = ParentChange, +#endif + ThreadChange = 22, // object has changed threads + WindowActivate = 24, // window was activated + WindowDeactivate = 25, // window was deactivated + ShowToParent = 26, // widget is shown to parent + HideToParent = 27, // widget is hidden to parent + Wheel = 31, // wheel event + WindowTitleChange = 33, // window title changed + WindowIconChange = 34, // icon changed + ApplicationWindowIconChange = 35, // application icon changed + ApplicationFontChange = 36, // application font changed + ApplicationLayoutDirectionChange = 37, // application layout direction changed + ApplicationPaletteChange = 38, // application palette changed + PaletteChange = 39, // widget palette changed + Clipboard = 40, // internal clipboard event + Speech = 42, // reserved for speech input + MetaCall = 43, // meta call event + SockAct = 50, // socket activation + WinEventAct = 132, // win event activation + DeferredDelete = 52, // deferred delete event + DragEnter = 60, // drag moves into widget + DragMove = 61, // drag moves in widget + DragLeave = 62, // drag leaves or is cancelled + Drop = 63, // actual drop + DragResponse = 64, // drag accepted/rejected + ChildAdded = 68, // new child widget + ChildPolished = 69, // polished child widget +#ifdef QT3_SUPPORT + ChildInsertedRequest = 67, // send ChildInserted compatibility events to receiver + ChildInserted = 70, // compatibility child inserted + LayoutHint = 72, // compatibility relayout request +#endif + ChildRemoved = 71, // deleted child widget + ShowWindowRequest = 73, // widget's window should be mapped + PolishRequest = 74, // widget should be polished + Polish = 75, // widget is polished + LayoutRequest = 76, // widget should be relayouted + UpdateRequest = 77, // widget should be repainted + UpdateLater = 78, // request update() later + + EmbeddingControl = 79, // ActiveX embedding + ActivateControl = 80, // ActiveX activation + DeactivateControl = 81, // ActiveX deactivation + ContextMenu = 82, // context popup menu + InputMethod = 83, // input method + AccessibilityPrepare = 86, // accessibility information is requested + TabletMove = 87, // Wacom tablet event + LocaleChange = 88, // the system locale changed + LanguageChange = 89, // the application language changed + LayoutDirectionChange = 90, // the layout direction changed + Style = 91, // internal style event + TabletPress = 92, // tablet press + TabletRelease = 93, // tablet release + OkRequest = 94, // CE (Ok) button pressed + HelpRequest = 95, // CE (?) button pressed + + IconDrag = 96, // proxy icon dragged + + FontChange = 97, // font has changed + EnabledChange = 98, // enabled state has changed + ActivationChange = 99, // window activation has changed + StyleChange = 100, // style has changed + IconTextChange = 101, // icon text has changed + ModifiedChange = 102, // modified state has changed + MouseTrackingChange = 109, // mouse tracking state has changed + + WindowBlocked = 103, // window is about to be blocked modally + WindowUnblocked = 104, // windows modal blocking has ended + WindowStateChange = 105, + + ToolTip = 110, + WhatsThis = 111, + StatusTip = 112, + + ActionChanged = 113, + ActionAdded = 114, + ActionRemoved = 115, + + FileOpen = 116, // file open request + + Shortcut = 117, // shortcut triggered + ShortcutOverride = 51, // shortcut override request + +#ifdef QT3_SUPPORT + Accel = 30, // accelerator event + AccelAvailable = 32, // accelerator available event + AccelOverride = ShortcutOverride, // accelerator override event +#endif + + WhatsThisClicked = 118, + +#ifdef QT3_SUPPORT + CaptionChange = WindowTitleChange, + IconChange = WindowIconChange, +#endif + ToolBarChange = 120, // toolbar visibility toggled + + ApplicationActivate = 121, // application has been changed to active + ApplicationActivated = ApplicationActivate, // deprecated + ApplicationDeactivate = 122, // application has been changed to inactive + ApplicationDeactivated = ApplicationDeactivate, // deprecated + + QueryWhatsThis = 123, // query what's this widget help + EnterWhatsThisMode = 124, + LeaveWhatsThisMode = 125, + + ZOrderChange = 126, // child widget has had its z-order changed + + HoverEnter = 127, // mouse cursor enters a hover widget + HoverLeave = 128, // mouse cursor leaves a hover widget + HoverMove = 129, // mouse cursor move inside a hover widget + + AccessibilityHelp = 119, // accessibility help text request + AccessibilityDescription = 130, // accessibility description text request + + // last event id used = 132 + +#ifdef QT_KEYPAD_NAVIGATION + EnterEditFocus = 150, // enter edit mode in keypad navigation + LeaveEditFocus = 151, // enter edit mode in keypad navigation +#endif + AcceptDropsChange = 152, + + MenubarUpdated = 153, // Support event for Q3MainWindow, which needs to + // knwow when QMenubar is updated. + + ZeroTimerEvent = 154, // Used for Windows Zero timer events + + GraphicsSceneMouseMove = 155, // GraphicsView + GraphicsSceneMousePress = 156, + GraphicsSceneMouseRelease = 157, + GraphicsSceneMouseDoubleClick = 158, + GraphicsSceneContextMenu = 159, + GraphicsSceneHoverEnter = 160, + GraphicsSceneHoverMove = 161, + GraphicsSceneHoverLeave = 162, + GraphicsSceneHelp = 163, + GraphicsSceneDragEnter = 164, + GraphicsSceneDragMove = 165, + GraphicsSceneDragLeave = 166, + GraphicsSceneDrop = 167, + GraphicsSceneWheel = 168, + + KeyboardLayoutChange = 169, // keyboard layout changed + + DynamicPropertyChange = 170, // A dynamic property was changed through setProperty/property + + TabletEnterProximity = 171, + TabletLeaveProximity = 172, + + NonClientAreaMouseMove = 173, + NonClientAreaMouseButtonPress = 174, + NonClientAreaMouseButtonRelease = 175, + NonClientAreaMouseButtonDblClick = 176, + + MacSizeChange = 177, // when the Qt::WA_Mac{Normal,Small,Mini}Size changes + + ContentsRectChange = 178, // sent by QWidget::setContentsMargins (internal) + + MacGLWindowChange = 179, // Internal! the window of the GLWidget has changed + + FutureCallOut = 180, + + GraphicsSceneResize = 181, + GraphicsSceneMove = 182, + + CursorChange = 183, + ToolTipChange = 184, + + NetworkReplyUpdated = 185, // Internal for QNetworkReply + + GrabMouse = 186, + UngrabMouse = 187, + GrabKeyboard = 188, + UngrabKeyboard = 189, + CocoaRequestModal = 190, // Internal for requesting an application modal Cocoa Window + + Signal = 191, + StateFinished = 192, + Bound = 193, + + // 512 reserved for Qt Jambi's MetaCall event + // 513 reserved for Qt Jambi's DeleteOnMainThread event + + User = 1000, // first user event id + MaxUser = 65535 // last user event id + }; + + QEvent(Type type); + virtual ~QEvent(); + inline Type type() const { return static_cast<Type>(t); } + inline bool spontaneous() const { return spont; } + + inline void setAccepted(bool accepted) { m_accept = accepted; } + inline bool isAccepted() const { return m_accept; } + + inline void accept() { m_accept = true; } + inline void ignore() { m_accept = false; } + + static int registerEventType(int hint = -1); + +protected: + QEventPrivate *d; + ushort t; + +private: + ushort posted : 1; + ushort spont : 1; + ushort m_accept : 1; + ushort reserved : 13; + + friend class QCoreApplication; + friend class QCoreApplicationPrivate; + friend class QThreadData; + friend class QApplication; + friend class QApplicationPrivate; + friend class Q3AccelManager; + friend class QShortcutMap; + friend class QETWidget; +}; + +class Q_CORE_EXPORT QTimerEvent : public QEvent +{ +public: + QTimerEvent( int timerId ); + ~QTimerEvent(); + int timerId() const { return id; } +protected: + int id; +}; + +class QObject; + +class Q_CORE_EXPORT QChildEvent : public QEvent +{ +public: + QChildEvent( Type type, QObject *child ); + ~QChildEvent(); + QObject *child() const { return c; } + bool added() const { return type() == ChildAdded; } +#ifdef QT3_SUPPORT + QT3_SUPPORT bool inserted() const { return type() == ChildInserted; } +#endif + bool polished() const { return type() == ChildPolished; } + bool removed() const { return type() == ChildRemoved; } +protected: + QObject *c; +}; + +#ifdef QT3_SUPPORT +class Q_CORE_EXPORT QCustomEvent : public QEvent +{ +public: + QT3_SUPPORT_CONSTRUCTOR QCustomEvent(int type, void *data = 0); + ~QCustomEvent(); + QT3_SUPPORT void *data() const { return d; } + QT3_SUPPORT void setData(void* aData) { d = reinterpret_cast<QEventPrivate *>(aData); } +}; +#endif + +class Q_CORE_EXPORT QDynamicPropertyChangeEvent : public QEvent +{ +public: + QDynamicPropertyChangeEvent(const QByteArray &name); + ~QDynamicPropertyChangeEvent(); + + inline QByteArray propertyName() const { return n; } + +private: + QByteArray n; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QCOREEVENT_H diff --git a/src/corelib/kernel/qcoreglobaldata.cpp b/src/corelib/kernel/qcoreglobaldata.cpp new file mode 100644 index 0000000..c756b6a --- /dev/null +++ b/src/corelib/kernel/qcoreglobaldata.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcoreglobaldata_p.h" + +#include <QtDebug> + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QCoreGlobalData, globalInstance) + +QCoreGlobalData *QCoreGlobalData::instance() +{ + return globalInstance(); +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcoreglobaldata_p.h b/src/corelib/kernel/qcoreglobaldata_p.h new file mode 100644 index 0000000..b4904ab --- /dev/null +++ b/src/corelib/kernel/qcoreglobaldata_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOREGLOBALDATA_P_H +#define QCOREGLOBALDATA_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. +// + +#include "QtCore/qmap.h" +#include "QtCore/qstringlist.h" +#include "QtCore/qreadwritelock.h" + +QT_BEGIN_NAMESPACE + +struct QCoreGlobalData { + QMap<QString, QStringList> dirSearchPaths; + QReadWriteLock dirSearchPathsLock; + + static QCoreGlobalData *instance(); +}; + + +QT_END_NAMESPACE +#endif // QCOREGLOBALDATA_P_H + diff --git a/src/corelib/kernel/qcrashhandler.cpp b/src/corelib/kernel/qcrashhandler.cpp new file mode 100644 index 0000000..7350b66 --- /dev/null +++ b/src/corelib/kernel/qcrashhandler.cpp @@ -0,0 +1,420 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/************************************************************************* + * + * stacktrace.c 1.2 1998/12/21 + * + * Copyright (c) 1998 by Bjorn Reese <breese@imada.ou.dk> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************/ + +#include "qplatformdefs.h" +#include "private/qcrashhandler_p.h" +#include "qbytearray.h" // for qvsnprintf() + +#ifndef QT_NO_CRASHHANDLER + +#include <stdio.h> +#include <signal.h> +#include <stdlib.h> + +QT_BEGIN_NAMESPACE + +QtCrashHandler QSegfaultHandler::callback = 0; + +#if defined(__GLIBC__) && (__GLIBC__ >= 2) && !defined(__UCLIBC__) && !defined(QT_LINUXBASE) +QT_BEGIN_INCLUDE_NAMESPACE +# include "qstring.h" +# include <execinfo.h> +QT_END_INCLUDE_NAMESPACE + +static void print_backtrace(FILE *outb) +{ + void *stack[128]; + int stack_size = backtrace(stack, sizeof(stack) / sizeof(void *)); + char **stack_symbols = backtrace_symbols(stack, stack_size); + fprintf(outb, "Stack [%d]:\n", stack_size); + if(FILE *cppfilt = popen("c++filt", "rw")) { + dup2(fileno(outb), fileno(cppfilt)); + for(int i = stack_size-1; i>=0; --i) + fwrite(stack_symbols[i], 1, strlen(stack_symbols[i]), cppfilt); + pclose(cppfilt); + } else { + for(int i = stack_size-1; i>=0; --i) + fprintf(outb, "#%d %p [%s]\n", i, stack[i], stack_symbols[i]); + } +} +static void init_backtrace(char **, int) +{ +} + +#else /* Don't use the GLIBC callback */ +/* Code sourced from: */ +QT_BEGIN_INCLUDE_NAMESPACE +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> +#if defined(Q_OS_IRIX) && defined(USE_LIBEXC) +# include <libexc.h> +#endif +QT_END_INCLUDE_NAMESPACE + + +static char *globalProgName = NULL; +static bool backtrace_command(FILE *outb, const char *format, ...) +{ + + bool ret = false; + char buffer[50]; + + /* + * Please note that vsnprintf() is not ASync safe (ie. cannot safely + * be used from a signal handler.) If this proves to be a problem + * then the cmd string can be built by more basic functions such as + * strcpy, strcat, and a home-made integer-to-ascii function. + */ + va_list args; + char cmd[512]; + va_start(args, format); + qvsnprintf(cmd, 512, format, args); + va_end(args); + + char *foo = cmd; +#if 0 + foo = "echo hi"; +#endif + if(FILE *inb = popen(foo, "r")) { + while(!feof(inb)) { + int len = fread(buffer, 1, sizeof(buffer), inb); + if(!len) + break; + if(!ret) { + fwrite("Output from ", 1, strlen("Output from "), outb); + strtok(cmd, " "); + fwrite(cmd, 1, strlen(cmd), outb); + fwrite("\n", 1, 1, outb); + ret = true; + } + fwrite(buffer, 1, len, outb); + } + fclose(inb); + } + return ret; +} + +static void init_backtrace(char **argv, int argc) +{ + if(argc >= 1) + globalProgName = argv[0]; +} + +static void print_backtrace(FILE *outb) +{ + /* + * In general dbx seems to do a better job than gdb. + * + * Different dbx implementations require different flags/commands. + */ +#if defined(Q_OS_AIX) + if(backtrace_command(outb, "dbx -a %d 2>/dev/null <<EOF\n" + "where\n" + "detach\n" + "EOF\n", + (int)getpid())) + return; + if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" + "set prompt\n" + "where\n" + "detach\n" + "quit\n" + "EOF\n", + globalProgName, (int)getpid())) + return; +#elif defined(Q_OS_FREEBSD) + /* + * FreeBSD insists on sending a SIGSTOP to the process we + * attach to, so we let the debugger send a SIGCONT to that + * process after we have detached. + */ + if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" + "set prompt\n" + "where\n" + "detach\n" + "shell kill -CONT %d\n" + "quit\n" + "EOF\n", + globalProgName, (int)getpid(), (int)getpid())) + return; +#elif defined(Q_OS_HPUX) + /* + * HP decided to call their debugger xdb. + * + * This does not seem to work properly yet. The debugger says + * "Note: Stack traces may not be possible until you are + * stopped in user code." on HP-UX 09.01 + * + * -L = line-oriented interface. + * "T [depth]" gives a stacktrace with local variables. + * The final "y" is confirmation to the quit command. + */ + if(backtrace_command(outb, "xdb -P %d -L %s 2>&1 <<EOF\n" + "T 50\n" + "q\ny\n" + "EOF\n", + (int)getpid(), globalProgName)) + return; + if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" + "set prompt\n" + "where\n" + "detach\n" + "quit\n" + "EOF\n", + globalProgName, (int)getpid())) + return; +#elif defined(Q_OS_IRIX) + /* + * "set $page=0" drops hold mode + * "dump ." displays the contents of the variables + */ + if(backtrace_command(outb, "dbx -p %d 2>/dev/null <<EOF\n" + "set \\$page=0\n" + "where\n" +# if !defined(__GNUC__) + /* gcc does not generate this information */ + "dump .\n" +# endif + "detach\n" + "EOF\n", + (int)getpid())) + return; + +# if defined(USE_LIBEXC) + if(trace_back_stack_and_print()) + return; +# endif + if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" + "set prompt\n" + "where\n" + "echo ---\\n\n" + "frame 5\n" /* Skip signal handler frames */ + "set \\$x = 50\n" + "while (\\$x)\n" /* Print local variables for each frame */ + "info locals\n" + "up\n" + "set \\$x--\n" + "end\n" + "echo ---\\n\n" + "detach\n" + "quit\n" + "EOF\n", + globalProgName, (int)getpid())) + return; +#elif defined(Q_OS_OSF) + if(backtrace_command(outb, "dbx -pid %d %s 2>/dev/null <<EOF\n" + "where\n" + "detach\n" + "quit\n" + "EOF\n", + (int)getpid(), globalProgName)) + return; + if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" + "set prompt\n" + "where\n" + "detach\n" + "quit\n" + "EOF\n", + globalProgName, (int)getpid())) + return; +#elif defined(Q_OS_SCO) + /* + * SCO OpenServer dbx is like a catch-22. The 'detach' command + * depends on whether ptrace(S) support detaching or not. If it + * is supported then 'detach' must be used, otherwise the process + * will be killed upon dbx exit. If it isn't supported then 'detach' + * will cause the process to be killed. We do not want it to be + * killed. + * + * Out of two evils, the omission of 'detach' was chosen because + * it worked on our system. + */ + if(backtrace_command(outb, "dbx %s %d 2>/dev/null <<EOF\n" + "where\n" + "quit\nEOF\n", + globalProgName, (int)getpid())) + return; + if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" + "set prompt\n" + "where\n" + "detach\n" + "quit\n" + "EOF\n", + globalProgName, (int)getpid())) + return; +#elif defined(Q_OS_SOLARIS) + if(backtrace_command(outb, "dbx %s %d 2>/dev/null <<EOF\n" + "where\n" + "detach\n" + "EOF\n", + globalProgName, (int)getpid())) + return; + if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" + "set prompt\n" + "where\n" + "echo ---\\n\n" + "frame 5\n" /* Skip signal handler frames */ + "set \\$x = 50\n" + "while (\\$x)\n" /* Print local variables for each frame */ + "info locals\n" + "up\n" + "set \\$x--\n" + "end\n" + "echo ---\\n\n" + "detach\n" + "quit\n" + "EOF\n", + globalProgName, (int)getpid())) + return; + if(backtrace_command(outb, "/usr/proc/bin/pstack %d", + (int)getpid())) + return; + /* + * Other Unices (AIX, HPUX, SCO) also have adb, but + * they seem unable to attach to a running process.) + */ + if(backtrace_command(outb, "adb %s 2>&1 <<EOF\n" + "0t%d:A\n" /* Attach to pid */ + "\\$c\n" /* print stacktrace */ + ":R\n" /* Detach */ + "\\$q\n" /* Quit */ + "EOF\n", + globalProgName, (int)getpid())) + return; +#else /* All other platforms */ + /* + * TODO: SCO/UnixWare 7 must be something like (not tested) + * debug -i c <pid> <<EOF\nstack -f 4\nquit\nEOF\n + */ +# if !defined(__GNUC__) + if(backtrace_command(outb, "dbx %s %d 2>/dev/null <<EOF\n" + "where\n" + "detach\n" + "EOF\n", + globalProgName, (int)getpid())) + return; +# endif + if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" + "set prompt\n" + "where\n" +#if 0 + "echo ---\\n\n" + "frame 4\n" + "set \\$x = 50\n" + "while (\\$x)\n" + "info locals\n" + "up\n" + "set \\$x--\n" + "end\n" + "echo ---\\n\n" +#endif + "detach\n" + "quit\n" + "EOF\n", + globalProgName, (int)getpid())) + return; +#endif + const char debug_err[] = "No debugger found\n"; + fwrite(debug_err, strlen(debug_err), 1, outb); +} +/* end of copied code */ +#endif + + +void qt_signal_handler(int sig) +{ + signal(sig, SIG_DFL); + if(QSegfaultHandler::callback) { + (*QSegfaultHandler::callback)(); + _exit(1); + } + FILE *outb = stderr; + if(char *crash_loc = ::getenv("QT_CRASH_OUTPUT")) { + if(FILE *new_outb = fopen(crash_loc, "w")) { + fprintf(stderr, "Crash (backtrace written to %s)!!!\n", crash_loc); + outb = new_outb; + } + } else { + fprintf(outb, "Crash!!!\n"); + } + print_backtrace(outb); + if(outb != stderr) + fclose(outb); + _exit(1); +} + + +void +QSegfaultHandler::initialize(char **argv, int argc) +{ + init_backtrace(argv, argc); + + struct sigaction SignalAction; + SignalAction.sa_flags = 0; + SignalAction.sa_handler = qt_signal_handler; + sigemptyset(&SignalAction.sa_mask); + sigaction(SIGSEGV, &SignalAction, NULL); + sigaction(SIGBUS, &SignalAction, NULL); +} + +QT_END_NAMESPACE + +#endif // QT_NO_CRASHHANDLER diff --git a/src/corelib/kernel/qcrashhandler_p.h b/src/corelib/kernel/qcrashhandler_p.h new file mode 100644 index 0000000..d41e637 --- /dev/null +++ b/src/corelib/kernel/qcrashhandler_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCRASHHANDLER_P_H +#define QCRASHHANDLER_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. +// + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_CRASHHANDLER + +QT_BEGIN_NAMESPACE + +typedef void (*QtCrashHandler)(); + +class Q_CORE_EXPORT QSegfaultHandler +{ + friend void qt_signal_handler(int); + static QtCrashHandler callback; +public: + static void initialize(char **, int); + + inline static void installCrashHandler(QtCrashHandler h) { callback = h; } + inline static QtCrashHandler crashHandler() { return callback; } + +private: +}; + +QT_END_NAMESPACE + +#endif // QT_NO_CRASHHANDLER + +#endif // QCRASHHANDLER_P_H diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp new file mode 100644 index 0000000..20548de --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_glib.cpp @@ -0,0 +1,500 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeventdispatcher_glib_p.h" +#include "qeventdispatcher_unix_p.h" + +#include <private/qthread_p.h> + +#include "qcoreapplication.h" +#include "qsocketnotifier.h" + +#include <QtCore/qhash.h> +#include <QtCore/qlist.h> +#include <QtCore/qpair.h> + +#include <glib.h> + +QT_BEGIN_NAMESPACE + +struct GPollFDWithQSocketNotifier +{ + GPollFD pollfd; + QSocketNotifier *socketNotifier; +}; + +struct GSocketNotifierSource +{ + GSource source; + QList<GPollFDWithQSocketNotifier *> pollfds; +}; + +static gboolean socketNotifierSourcePrepare(GSource *, gint *timeout) +{ + if (timeout) + *timeout = -1; + return false; +} + +static gboolean socketNotifierSourceCheck(GSource *source) +{ + GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source); + + bool pending = false; + for (int i = 0; !pending && i < src->pollfds.count(); ++i) { + GPollFDWithQSocketNotifier *p = src->pollfds.at(i); + + if (p->pollfd.revents & G_IO_NVAL) { + // disable the invalid socket notifier + static const char *t[] = { "Read", "Write", "Exception" }; + qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...", + p->pollfd.fd, t[int(p->socketNotifier->type())]); + // ### note, modifies src->pollfds! + p->socketNotifier->setEnabled(false); + } + + pending = ((p->pollfd.revents & p->pollfd.events) != 0); + } + + return pending; +} + +static gboolean socketNotifierSourceDispatch(GSource *source, GSourceFunc, gpointer) +{ + QEvent event(QEvent::SockAct); + + GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source); + for (int i = 0; i < src->pollfds.count(); ++i) { + GPollFDWithQSocketNotifier *p = src->pollfds.at(i); + + if ((p->pollfd.revents & p->pollfd.events) != 0) + QCoreApplication::sendEvent(p->socketNotifier, &event); + } + + return true; // ??? don't remove, right? +} + +static GSourceFuncs socketNotifierSourceFuncs = { + socketNotifierSourcePrepare, + socketNotifierSourceCheck, + socketNotifierSourceDispatch, + NULL, + NULL, + NULL +}; + +struct GTimerSource +{ + GSource source; + QTimerInfoList timerList; + QEventLoop::ProcessEventsFlags processEventsFlags; +}; + +static gboolean timerSourcePrepare(GSource *source, gint *timeout) +{ + gint dummy; + if (!timeout) + timeout = &dummy; + + GTimerSource *src = reinterpret_cast<GTimerSource *>(source); + + timeval tv = { 0l, 0l }; + if (!(src->processEventsFlags & QEventLoop::X11ExcludeTimers) && src->timerList.timerWait(tv)) + *timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); + else + *timeout = -1; + + return (*timeout == 0); +} + +static gboolean timerSourceCheck(GSource *source) +{ + GTimerSource *src = reinterpret_cast<GTimerSource *>(source); + + if (src->timerList.isEmpty() + || (src->processEventsFlags & QEventLoop::X11ExcludeTimers)) + return false; + + if (src->timerList.updateCurrentTime() < src->timerList.first()->timeout) + return false; + + return true; +} + +static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer) +{ + (void) reinterpret_cast<GTimerSource *>(source)->timerList.activateTimers(); + return true; // ??? don't remove, right again? +} + +static GSourceFuncs timerSourceFuncs = { + timerSourcePrepare, + timerSourceCheck, + timerSourceDispatch, + NULL, + NULL, + NULL +}; + +struct GPostEventSource +{ + GSource source; + QAtomicInt serialNumber; + int lastSerialNumber; +}; + +static gboolean postEventSourcePrepare(GSource *s, gint *timeout) +{ + QThreadData *data = QThreadData::current(); + if (!data) + return false; + + gint dummy; + if (!timeout) + timeout = &dummy; + *timeout = data->canWait ? -1 : 0; + + GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s); + return (!data->canWait + || (source->serialNumber != source->lastSerialNumber)); +} + +static gboolean postEventSourceCheck(GSource *source) +{ + return postEventSourcePrepare(source, 0); +} + +static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer) +{ + GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s); + source->lastSerialNumber = source->serialNumber; + QCoreApplication::sendPostedEvents(); + return true; // i dunno, george... +} + +static GSourceFuncs postEventSourceFuncs = { + postEventSourcePrepare, + postEventSourceCheck, + postEventSourceDispatch, + NULL, + NULL, + NULL +}; + + +QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(GMainContext *context) + : mainContext(context) +{ + if (qgetenv("QT_NO_THREADED_GLIB").isEmpty()) { + if (!g_thread_supported()) + g_thread_init(NULL); + } + + if (mainContext) { + g_main_context_ref(mainContext); + } else { + QCoreApplication *app = QCoreApplication::instance(); + if (app && QThread::currentThread() == app->thread()) { + mainContext = g_main_context_default(); + g_main_context_ref(mainContext); + } else { + mainContext = g_main_context_new(); + } + } + + postEventSource = reinterpret_cast<GPostEventSource *>(g_source_new(&postEventSourceFuncs, + sizeof(GPostEventSource))); + g_source_set_can_recurse(&postEventSource->source, true); + g_source_attach(&postEventSource->source, mainContext); + + // setup socketNotifierSource + socketNotifierSource = + reinterpret_cast<GSocketNotifierSource *>(g_source_new(&socketNotifierSourceFuncs, + sizeof(GSocketNotifierSource))); + (void) new (&socketNotifierSource->pollfds) QList<GPollFDWithQSocketNotifier *>(); + g_source_set_can_recurse(&socketNotifierSource->source, true); + g_source_attach(&socketNotifierSource->source, mainContext); + + // setup timerSource + timerSource = reinterpret_cast<GTimerSource *>(g_source_new(&timerSourceFuncs, + sizeof(GTimerSource))); + (void) new (&timerSource->timerList) QTimerInfoList(); + timerSource->processEventsFlags = QEventLoop::AllEvents; + g_source_set_can_recurse(&timerSource->source, true); + g_source_attach(&timerSource->source, mainContext); +} + +QEventDispatcherGlib::QEventDispatcherGlib(QObject *parent) + : QAbstractEventDispatcher(*(new QEventDispatcherGlibPrivate), parent) +{ +} + +QEventDispatcherGlib::QEventDispatcherGlib(GMainContext *mainContext, + QObject *parent) + : QAbstractEventDispatcher(*(new QEventDispatcherGlibPrivate(mainContext)), + parent) +{ +} + +QEventDispatcherGlib::~QEventDispatcherGlib() +{ + Q_D(QEventDispatcherGlib); + + // destroy all timer sources + qDeleteAll(d->timerSource->timerList); + d->timerSource->timerList.~QTimerInfoList(); + g_source_destroy(&d->timerSource->source); + g_source_unref(&d->timerSource->source); + d->timerSource = 0; + + // destroy socket notifier source + for (int i = 0; i < d->socketNotifierSource->pollfds.count(); ++i) { + GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds[i]; + g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd); + delete p; + } + d->socketNotifierSource->pollfds.~QList<GPollFDWithQSocketNotifier *>(); + g_source_destroy(&d->socketNotifierSource->source); + g_source_unref(&d->socketNotifierSource->source); + d->socketNotifierSource = 0; + + // destroy post event source + g_source_destroy(&d->postEventSource->source); + g_source_unref(&d->postEventSource->source); + d->postEventSource = 0; + + Q_ASSERT(d->mainContext != 0); + g_main_context_unref(d->mainContext); + d->mainContext = 0; +} + +bool QEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + Q_D(QEventDispatcherGlib); + + const bool canWait = (flags & QEventLoop::WaitForMoreEvents); + if (canWait) + emit aboutToBlock(); + else + emit awake(); + + // tell postEventSourcePrepare() and timerSource about any new flags + QEventLoop::ProcessEventsFlags savedFlags = d->timerSource->processEventsFlags; + d->timerSource->processEventsFlags = flags; + + bool result = g_main_context_iteration(d->mainContext, canWait); + while (!result && canWait) + result = g_main_context_iteration(d->mainContext, canWait); + + d->timerSource->processEventsFlags = savedFlags; + + if (canWait) + emit awake(); + + return result; +} + +bool QEventDispatcherGlib::hasPendingEvents() +{ + Q_D(QEventDispatcherGlib); + return g_main_context_pending(d->mainContext); +} + +void QEventDispatcherGlib::registerSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int sockfd = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (sockfd < 0) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != thread() + || thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); + return; + } +#endif + + Q_D(QEventDispatcherGlib); + + + GPollFDWithQSocketNotifier *p = new GPollFDWithQSocketNotifier; + p->pollfd.fd = sockfd; + switch (type) { + case QSocketNotifier::Read: + p->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR; + break; + case QSocketNotifier::Write: + p->pollfd.events = G_IO_OUT | G_IO_ERR; + break; + case QSocketNotifier::Exception: + p->pollfd.events = G_IO_PRI | G_IO_ERR; + break; + } + p->socketNotifier = notifier; + + d->socketNotifierSource->pollfds.append(p); + + g_source_add_poll(&d->socketNotifierSource->source, &p->pollfd); +} + +void QEventDispatcherGlib::unregisterSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); +#ifndef QT_NO_DEBUG + int sockfd = notifier->socket(); + if (sockfd < 0) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != thread() + || thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); + return; + } +#endif + + Q_D(QEventDispatcherGlib); + + for (int i = 0; i < d->socketNotifierSource->pollfds.count(); ++i) { + GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds.at(i); + if (p->socketNotifier == notifier) { + // found it + g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd); + + d->socketNotifierSource->pollfds.removeAt(i); + delete p; + + return; + } + } +} + +void QEventDispatcherGlib::registerTimer(int timerId, int interval, QObject *object) +{ +#ifndef QT_NO_DEBUG + if (timerId < 1 || interval < 0 || !object) { + qWarning("QEventDispatcherUNIX::registerTimer: invalid arguments"); + return; + } else if (object->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QObject::startTimer: timers cannot be started from another thread"); + return; + } +#endif + + Q_D(QEventDispatcherGlib); + d->timerSource->timerList.registerTimer(timerId, interval, object); +} + +bool QEventDispatcherGlib::unregisterTimer(int timerId) +{ +#ifndef QT_NO_DEBUG + if (timerId < 1) { + qWarning("QEventDispatcherUNIX::unregisterTimer: invalid argument"); + return false; + } else if (thread() != QThread::currentThread()) { + qWarning("QObject::killTimer: timers cannot be stopped from another thread"); + return false; + } +#endif + + Q_D(QEventDispatcherGlib); + return d->timerSource->timerList.unregisterTimer(timerId); +} + +bool QEventDispatcherGlib::unregisterTimers(QObject *object) +{ +#ifndef QT_NO_DEBUG + if (!object) { + qWarning("QEventDispatcherUNIX::unregisterTimers: invalid argument"); + return false; + } else if (object->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QObject::killTimers: timers cannot be stopped from another thread"); + return false; + } +#endif + + Q_D(QEventDispatcherGlib); + return d->timerSource->timerList.unregisterTimers(object); +} + +QList<QEventDispatcherGlib::TimerInfo> QEventDispatcherGlib::registeredTimers(QObject *object) const +{ + if (!object) { + qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument"); + return QList<TimerInfo>(); + } + + Q_D(const QEventDispatcherGlib); + return d->timerSource->timerList.registeredTimers(object); +} + +void QEventDispatcherGlib::interrupt() +{ + wakeUp(); +} + +void QEventDispatcherGlib::wakeUp() +{ + Q_D(QEventDispatcherGlib); + d->postEventSource->serialNumber.ref(); + g_main_context_wakeup(d->mainContext); +} + +void QEventDispatcherGlib::flush() +{ +} + +bool QEventDispatcherGlib::versionSupported() +{ +#if !defined(GLIB_MAJOR_VERSION) || !defined(GLIB_MINOR_VERSION) || !defined(GLIB_MICRO_VERSION) + return false; +#else + return ((GLIB_MAJOR_VERSION << 16) + (GLIB_MINOR_VERSION << 8) + GLIB_MICRO_VERSION) >= 0x020301; +#endif +} + +QEventDispatcherGlib::QEventDispatcherGlib(QEventDispatcherGlibPrivate &dd, QObject *parent) + : QAbstractEventDispatcher(dd, parent) +{ +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_glib_p.h b/src/corelib/kernel/qeventdispatcher_glib_p.h new file mode 100644 index 0000000..a2e6c3b --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_glib_p.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVENTDISPATCHER_GLIB_P_H +#define QEVENTDISPATCHER_GLIB_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qabstracteventdispatcher.h" +#include "qabstracteventdispatcher_p.h" + +#include <QtCore/qhash.h> + +typedef struct _GMainContext GMainContext; + +QT_BEGIN_NAMESPACE + +class QEventDispatcherGlibPrivate; + +class Q_CORE_EXPORT QEventDispatcherGlib : public QAbstractEventDispatcher +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QEventDispatcherGlib) + +public: + explicit QEventDispatcherGlib(QObject *parent = 0); + explicit QEventDispatcherGlib(GMainContext *context, QObject *parent = 0); + ~QEventDispatcherGlib(); + + bool processEvents(QEventLoop::ProcessEventsFlags flags); + bool hasPendingEvents(); + + void registerSocketNotifier(QSocketNotifier *socketNotifier); + void unregisterSocketNotifier(QSocketNotifier *socketNotifier); + + void registerTimer(int timerId, int interval, QObject *object); + bool unregisterTimer(int timerId); + bool unregisterTimers(QObject *object); + QList<TimerInfo> registeredTimers(QObject *object) const; + + void wakeUp(); + void interrupt(); + void flush(); + + static bool versionSupported(); + +protected: + QEventDispatcherGlib(QEventDispatcherGlibPrivate &dd, QObject *parent); +}; + +struct GPostEventSource; +struct GSocketNotifierSource; +struct GTimerSource; + +class Q_CORE_EXPORT QEventDispatcherGlibPrivate : public QAbstractEventDispatcherPrivate +{ + +public: + QEventDispatcherGlibPrivate(GMainContext *context = 0); + GMainContext *mainContext; + GPostEventSource *postEventSource; + GSocketNotifierSource *socketNotifierSource; + GTimerSource *timerSource; +}; + +QT_END_NAMESPACE + +#endif // QEVENTDISPATCHER_GLIB_P_H diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp new file mode 100644 index 0000000..6aa3b56 --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -0,0 +1,957 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" + +#include "qcoreapplication.h" +#include "qpair.h" +#include "qsocketnotifier.h" +#include "qthread.h" + +#include "qeventdispatcher_unix_p.h" +#include <private/qthread_p.h> +#include <private/qcoreapplication_p.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED) +# include <sys/times.h> +#endif + +QT_BEGIN_NAMESPACE + +Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false; + +/***************************************************************************** + UNIX signal handling + *****************************************************************************/ + +static sig_atomic_t signal_received; +static sig_atomic_t signals_fired[NSIG]; + +static void signalHandler(int sig) +{ + signals_fired[sig] = 1; + signal_received = 1; +} + + +static void initThreadPipeFD(int fd) +{ + int ret = fcntl(fd, F_SETFD, FD_CLOEXEC); + if (ret == -1) + perror("QEventDispatcherUNIXPrivate: Unable to init thread pipe"); + + int flags = fcntl(fd, F_GETFL); + if (flags == -1) + perror("QEventDispatcherUNIXPrivate: Unable to get flags on thread pipe"); + + ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if (ret == -1) + perror("QEventDispatcherUNIXPrivate: Unable to set flags on thread pipe"); +} + + +QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate() +{ + extern Qt::HANDLE qt_application_thread_id; + mainThread = (QThread::currentThreadId() == qt_application_thread_id); + + // initialize the common parts of the event loop +#ifdef Q_OS_INTEGRITY + // INTEGRITY doesn't like a "select" on pipes, so use socketpair instead + if (socketpair(AF_INET, SOCK_STREAM, PF_INET, thread_pipe) == -1) + perror("QEventDispatcherUNIXPrivate(): Unable to create socket pair"); +#else + if (pipe(thread_pipe) == -1) + perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe"); +#endif + + initThreadPipeFD(thread_pipe[0]); + initThreadPipeFD(thread_pipe[1]); + + sn_highest = -1; + + interrupt = false; +} + +QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate() +{ + // cleanup the common parts of the event loop + close(thread_pipe[0]); + close(thread_pipe[1]); + + // cleanup timers + qDeleteAll(timerList); +} + +int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, timeval *timeout) +{ + Q_Q(QEventDispatcherUNIX); + + // needed in QEventDispatcherUNIX::select() + timerList.updateCurrentTime(); + + int nsel; + do { + if (mainThread) { + while (signal_received) { + signal_received = 0; + for (int i = 0; i < NSIG; ++i) { + if (signals_fired[i]) { + signals_fired[i] = 0; + emit QCoreApplication::instance()->unixSignal(i); + } + } + } + } + + // Process timers and socket notifiers - the common UNIX stuff + int highest = 0; + if (! (flags & QEventLoop::ExcludeSocketNotifiers) && (sn_highest >= 0)) { + // return the highest fd we can wait for input on + sn_vec[0].select_fds = sn_vec[0].enabled_fds; + sn_vec[1].select_fds = sn_vec[1].enabled_fds; + sn_vec[2].select_fds = sn_vec[2].enabled_fds; + highest = sn_highest; + } else { + FD_ZERO(&sn_vec[0].select_fds); + FD_ZERO(&sn_vec[1].select_fds); + FD_ZERO(&sn_vec[2].select_fds); + } + + FD_SET(thread_pipe[0], &sn_vec[0].select_fds); + highest = qMax(highest, thread_pipe[0]); + + nsel = q->select(highest + 1, + &sn_vec[0].select_fds, + &sn_vec[1].select_fds, + &sn_vec[2].select_fds, + timeout); + } while (nsel == -1 && (errno == EINTR || errno == EAGAIN)); + + if (nsel == -1) { + if (errno == EBADF) { + // it seems a socket notifier has a bad fd... find out + // which one it is and disable it + fd_set fdset; + timeval tm; + tm.tv_sec = tm.tv_usec = 0l; + + for (int type = 0; type < 3; ++type) { + QSockNotType::List &list = sn_vec[type].list; + if (list.size() == 0) + continue; + + for (int i = 0; i < list.size(); ++i) { + QSockNot *sn = list.at(i); + + FD_ZERO(&fdset); + FD_SET(sn->fd, &fdset); + + int ret = -1; + do { + switch (type) { + case 0: // read + ret = select(sn->fd + 1, &fdset, 0, 0, &tm); + break; + case 1: // write + ret = select(sn->fd + 1, 0, &fdset, 0, &tm); + break; + case 2: // except + ret = select(sn->fd + 1, 0, 0, &fdset, &tm); + break; + } + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + + if (ret == -1 && errno == EBADF) { + // disable the invalid socket notifier + static const char *t[] = { "Read", "Write", "Exception" }; + qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...", + sn->fd, t[type]); + sn->obj->setEnabled(false); + } + } + } + } else { + // EINVAL... shouldn't happen, so let's complain to stderr + // and hope someone sends us a bug report + perror("select"); + } + } + + // some other thread woke us up... consume the data on the thread pipe so that + // select doesn't immediately return next time + int nevents = 0; + if (nsel > 0 && FD_ISSET(thread_pipe[0], &sn_vec[0].select_fds)) { + char c[16]; + while (::read(thread_pipe[0], c, sizeof(c)) > 0) + ; + if (!wakeUps.testAndSetRelease(1, 0)) { + // hopefully, this is dead code + qWarning("QEventDispatcherUNIX: internal error, wakeUps.testAndSetRelease(1, 0) failed!"); + } + ++nevents; + } + + // activate socket notifiers + if (! (flags & QEventLoop::ExcludeSocketNotifiers) && nsel > 0 && sn_highest >= 0) { + // if select says data is ready on any socket, then set the socket notifier + // to pending + for (int i=0; i<3; i++) { + QSockNotType::List &list = sn_vec[i].list; + for (int j = 0; j < list.size(); ++j) { + QSockNot *sn = list.at(j); + if (FD_ISSET(sn->fd, &sn_vec[i].select_fds)) + q->setSocketNotifierPending(sn->obj); + } + } + } + return (nevents + q->activateSocketNotifiers()); +} + +/* + * Internal functions for manipulating timer data structures. The + * timerBitVec array is used for keeping track of timer identifiers. + */ + +QTimerInfoList::QTimerInfoList() +{ +#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) + useMonotonicTimers = false; + +# if (_POSIX_MONOTONIC_CLOCK == 0) + // detect if the system support monotonic timers + long x = sysconf(_SC_MONOTONIC_CLOCK); + useMonotonicTimers = x >= 200112L; +# endif + + getTime(currentTime); + + if (!useMonotonicTimers) { + // not using monotonic timers, initialize the timeChanged() machinery + previousTime = currentTime; + + tms unused; + previousTicks = times(&unused); + + ticksPerSecond = sysconf(_SC_CLK_TCK); + msPerTick = 1000/ticksPerSecond; + } else { + // detected monotonic timers + previousTime.tv_sec = previousTime.tv_usec = 0; + previousTicks = 0; + ticksPerSecond = 0; + msPerTick = 0; + } +#else + // using monotonic timers unconditionally + getTime(currentTime); +#endif + + firstTimerInfo = currentTimerInfo = 0; +} + +timeval QTimerInfoList::updateCurrentTime() +{ + getTime(currentTime); + return currentTime; +} + +#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED) + +/* + Returns true if the real time clock has changed by more than 10% + relative to the processor time since the last time this function was + called. This presumably means that the system time has been changed. + + If /a delta is nonzero, delta is set to our best guess at how much the system clock was changed. +*/ +bool QTimerInfoList::timeChanged(timeval *delta) +{ + tms unused; + clock_t currentTicks = times(&unused); + + int elapsedTicks = currentTicks - previousTicks; + timeval elapsedTime = currentTime - previousTime; + int elapsedMsecTicks = (elapsedTicks * 1000) / ticksPerSecond; + int deltaMsecs = (elapsedTime.tv_sec * 1000 + elapsedTime.tv_usec / 1000) + - elapsedMsecTicks; + + if (delta) { + delta->tv_sec = deltaMsecs / 1000; + delta->tv_usec = (deltaMsecs % 1000) * 1000; + } + previousTicks = currentTicks; + previousTime = currentTime; + + // If tick drift is more than 10% off compared to realtime, we assume that the clock has + // been set. Of course, we have to allow for the tick granularity as well. + + return (qAbs(deltaMsecs) - msPerTick) * 10 > elapsedMsecTicks; +} + +void QTimerInfoList::getTime(timeval &t) +{ +#if !defined(QT_NO_CLOCK_MONOTONIC) && !defined(QT_BOOTSTRAPPED) + if (useMonotonicTimers) { + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + t.tv_sec = ts.tv_sec; + t.tv_usec = ts.tv_nsec / 1000; + return; + } +#endif + + gettimeofday(&t, 0); + // NTP-related fix + while (t.tv_usec >= 1000000l) { + t.tv_usec -= 1000000l; + ++t.tv_sec; + } + while (t.tv_usec < 0l) { + if (t.tv_sec > 0l) { + t.tv_usec += 1000000l; + --t.tv_sec; + } else { + t.tv_usec = 0l; + break; + } + } +} + +void QTimerInfoList::repairTimersIfNeeded() +{ + if (useMonotonicTimers) + return; + timeval delta; + if (timeChanged(&delta)) + timerRepair(delta); +} + +#else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED) + +void QTimerInfoList::getTime(timeval &t) +{ + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + t.tv_sec = ts.tv_sec; + t.tv_usec = ts.tv_nsec / 1000; +} + +void QTimerInfoList::repairTimersIfNeeded() +{ +} + +#endif + +/* + insert timer info into list +*/ +void QTimerInfoList::timerInsert(QTimerInfo *ti) +{ + int index = size(); + while (index--) { + register const QTimerInfo * const t = at(index); + if (!(ti->timeout < t->timeout)) + break; + } + insert(index+1, ti); +} + +/* + repair broken timer +*/ +void QTimerInfoList::timerRepair(const timeval &diff) +{ + // repair all timers + for (int i = 0; i < size(); ++i) { + register QTimerInfo *t = at(i); + t->timeout = t->timeout - diff; + } +} + +/* + Returns the time to wait for the next timer, or null if no timers + are waiting. +*/ +bool QTimerInfoList::timerWait(timeval &tm) +{ + timeval currentTime = updateCurrentTime(); + repairTimersIfNeeded(); + + if (isEmpty()) + return false; + + QTimerInfo *t = first(); // first waiting timer + if (currentTime < t->timeout) { + // time to wait + tm = t->timeout - currentTime; + } else { + // no time to wait + tm.tv_sec = 0; + tm.tv_usec = 0; + } + + return true; +} + +void QTimerInfoList::registerTimer(int timerId, int interval, QObject *object) +{ + QTimerInfo *t = new QTimerInfo; + t->id = timerId; + t->interval.tv_sec = interval / 1000; + t->interval.tv_usec = (interval % 1000) * 1000; + t->timeout = updateCurrentTime() + t->interval; + t->obj = object; + t->inTimerEvent = false; + + timerInsert(t); +} + +bool QTimerInfoList::unregisterTimer(int timerId) +{ + // set timer inactive + for (int i = 0; i < count(); ++i) { + register QTimerInfo *t = at(i); + if (t->id == timerId) { + // found it + removeAt(i); + if (t == firstTimerInfo) + firstTimerInfo = 0; + if (t == currentTimerInfo) + currentTimerInfo = 0; + + // release the timer id + if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) + QAbstractEventDispatcherPrivate::releaseTimerId(timerId); + + delete t; + return true; + } + } + // id not found + return false; +} + +bool QTimerInfoList::unregisterTimers(QObject *object) +{ + if (isEmpty()) + return false; + for (int i = 0; i < count(); ++i) { + register QTimerInfo *t = at(i); + if (t->obj == object) { + // object found + removeAt(i); + if (t == firstTimerInfo) + firstTimerInfo = 0; + if (t == currentTimerInfo) + currentTimerInfo = 0; + + // release the timer id + if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) + QAbstractEventDispatcherPrivate::releaseTimerId(t->id); + + delete t; + // move back one so that we don't skip the new current item + --i; + } + } + return true; +} + +QList<QPair<int, int> > QTimerInfoList::registeredTimers(QObject *object) const +{ + QList<QPair<int, int> > list; + for (int i = 0; i < count(); ++i) { + register const QTimerInfo * const t = at(i); + if (t->obj == object) + list << QPair<int, int>(t->id, t->interval.tv_sec * 1000 + t->interval.tv_usec / 1000); + } + return list; +} + +/* + Activate pending timers, returning how many where activated. +*/ +int QTimerInfoList::activateTimers() +{ + if (qt_disable_lowpriority_timers || isEmpty()) + return 0; // nothing to do + + bool firstTime = true; + timeval currentTime; + int n_act = 0, maxCount = count(); + + QTimerInfo *saveFirstTimerInfo = firstTimerInfo; + QTimerInfo *saveCurrentTimerInfo = currentTimerInfo; + firstTimerInfo = currentTimerInfo = 0; + + while (maxCount--) { + currentTime = updateCurrentTime(); + if (firstTime) { + repairTimersIfNeeded(); + firstTime = false; + } + + if (isEmpty()) + break; + + currentTimerInfo = first(); + if (currentTime < currentTimerInfo->timeout) + break; // no timer has expired + + if (!firstTimerInfo) { + firstTimerInfo = currentTimerInfo; + } else if (firstTimerInfo == currentTimerInfo) { + // avoid sending the same timer multiple times + break; + } else if (currentTimerInfo->interval < firstTimerInfo->interval + || currentTimerInfo->interval == firstTimerInfo->interval) { + firstTimerInfo = currentTimerInfo; + } + + // remove from list + removeFirst(); + + // determine next timeout time + currentTimerInfo->timeout += currentTimerInfo->interval; + if (currentTimerInfo->timeout < currentTime) + currentTimerInfo->timeout = currentTime + currentTimerInfo->interval; + + // reinsert timer + timerInsert(currentTimerInfo); + if (currentTimerInfo->interval.tv_usec > 0 || currentTimerInfo->interval.tv_sec > 0) + n_act++; + + if (!currentTimerInfo->inTimerEvent) { + // send event, but don't allow it to recurse + currentTimerInfo->inTimerEvent = true; + + QTimerEvent e(currentTimerInfo->id); + QCoreApplication::sendEvent(currentTimerInfo->obj, &e); + + if (currentTimerInfo) + currentTimerInfo->inTimerEvent = false; + } + } + + firstTimerInfo = saveFirstTimerInfo; + currentTimerInfo = saveCurrentTimerInfo; + + return n_act; +} + +QEventDispatcherUNIX::QEventDispatcherUNIX(QObject *parent) + : QAbstractEventDispatcher(*new QEventDispatcherUNIXPrivate, parent) +{ } + +QEventDispatcherUNIX::QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObject *parent) + : QAbstractEventDispatcher(dd, parent) +{ } + +QEventDispatcherUNIX::~QEventDispatcherUNIX() +{ } + +int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + timeval *timeout) +{ + Q_D(QEventDispatcherUNIX); + if (timeout) { + // handle the case where select returns with a timeout, too + // soon. + timeval tvStart = d->timerList.currentTime; + timeval tvCurrent = tvStart; + timeval originalTimeout = *timeout; + + int nsel; + do { + timeval tvRest = originalTimeout + tvStart - tvCurrent; + nsel = ::select(nfds, readfds, writefds, exceptfds, &tvRest); + d->timerList.getTime(tvCurrent); + } while (nsel == 0 && (tvCurrent - tvStart) < originalTimeout); + + return nsel; + } + + return ::select(nfds, readfds, writefds, exceptfds, timeout); +} + +/*! + \internal +*/ +void QEventDispatcherUNIX::registerTimer(int timerId, int interval, QObject *obj) +{ +#ifndef QT_NO_DEBUG + if (timerId < 1 || interval < 0 || !obj) { + qWarning("QEventDispatcherUNIX::registerTimer: invalid arguments"); + return; + } else if (obj->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QObject::startTimer: timers cannot be started from another thread"); + return; + } +#endif + + Q_D(QEventDispatcherUNIX); + d->timerList.registerTimer(timerId, interval, obj); +} + +/*! + \internal +*/ +bool QEventDispatcherUNIX::unregisterTimer(int timerId) +{ +#ifndef QT_NO_DEBUG + if (timerId < 1) { + qWarning("QEventDispatcherUNIX::unregisterTimer: invalid argument"); + return false; + } else if (thread() != QThread::currentThread()) { + qWarning("QObject::killTimer: timers cannot be stopped from another thread"); + return false; + } +#endif + + Q_D(QEventDispatcherUNIX); + return d->timerList.unregisterTimer(timerId); +} + +/*! + \internal +*/ +bool QEventDispatcherUNIX::unregisterTimers(QObject *object) +{ +#ifndef QT_NO_DEBUG + if (!object) { + qWarning("QEventDispatcherUNIX::unregisterTimers: invalid argument"); + return false; + } else if (object->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QObject::killTimers: timers cannot be stopped from another thread"); + return false; + } +#endif + + Q_D(QEventDispatcherUNIX); + return d->timerList.unregisterTimers(object); +} + +QList<QEventDispatcherUNIX::TimerInfo> +QEventDispatcherUNIX::registeredTimers(QObject *object) const +{ + if (!object) { + qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument"); + return QList<TimerInfo>(); + } + + Q_D(const QEventDispatcherUNIX); + return d->timerList.registeredTimers(object); +} + +/***************************************************************************** + Socket notifier type + *****************************************************************************/ +QSockNotType::QSockNotType() +{ + FD_ZERO(&select_fds); + FD_ZERO(&enabled_fds); + FD_ZERO(&pending_fds); +} + +QSockNotType::~QSockNotType() +{ + while (!list.isEmpty()) + delete list.takeFirst(); +} + +/***************************************************************************** + QEventDispatcher implementations for UNIX + *****************************************************************************/ + +void QEventDispatcherUNIX::registerSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int sockfd = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (sockfd < 0 + || unsigned(sockfd) >= FD_SETSIZE) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != thread() + || thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); + return; + } +#endif + + Q_D(QEventDispatcherUNIX); + QSockNotType::List &list = d->sn_vec[type].list; + fd_set *fds = &d->sn_vec[type].enabled_fds; + QSockNot *sn; + + sn = new QSockNot; + sn->obj = notifier; + sn->fd = sockfd; + sn->queue = &d->sn_vec[type].pending_fds; + + int i; + for (i = 0; i < list.size(); ++i) { + QSockNot *p = list.at(i); + if (p->fd < sockfd) + break; + if (p->fd == sockfd) { + static const char *t[] = { "Read", "Write", "Exception" }; + qWarning("QSocketNotifier: Multiple socket notifiers for " + "same socket %d and type %s", sockfd, t[type]); + } + } + list.insert(i, sn); + + FD_SET(sockfd, fds); + d->sn_highest = qMax(d->sn_highest, sockfd); +} + +void QEventDispatcherUNIX::unregisterSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int sockfd = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (sockfd < 0 + || unsigned(sockfd) >= FD_SETSIZE) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != thread() + || thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); + return; + } +#endif + + Q_D(QEventDispatcherUNIX); + QSockNotType::List &list = d->sn_vec[type].list; + fd_set *fds = &d->sn_vec[type].enabled_fds; + QSockNot *sn = 0; + int i; + for (i = 0; i < list.size(); ++i) { + sn = list.at(i); + if(sn->obj == notifier && sn->fd == sockfd) + break; + } + if (i == list.size()) // not found + return; + + FD_CLR(sockfd, fds); // clear fd bit + FD_CLR(sockfd, sn->queue); + d->sn_pending_list.removeAll(sn); // remove from activation list + list.removeAt(i); // remove notifier found above + delete sn; + + if (d->sn_highest == sockfd) { // find highest fd + d->sn_highest = -1; + for (int i=0; i<3; i++) { + if (!d->sn_vec[i].list.isEmpty()) + d->sn_highest = qMax(d->sn_highest, // list is fd-sorted + d->sn_vec[i].list.first()->fd); + } + } +} + +void QEventDispatcherUNIX::setSocketNotifierPending(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int sockfd = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (sockfd < 0 + || unsigned(sockfd) >= FD_SETSIZE) { + qWarning("QSocketNotifier: Internal error"); + return; + } + Q_ASSERT(notifier->thread() == thread() && thread() == QThread::currentThread()); +#endif + + Q_D(QEventDispatcherUNIX); + QSockNotType::List &list = d->sn_vec[type].list; + QSockNot *sn = 0; + int i; + for (i = 0; i < list.size(); ++i) { + sn = list.at(i); + if(sn->obj == notifier && sn->fd == sockfd) + break; + } + if (i == list.size()) // not found + return; + + // We choose a random activation order to be more fair under high load. + // If a constant order is used and a peer early in the list can + // saturate the IO, it might grab our attention completely. + // Also, if we're using a straight list, the callback routines may + // delete other entries from the list before those other entries are + // processed. + if (! FD_ISSET(sn->fd, sn->queue)) { + if (d->sn_pending_list.isEmpty()) { + d->sn_pending_list.append(sn); + } else { + d->sn_pending_list.insert((qrand() & 0xff) % + (d->sn_pending_list.size()+1), sn); + } + FD_SET(sn->fd, sn->queue); + } +} + +int QEventDispatcherUNIX::activateTimers() +{ + Q_ASSERT(thread() == QThread::currentThread()); + Q_D(QEventDispatcherUNIX); + return d->timerList.activateTimers(); +} + +int QEventDispatcherUNIX::activateSocketNotifiers() +{ + Q_D(QEventDispatcherUNIX); + if (d->sn_pending_list.isEmpty()) + return 0; + + // activate entries + int n_act = 0; + QEvent event(QEvent::SockAct); + while (!d->sn_pending_list.isEmpty()) { + QSockNot *sn = d->sn_pending_list.takeFirst(); + if (FD_ISSET(sn->fd, sn->queue)) { + FD_CLR(sn->fd, sn->queue); + QCoreApplication::sendEvent(sn->obj, &event); + ++n_act; + } + } + return n_act; +} + +bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + Q_D(QEventDispatcherUNIX); + d->interrupt = false; + + // we are awake, broadcast it + emit awake(); + QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); + + int nevents = 0; + const bool canWait = (d->threadData->canWait + && !d->interrupt + && (flags & QEventLoop::WaitForMoreEvents)); + + if (canWait) + emit aboutToBlock(); + + if (!d->interrupt) { + // return the maximum time we can wait for an event. + timeval *tm = 0; + timeval wait_tm = { 0l, 0l }; + if (!(flags & QEventLoop::X11ExcludeTimers)) { + if (d->timerList.timerWait(wait_tm)) + tm = &wait_tm; + } + + if (!canWait) { + if (!tm) + tm = &wait_tm; + + // no time to wait + tm->tv_sec = 0l; + tm->tv_usec = 0l; + } + + nevents = d->doSelect(flags, tm); + + // activate timers + if (! (flags & QEventLoop::X11ExcludeTimers)) { + nevents += activateTimers(); + } + } + // return true if we handled events, false otherwise + return (nevents > 0); +} + +bool QEventDispatcherUNIX::hasPendingEvents() +{ + extern uint qGlobalPostedEventsCount(); // from qapplication.cpp + return qGlobalPostedEventsCount(); +} + +void QEventDispatcherUNIX::wakeUp() +{ + Q_D(QEventDispatcherUNIX); + if (d->wakeUps.testAndSetAcquire(0, 1)) { + char c = 0; + ::write( d->thread_pipe[1], &c, 1 ); + } +} + +void QEventDispatcherUNIX::interrupt() +{ + Q_D(QEventDispatcherUNIX); + d->interrupt = true; + wakeUp(); +} + +void QEventDispatcherUNIX::flush() +{ } + + + + +void QCoreApplication::watchUnixSignal(int sig, bool watch) +{ + if (sig < NSIG) { + struct sigaction sa; + sigemptyset(&(sa.sa_mask)); + sa.sa_flags = 0; + if (watch) + sa.sa_handler = signalHandler; + else + sa.sa_handler = SIG_DFL; + sigaction(sig, &sa, 0); + } +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h new file mode 100644 index 0000000..41329cf --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVENTDISPATCHER_UNIX_P_H +#define QEVENTDISPATCHER_UNIX_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. +// + +#include "QtCore/qabstracteventdispatcher.h" +#include "QtCore/qlist.h" +#include "private/qabstracteventdispatcher_p.h" +#include "private/qpodlist_p.h" + +#include <sys/types.h> +#include <sys/time.h> +#if !defined(Q_OS_HPUX) || defined(__ia64) +#include <sys/select.h> +#endif +#include <unistd.h> + +QT_BEGIN_NAMESPACE +#if !defined(_POSIX_MONOTONIC_CLOCK) +# define _POSIX_MONOTONIC_CLOCK -1 +#endif + +// Internal operator functions for timevals +inline bool operator<(const timeval &t1, const timeval &t2) +{ return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec); } +inline bool operator==(const timeval &t1, const timeval &t2) +{ return t1.tv_sec == t2.tv_sec && t1.tv_usec == t2.tv_usec; } +inline timeval &operator+=(timeval &t1, const timeval &t2) +{ + t1.tv_sec += t2.tv_sec; + if ((t1.tv_usec += t2.tv_usec) >= 1000000l) { + ++t1.tv_sec; + t1.tv_usec -= 1000000l; + } + return t1; +} +inline timeval operator+(const timeval &t1, const timeval &t2) +{ + timeval tmp; + tmp.tv_sec = t1.tv_sec + t2.tv_sec; + if ((tmp.tv_usec = t1.tv_usec + t2.tv_usec) >= 1000000l) { + ++tmp.tv_sec; + tmp.tv_usec -= 1000000l; + } + return tmp; +} +inline timeval operator-(const timeval &t1, const timeval &t2) +{ + timeval tmp; + tmp.tv_sec = t1.tv_sec - t2.tv_sec; + if ((tmp.tv_usec = t1.tv_usec - t2.tv_usec) < 0l) { + --tmp.tv_sec; + tmp.tv_usec += 1000000l; + } + return tmp; +} + +// internal timer info +struct QTimerInfo { + int id; // - timer identifier + timeval interval; // - timer interval + timeval timeout; // - when to sent event + QObject *obj; // - object to receive event + bool inTimerEvent; +}; + +class QTimerInfoList : public QList<QTimerInfo*> +{ +#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED) + bool useMonotonicTimers; + + timeval previousTime; + clock_t previousTicks; + int ticksPerSecond; + int msPerTick; + + bool timeChanged(timeval *delta); +#endif + + // state variables used by activateTimers() + QTimerInfo *firstTimerInfo, *currentTimerInfo; + +public: + QTimerInfoList(); + + void getTime(timeval &t); + + timeval currentTime; + timeval updateCurrentTime(); + + // must call updateCurrentTime() first! + void repairTimersIfNeeded(); + + bool timerWait(timeval &); + void timerInsert(QTimerInfo *); + void timerRepair(const timeval &); + + void registerTimer(int timerId, int interval, QObject *object); + bool unregisterTimer(int timerId); + bool unregisterTimers(QObject *object); + QList<QPair<int, int> > registeredTimers(QObject *object) const; + + int activateTimers(); +}; + +struct Q_CORE_EXPORT QSockNot +{ + QSocketNotifier *obj; + int fd; + fd_set *queue; +}; + +class Q_CORE_EXPORT QSockNotType +{ +public: + QSockNotType(); + ~QSockNotType(); + + typedef QPodList<QSockNot*, 32> List; + + List list; + fd_set select_fds; + fd_set enabled_fds; + fd_set pending_fds; + +}; + +class QEventDispatcherUNIXPrivate; + +class Q_CORE_EXPORT QEventDispatcherUNIX : public QAbstractEventDispatcher +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QEventDispatcherUNIX) + +public: + explicit QEventDispatcherUNIX(QObject *parent = 0); + ~QEventDispatcherUNIX(); + + bool processEvents(QEventLoop::ProcessEventsFlags flags); + bool hasPendingEvents(); + + void registerSocketNotifier(QSocketNotifier *notifier); + void unregisterSocketNotifier(QSocketNotifier *notifier); + + void registerTimer(int timerId, int interval, QObject *object); + bool unregisterTimer(int timerId); + bool unregisterTimers(QObject *object); + QList<TimerInfo> registeredTimers(QObject *object) const; + + void wakeUp(); + void interrupt(); + void flush(); + +protected: + QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObject *parent = 0); + + void setSocketNotifierPending(QSocketNotifier *notifier); + + int activateTimers(); + int activateSocketNotifiers(); + + virtual int select(int nfds, + fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + timeval *timeout); +}; + +class Q_CORE_EXPORT QEventDispatcherUNIXPrivate : public QAbstractEventDispatcherPrivate +{ + Q_DECLARE_PUBLIC(QEventDispatcherUNIX) + +public: + QEventDispatcherUNIXPrivate(); + ~QEventDispatcherUNIXPrivate(); + + int doSelect(QEventLoop::ProcessEventsFlags flags, timeval *timeout); + + bool mainThread; + int thread_pipe[2]; + + // highest fd for all socket notifiers + int sn_highest; + // 3 socket notifier types - read, write and exception + QSockNotType sn_vec[3]; + + QTimerInfoList timerList; + + // pending socket notifiers list + QSockNotType::List sn_pending_list; + + QAtomicInt wakeUps; + bool interrupt; +}; + +QT_END_NAMESPACE + +#endif // QEVENTDISPATCHER_UNIX_P_H diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp new file mode 100644 index 0000000..880e95c --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -0,0 +1,1076 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeventdispatcher_win_p.h" + +#include "qcoreapplication.h" +#include "qhash.h" +#include "qlibrary.h" +#include "qpair.h" +#include "qset.h" +#include "qsocketnotifier.h" +#include "qvarlengtharray.h" +#include "qwineventnotifier_p.h" + +#include "qabstracteventdispatcher_p.h" +#include "qcoreapplication_p.h" +#include <private/qthread_p.h> +#include <private/qmutexpool_p.h> + +QT_BEGIN_NAMESPACE + +HINSTANCE qWinAppInst(); +extern uint qGlobalPostedEventsCount(); + +#ifndef TIME_KILL_SYNCHRONOUS +# define TIME_KILL_SYNCHRONOUS 0x0100 +#endif + +#if defined(Q_OS_WINCE) +QT_BEGIN_INCLUDE_NAMESPACE +#include <winsock.h> +// Asynchronous Winsocks ------------------------------------------ +#ifndef QT_NO_THREAD +#include <qthread.h> +#include <qmap.h> +#include <qmutex.h> +QT_END_INCLUDE_NAMESPACE + +//#define QCE_ASYNC_DEBUG + +namespace { + class SocketAsyncHandler; + + class SocketAsyncHandler : public QThread + { + public: + SocketAsyncHandler(); + ~SocketAsyncHandler(); + void run(); + void select(SOCKET sock, HWND handle, unsigned int msg, long ev); + void removeSelect(SOCKET sock); + void safeRemove(SOCKET sock); + private: + struct SockInfo { + HWND handle; + unsigned int msg; + long ev; + }; + QMap<SOCKET, SockInfo> sockets; + QMutex mutex; + QWaitCondition cond; + bool supposedToDie; + }; + + SocketAsyncHandler::SocketAsyncHandler() + : supposedToDie(false) + { + } + + SocketAsyncHandler::~SocketAsyncHandler() + { + mutex.lock(); + supposedToDie = true; + mutex.unlock(); + cond.wakeOne(); + wait(); + while (sockets.size() > 0) + removeSelect(sockets.begin().key()); + } + + void SocketAsyncHandler::removeSelect(SOCKET sock) + { + if (!sockets.contains(sock)) + return; + sockets.remove(sock); + return; + } + + void SocketAsyncHandler::safeRemove(SOCKET sock) + { + QMutexLocker locker(&mutex); + removeSelect(sock); + } + + void SocketAsyncHandler::select(SOCKET sock, HWND handle, unsigned int msg, long ev) + { + QMutexLocker locker(&mutex); + + if (sockets.contains(sock)) + sockets.remove(sock); + + SockInfo info; + info.handle = handle; + info.msg = msg; + info.ev = ev; + sockets.insert(sock, info); + cond.wakeOne(); + } + + void SocketAsyncHandler::run() + { + do { + mutex.lock(); + + while (!supposedToDie && sockets.isEmpty()) { + cond.wait(&mutex); + } + + if (supposedToDie) { + mutex.unlock(); + break; + } + + // Copy current items to reduce lock time + // and to be able to use SendMessage + QMap<SOCKET, SockInfo> currentSockets = sockets; + mutex.unlock(); + + fd_set readS, writeS, exS; + FD_ZERO(&readS); + FD_ZERO(&writeS); + FD_ZERO(&exS); + + int maxFd = 0; + + for (QMap<SOCKET, SockInfo>::iterator it = currentSockets.begin(); it != currentSockets.end(); ++it) { + const SockInfo &info = it.value(); + int socket = it.key(); + maxFd = qMax(maxFd, socket); + + if ((info.ev & FD_READ) || (info.ev & FD_CLOSE) || (info.ev & FD_ACCEPT)) + FD_SET(socket, &readS); + if ((info.ev & FD_WRITE)|| (info.ev & FD_CONNECT)) + FD_SET(socket, &writeS); + if (info.ev & FD_OOB) + FD_SET(socket, &exS); + } + + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; + int result = ::select(maxFd + 1, &readS, &writeS, &exS, &timeout); + if (result > 0) { + HWND handle; + unsigned int tmpMsg; + SOCKET sock; + HRESULT ret; + for (QMap<SOCKET, SockInfo>::const_iterator it = currentSockets.constBegin(); + it != currentSockets.constEnd(); ++it) { + handle = (*it).handle; + tmpMsg = (*it).msg; + sock = it.key(); + if (FD_ISSET(sock, &readS)) + ret = SendMessage(handle, tmpMsg, sock, FD_READ); + + if (FD_ISSET(sock, &writeS)) + ret = SendMessage(handle, tmpMsg, sock, FD_WRITE); + + if (FD_ISSET(sock, &exS)) + ret = SendMessage(handle, tmpMsg, sock, FD_OOB); + } + } + +#ifdef QCE_ASYNC_DEBUG + else if (result == 0) { //timeout + qDebug(" WSAAsync select timeout"); + } else if (result < 0) { // SocketError + // This might happen because of two reasons + // 1. We already closed a socket in between the copy and the select + // and thus select() returns an error + // 2. Something is really wrong, then + // ### Loop on all descriptors, try to select and remove the + // ### broken one. + qWarning("WSAAsync select error %d", WSAGetLastError()); + } +#endif + } while(true); + } +} // namespace + +Q_GLOBAL_STATIC(SocketAsyncHandler, qt_async_handler) + +int WSAAsyncSelect(SOCKET sock, HWND handle, unsigned int msg, long ev) +{ + if (sock == 0 || handle == 0 || handle == INVALID_HANDLE_VALUE) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + + if (msg == 0 && ev == 0) + qt_async_handler()->safeRemove(sock); + else + qt_async_handler()->select(sock, handle, msg, ev); + + qt_async_handler()->start(QThread::LowPriority); + WSASetLastError(0); + return 0; +} +#else // QT_NO_THREAD +int WSAAsyncSelect(SOCKET, HWND, unsigned int, long) +{ + return SOCKET_ERROR; +} +#endif +#endif // Q_OS_WINCE + +class QEventDispatcherWin32Private; + +struct QSockNot { + QSocketNotifier *obj; + int fd; +}; +typedef QHash<int, QSockNot *> QSNDict; + +struct WinTimerInfo { // internal timer info + QObject *dispatcher; + int timerId; + int interval; + QObject *obj; // - object to receive events + bool inTimerEvent; + int fastTimerId; +}; + +class QZeroTimerEvent : public QTimerEvent +{ +public: + inline QZeroTimerEvent(int timerId) + : QTimerEvent(timerId) + { t = QEvent::ZeroTimerEvent; } +}; + +typedef QList<WinTimerInfo*> WinTimerVec; // vector of TimerInfo structs +typedef QHash<int, WinTimerInfo*> WinTimerDict; // fast dict of timers + +#if !defined(DWORD_PTR) && !defined(Q_WS_WIN64) +#define DWORD_PTR DWORD +#endif + +typedef MMRESULT(WINAPI *ptimeSetEvent)(UINT, UINT, LPTIMECALLBACK, DWORD_PTR, UINT); +typedef MMRESULT(WINAPI *ptimeKillEvent)(UINT); + +static ptimeSetEvent qtimeSetEvent = 0; +static ptimeKillEvent qtimeKillEvent = 0; + +LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); + +static void resolveTimerAPI() +{ + static bool triedResolve = false; + if (!triedResolve) { +#ifndef QT_NO_THREAD + QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); + if (triedResolve) + return; +#endif + triedResolve = true; +#if !defined(Q_OS_WINCE) + qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("winmm"), "timeSetEvent"); + qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("winmm"), "timeKillEvent"); +#else + qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeSetEvent"); + qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeKillEvent"); +#endif + } +} + + +class QEventDispatcherWin32Private : public QAbstractEventDispatcherPrivate +{ + Q_DECLARE_PUBLIC(QEventDispatcherWin32) +public: + QEventDispatcherWin32Private(); + ~QEventDispatcherWin32Private(); + + DWORD threadId; + + bool interrupt; + + // internal window handle used for socketnotifiers/timers/etc + HWND internalHwnd; + + // timers + WinTimerVec timerVec; + WinTimerDict timerDict; + void registerTimer(WinTimerInfo *t); + void unregisterTimer(WinTimerInfo *t); + void sendTimerEvent(int timerId); + + // socket notifiers + QSNDict sn_read; + QSNDict sn_write; + QSNDict sn_except; + void doWsaAsyncSelect(int socket); + + // event notifier + QWinEventNotifier wakeUpNotifier; + + QList<QWinEventNotifier *> winEventNotifierList; + void activateEventNotifier(QWinEventNotifier * wen); + + QList<MSG> queuedUserInputEvents; + QList<MSG> queuedSocketEvents; +}; + +QEventDispatcherWin32Private::QEventDispatcherWin32Private() + : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0) +{ + resolveTimerAPI(); + + wakeUpNotifier.setHandle(QT_WA_INLINE(CreateEventW(0, FALSE, FALSE, 0), + CreateEventA(0, FALSE, FALSE, 0))); + if (!wakeUpNotifier.handle()) + qWarning("QEventDispatcher: Creating QEventDispatcherWin32Private wakeup event failed"); +} + +QEventDispatcherWin32Private::~QEventDispatcherWin32Private() +{ + wakeUpNotifier.setEnabled(false); + CloseHandle(wakeUpNotifier.handle()); + if (internalHwnd) + DestroyWindow(internalHwnd); + QByteArray className = "QEventDispatcherWin32_Internal_Widget" + QByteArray::number(quintptr(qt_internal_proc)); +#if !defined(Q_OS_WINCE) + UnregisterClassA(className.constData(), qWinAppInst()); +#else + UnregisterClassW(reinterpret_cast<const wchar_t *> (QString::fromLatin1(className.constData()).utf16()) + , qWinAppInst()); +#endif +} + +void QEventDispatcherWin32Private::activateEventNotifier(QWinEventNotifier * wen) +{ + QEvent event(QEvent::WinEventAct); + QCoreApplication::sendEvent(wen, &event); +} + + +Q_CORE_EXPORT bool winPeekMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin, + UINT wMsgFilterMax, UINT wRemoveMsg) +{ + QT_WA({ return PeekMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); } , + { return PeekMessageA(msg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); }); +} + +Q_CORE_EXPORT bool winPostMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + QT_WA({ return PostMessage(hWnd, msg, wParam, lParam); } , + { return PostMessageA(hWnd, msg, wParam, lParam); }); +} + +Q_CORE_EXPORT bool winGetMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin, + UINT wMsgFilterMax) +{ + QT_WA({ return GetMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax); } , + { return GetMessageA(msg, hWnd, wMsgFilterMin, wMsgFilterMax); }); +} + +// This function is called by a workerthread +void WINAPI CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/, DWORD_PTR user, DWORD_PTR /*reserved*/, DWORD_PTR /*reserved*/) +{ + if (!timerId) // sanity check + return; + WinTimerInfo *t = (WinTimerInfo*)user; + Q_ASSERT(t); + QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId)); +} + +LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) +{ + if (message == WM_NCCREATE) { + return true; + } else if (message == WM_USER) { + + // socket notifier message + MSG msg; + msg.hwnd = hwnd; + msg.message = message; + msg.wParam = wp; + msg.lParam = lp; + + QCoreApplication *app = QCoreApplication::instance(); + long result; + if (app && app->filterEvent(&msg, &result)) + return result; + + int type = -1; + switch (WSAGETSELECTEVENT(lp)) { + case FD_READ: + case FD_CLOSE: + case FD_ACCEPT: + type = 0; + break; + case FD_WRITE: + case FD_CONNECT: + type = 1; + break; + case FD_OOB: + type = 2; + break; + } + if (type >= 0) { + + #ifdef GWLP_USERDATA + QEventDispatcherWin32 *eventDispatcher = + (QEventDispatcherWin32 *) GetWindowLongPtrA(hwnd, GWLP_USERDATA); + #else + QEventDispatcherWin32 *eventDispatcher = + (QEventDispatcherWin32 *) GetWindowLongA(hwnd, GWL_USERDATA); + #endif + if (eventDispatcher) { + QEventDispatcherWin32Private *d = eventDispatcher->d_func(); + QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except }; + QSNDict *dict = sn_vec[type]; + + QSockNot *sn = dict ? dict->value(wp) : 0; + if (sn) { + QEvent event(QEvent::SockAct); + QCoreApplication::sendEvent(sn->obj, &event); + } + } + } + return 0; + + } else if (message == WM_TIMER) { + + MSG msg; + msg.hwnd = hwnd; + msg.message = message; + msg.wParam = wp; + msg.lParam = lp; + + QCoreApplication *app = QCoreApplication::instance(); + Q_ASSERT_X(app, "qt_interal_proc", "Timer fired, but no QCoreApplication"); + if (!app) { + KillTimer(hwnd, wp); + return 0; + } + + long result; + if (app->filterEvent(&msg, &result)) + return result; + + QEventDispatcherWin32 *eventDispatcher = + qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance()); + Q_ASSERT(eventDispatcher != 0); + QEventDispatcherWin32Private *d = eventDispatcher->d_func(); + d->sendTimerEvent(wp); + return 0; + } + + return DefWindowProc(hwnd, message, wp, lp); +} + +static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher) +{ + HINSTANCE hi = qWinAppInst(); +#if defined(Q_OS_WINCE) + WNDCLASS wc; +#else + WNDCLASSA wc; +#endif + wc.style = 0; + wc.lpfnWndProc = qt_internal_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hi; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = 0; + wc.lpszMenuName = NULL; + + // make sure that multiple Qt's can coexist in the same process + QByteArray className = "QEventDispatcherWin32_Internal_Widget" + QByteArray::number(quintptr(qt_internal_proc)); +#if defined(Q_OS_WINCE) + QString tmp = QString::fromLatin1(className.data()); + wc.lpszClassName = reinterpret_cast<const wchar_t *> (tmp.utf16()); + RegisterClass(&wc); + HWND wnd = CreateWindow(wc.lpszClassName, // classname + wc.lpszClassName, // window name + 0, // style + 0, 0, 0, 0, // geometry + 0, // parent + 0, // menu handle + hi, // application + 0); // windows creation data. +#else + wc.lpszClassName = className.constData(); + RegisterClassA(&wc); + HWND wnd = CreateWindowA(wc.lpszClassName, // classname + wc.lpszClassName, // window name + 0, // style + 0, 0, 0, 0, // geometry + 0, // parent + 0, // menu handle + hi, // application + 0); // windows creation data. +#endif + + +#ifdef GWLP_USERDATA + SetWindowLongPtrA(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher); +#else + SetWindowLongA(wnd, GWL_USERDATA, (LONG)eventDispatcher); +#endif + + if (!wnd) { + qWarning("QEventDispatcher: Failed to create QEventDispatcherWin32 internal window: %d\n", (int)GetLastError()); + } + return wnd; +} + +void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t) +{ + Q_ASSERT(internalHwnd); + + Q_Q(QEventDispatcherWin32); + + int ok = 0; + + if (t->interval > 10 || !t->interval || !qtimeSetEvent) { + ok = 1; + if (!t->interval) // optimization for single-shot-zero-timer + QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId)); + else + ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0); + } else { + ok = t->fastTimerId = qtimeSetEvent(t->interval, 1, qt_fast_timer_proc, (DWORD_PTR)t, + TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS); + if (ok == 0) { // fall back to normal timer if no more multimedia timers avaiable + ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0); + } + } + + if (ok == 0) + qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer"); +} + +void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t) +{ + // mark timer as unused + if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) + QAbstractEventDispatcherPrivate::releaseTimerId(t->timerId); + + if (t->interval == 0) { + QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId); + } else if (t->fastTimerId != 0) { + qtimeKillEvent(t->fastTimerId); + QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId); + } else if (internalHwnd) { + KillTimer(internalHwnd, t->timerId); + } + delete t; +} + +void QEventDispatcherWin32Private::sendTimerEvent(int timerId) +{ + WinTimerInfo *t = timerDict.value(timerId); + if (t && !t->inTimerEvent) { + // send event, but don't allow it to recurse + t->inTimerEvent = true; + + QTimerEvent e(t->timerId); + QCoreApplication::sendEvent(t->obj, &e); + + // timer could have been removed + t = timerDict.value(timerId); + if (t) { + t->inTimerEvent = false; + } + } +} + +void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket) +{ + Q_ASSERT(internalHwnd); + int sn_event = 0; + if (sn_read.contains(socket)) + sn_event |= FD_READ | FD_CLOSE | FD_ACCEPT; + if (sn_write.contains(socket)) + sn_event |= FD_WRITE | FD_CONNECT; + if (sn_except.contains(socket)) + sn_event |= FD_OOB; + // BoundsChecker may emit a warning for WSAAsyncSelect when sn_event == 0 + // This is a BoundsChecker bug and not a Qt bug + WSAAsyncSelect(socket, internalHwnd, sn_event ? WM_USER : 0, sn_event); +} + +void QEventDispatcherWin32::createInternalHwnd() +{ + Q_D(QEventDispatcherWin32); + + Q_ASSERT(!d->internalHwnd); + if (d->internalHwnd) + return; + d->internalHwnd = qt_create_internal_window(this); + + // register all socket notifiers + QList<int> sockets = (d->sn_read.keys().toSet() + + d->sn_write.keys().toSet() + + d->sn_except.keys().toSet()).toList(); + for (int i = 0; i < sockets.count(); ++i) + d->doWsaAsyncSelect(sockets.at(i)); + + // start all normal timers + for (int i = 0; i < d->timerVec.count(); ++i) + d->registerTimer(d->timerVec.at(i)); +} + +QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent) + : QAbstractEventDispatcher(*new QEventDispatcherWin32Private, parent) +{ +} + +QEventDispatcherWin32::~QEventDispatcherWin32() +{ +} + +bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + Q_D(QEventDispatcherWin32); + + if (!d->internalHwnd) + createInternalHwnd(); + + d->interrupt = false; + emit awake(); + + bool canWait; + bool retVal = false; + do { + QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); + + DWORD waitRet = 0; + HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1]; + QVarLengthArray<MSG> processedTimers; + while (!d->interrupt) { + DWORD nCount = d->winEventNotifierList.count(); + Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1); + + MSG msg; + bool haveMessage; + + if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) { + // process queued user input events + haveMessage = true; + msg = d->queuedUserInputEvents.takeFirst(); + } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) { + // process queued socket events + haveMessage = true; + msg = d->queuedSocketEvents.takeFirst(); + } else { + haveMessage = winPeekMessage(&msg, 0, 0, 0, PM_REMOVE); + if (haveMessage && (flags & QEventLoop::ExcludeUserInputEvents) + && ((msg.message >= WM_KEYFIRST + && msg.message <= WM_KEYLAST) + || (msg.message >= WM_MOUSEFIRST + && msg.message <= WM_MOUSELAST) + || msg.message == WM_MOUSEWHEEL)) { + // queue user input events for later processing + haveMessage = false; + d->queuedUserInputEvents.append(msg); + } + if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers) + && (msg.message == WM_USER && msg.hwnd == d->internalHwnd)) { + // queue socket events for later processing + haveMessage = false; + d->queuedSocketEvents.append(msg); + } + } + if (!haveMessage) { + // no message - check for signalled objects + for (int i=0; i<(int)nCount; i++) + pHandles[i] = d->winEventNotifierList.at(i)->handle(); + waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE); + if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) { + // a new message has arrived, process it + continue; + } + } + if (haveMessage) { + if (msg.message == WM_TIMER) { + // avoid live-lock by keeping track of the timers we've already sent + bool found = false; + for (int i = 0; !found && i < processedTimers.count(); ++i) { + const MSG processed = processedTimers.constData()[i]; + found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam); + } + if (found) + continue; + processedTimers.append(msg); + } else if (msg.message == WM_QUIT) { + if (QCoreApplication::instance()) + QCoreApplication::instance()->quit(); + return false; + } + + if (!filterEvent(&msg)) { + TranslateMessage(&msg); + QT_WA({ + DispatchMessage(&msg); + } , { + DispatchMessageA(&msg); + }); + } + } else if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) { + d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); + } else { + // nothing todo so break + break; + } + retVal = true; + } + + // still nothing - wait for message or signalled objects + QThreadData *data = d->threadData; + canWait = (!retVal + && data->canWait + && !d->interrupt + && (flags & QEventLoop::WaitForMoreEvents)); + if (canWait) { + DWORD nCount = d->winEventNotifierList.count(); + Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1); + for (int i=0; i<(int)nCount; i++) + pHandles[i] = d->winEventNotifierList.at(i)->handle(); + + emit aboutToBlock(); + waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE); + emit awake(); + if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) { + d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); + retVal = true; + } + } + } while (canWait); + + return retVal; +} + +bool QEventDispatcherWin32::hasPendingEvents() +{ + MSG msg; + return qGlobalPostedEventsCount() || winPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); +} + +void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int sockfd = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (sockfd < 0) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); + return; + } +#endif + + Q_D(QEventDispatcherWin32); + QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except }; + QSNDict *dict = sn_vec[type]; + + if (QCoreApplication::closingDown()) // ### d->exitloop? + return; // after sn_cleanup, don't reinitialize. + + if (dict->contains(sockfd)) { + const char *t[] = { "Read", "Write", "Exception" }; + /* Variable "socket" below is a function pointer. */ + qWarning("QSocketNotifier: Multiple socket notifiers for " + "same socket %d and type %s", sockfd, t[type]); + } + + QSockNot *sn = new QSockNot; + sn->obj = notifier; + sn->fd = sockfd; + dict->insert(sn->fd, sn); + + if (d->internalHwnd) + d->doWsaAsyncSelect(sockfd); +} + +void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int sockfd = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (sockfd < 0) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); + return; + } +#endif + + Q_D(QEventDispatcherWin32); + QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except }; + QSNDict *dict = sn_vec[type]; + QSockNot *sn = dict->value(sockfd); + if (!sn) + return; + + dict->remove(sockfd); + delete sn; + + if (d->internalHwnd) + d->doWsaAsyncSelect(sockfd); +} + +void QEventDispatcherWin32::registerTimer(int timerId, int interval, QObject *object) +{ + if (timerId < 1 || interval < 0 || !object) { + qWarning("QEventDispatcherWin32::registerTimer: invalid arguments"); + return; + } else if (object->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QObject::startTimer: timers cannot be started from another thread"); + return; + } + + Q_D(QEventDispatcherWin32); + + register WinTimerInfo *t = new WinTimerInfo; + t->dispatcher = this; + t->timerId = timerId; + t->interval = interval; + t->obj = object; + t->inTimerEvent = false; + t->fastTimerId = 0; + + if (d->internalHwnd) + d->registerTimer(t); + + d->timerVec.append(t); // store in timer vector + d->timerDict.insert(t->timerId, t); // store timers in dict +} + +bool QEventDispatcherWin32::unregisterTimer(int timerId) +{ + if (timerId < 1) { + qWarning("QEventDispatcherWin32::unregisterTimer: invalid argument"); + return false; + } + QThread *currentThread = QThread::currentThread(); + if (thread() != currentThread) { + qWarning("QObject::killTimer: timers cannot be stopped from another thread"); + return false; + } + + Q_D(QEventDispatcherWin32); + if (d->timerVec.isEmpty() || timerId <= 0) + return false; + + WinTimerInfo *t = d->timerDict.value(timerId); + if (!t) + return false; + + d->timerDict.remove(t->timerId); + d->timerVec.removeAll(t); + d->unregisterTimer(t); + return true; +} + +bool QEventDispatcherWin32::unregisterTimers(QObject *object) +{ + if (!object) { + qWarning("QEventDispatcherWin32::unregisterTimers: invalid argument"); + return false; + } + QThread *currentThread = QThread::currentThread(); + if (object->thread() != thread() || thread() != currentThread) { + qWarning("QObject::killTimers: timers cannot be stopped from another thread"); + return false; + } + + Q_D(QEventDispatcherWin32); + if (d->timerVec.isEmpty()) + return false; + register WinTimerInfo *t; + for (int i=0; i<d->timerVec.size(); i++) { + t = d->timerVec.at(i); + if (t && t->obj == object) { // object found + d->timerDict.remove(t->timerId); + d->timerVec.removeAt(i); + d->unregisterTimer(t); + --i; + } + } + return true; +} + +QList<QEventDispatcherWin32::TimerInfo> +QEventDispatcherWin32::registeredTimers(QObject *object) const +{ + if (!object) { + qWarning("QEventDispatcherWin32:registeredTimers: invalid argument"); + return QList<TimerInfo>(); + } + + Q_D(const QEventDispatcherWin32); + QList<TimerInfo> list; + for (int i = 0; i < d->timerVec.size(); ++i) { + const WinTimerInfo *t = d->timerVec.at(i); + if (t && t->obj == object) + list << TimerInfo(t->timerId, t->interval); + } + return list; +} + +bool QEventDispatcherWin32::registerEventNotifier(QWinEventNotifier *notifier) +{ + if (!notifier) { + qWarning("QWinEventNotifier: Internal error"); + return false; + } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QWinEventNotifier: event notifiers cannot be enabled from another thread"); + return false; + } + + Q_D(QEventDispatcherWin32); + + if (d->winEventNotifierList.contains(notifier)) + return true; + + if (d->winEventNotifierList.count() >= MAXIMUM_WAIT_OBJECTS - 2) { + qWarning("QWinEventNotifier: Cannot have more than %d enabled at one time", MAXIMUM_WAIT_OBJECTS - 2); + return false; + } + d->winEventNotifierList.append(notifier); + return true; +} + +void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier) +{ + if (!notifier) { + qWarning("QWinEventNotifier: Internal error"); + return; + } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QWinEventNotifier: event notifiers cannot be disabled from another thread"); + return; + } + + Q_D(QEventDispatcherWin32); + + int i = d->winEventNotifierList.indexOf(notifier); + if (i != -1) + d->winEventNotifierList.takeAt(i); +} + +void QEventDispatcherWin32::activateEventNotifiers() +{ + Q_D(QEventDispatcherWin32); + //### this could break if events are removed/added in the activation + for (int i=0; i<d->winEventNotifierList.count(); i++) { +#if !defined(Q_OS_WINCE) + if (WaitForSingleObjectEx(d->winEventNotifierList.at(i)->handle(), 0, TRUE) == WAIT_OBJECT_0) + d->activateEventNotifier(d->winEventNotifierList.at(i)); +#else + if (WaitForSingleObject(d->winEventNotifierList.at(i)->handle(), 0) == WAIT_OBJECT_0) + d->activateEventNotifier(d->winEventNotifierList.at(i)); +#endif + } +} + +void QEventDispatcherWin32::wakeUp() +{ + Q_D(QEventDispatcherWin32); + SetEvent(d->wakeUpNotifier.handle()); +} + +void QEventDispatcherWin32::interrupt() +{ + Q_D(QEventDispatcherWin32); + d->interrupt = true; + wakeUp(); +} + +void QEventDispatcherWin32::flush() +{ } + + +void QEventDispatcherWin32::startingUp() +{ + Q_D(QEventDispatcherWin32); + + if (d->wakeUpNotifier.handle()) d->wakeUpNotifier.setEnabled(true); +} + +void QEventDispatcherWin32::closingDown() +{ + Q_D(QEventDispatcherWin32); + + // clean up any socketnotifiers + while (!d->sn_read.isEmpty()) + unregisterSocketNotifier((*(d->sn_read.begin()))->obj); + while (!d->sn_write.isEmpty()) + unregisterSocketNotifier((*(d->sn_write.begin()))->obj); + while (!d->sn_except.isEmpty()) + unregisterSocketNotifier((*(d->sn_except.begin()))->obj); + + // clean up any timers + while (!d->timerDict.isEmpty()) + unregisterTimer((*(d->timerDict.begin()))->timerId); +} + +bool QEventDispatcherWin32::event(QEvent *e) +{ + Q_D(QEventDispatcherWin32); + if (e->type() == QEvent::ZeroTimerEvent) { + QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e); + WinTimerInfo *t = d->timerDict.value(zte->timerId()); + if (t) { + QTimerEvent te(zte->timerId()); + QCoreApplication::sendEvent(t->obj, &te); + WinTimerInfo *tn = d->timerDict.value(zte->timerId()); + if (tn && t == tn) + QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId())); + } + return true; + } else if (e->type() == QEvent::Timer) { + QTimerEvent *te = static_cast<QTimerEvent*>(e); + d->sendTimerEvent(te->timerId()); + } + return QAbstractEventDispatcher::event(e); +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h new file mode 100644 index 0000000..aec0f7d --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVENTDISPATCHER_WIN_P_H +#define QEVENTDISPATCHER_WIN_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. +// + +#include "QtCore/qabstracteventdispatcher.h" +#include "QtCore/qt_windows.h" + +QT_BEGIN_NAMESPACE + +class QWinEventNotifier; +class QEventDispatcherWin32Private; + +// forward declaration +LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); + +class Q_CORE_EXPORT QEventDispatcherWin32 : public QAbstractEventDispatcher +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QEventDispatcherWin32) + + void createInternalHwnd(); + friend class QGuiEventDispatcherWin32; + +public: + explicit QEventDispatcherWin32(QObject *parent = 0); + ~QEventDispatcherWin32(); + + bool processEvents(QEventLoop::ProcessEventsFlags flags); + bool hasPendingEvents(); + + void registerSocketNotifier(QSocketNotifier *notifier); + void unregisterSocketNotifier(QSocketNotifier *notifier); + + void registerTimer(int timerId, int interval, QObject *object); + bool unregisterTimer(int timerId); + bool unregisterTimers(QObject *object); + QList<TimerInfo> registeredTimers(QObject *object) const; + + bool registerEventNotifier(QWinEventNotifier *notifier); + void unregisterEventNotifier(QWinEventNotifier *notifier); + void activateEventNotifiers(); + + void wakeUp(); + void interrupt(); + void flush(); + + void startingUp(); + void closingDown(); + + bool event(QEvent *e); + +private: + friend LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); +}; + +QT_END_NAMESPACE + +#endif // QEVENTDISPATCHER_WIN_P_H diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp new file mode 100644 index 0000000..92bdf73 --- /dev/null +++ b/src/corelib/kernel/qeventloop.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeventloop.h" + +#include "qabstracteventdispatcher.h" +#include "qcoreapplication.h" +#include "qdatetime.h" + +#include "qobject_p.h" +#include <private/qthread_p.h> + +QT_BEGIN_NAMESPACE + +class QEventLoopPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QEventLoop) +public: + inline QEventLoopPrivate() + : exit(true), inExec(false), returnCode(-1) + { } + bool exit, inExec; + int returnCode; +}; + +/*! + \class QEventLoop + \brief The QEventLoop class provides a means of entering and leaving an event loop. + + At any time, you can create a QEventLoop object and call exec() + on it to start a local event loop. From within the event loop, + calling exit() will force exec() to return. + + \sa QAbstractEventDispatcher +*/ + +/*! + \enum QEventLoop::ProcessEventsFlag + + This enum controls the types of events processed by the + processEvents() functions. + + \value AllEvents All events. Note that + \l{QEvent::DeferredDelete}{DeferredDelete} events are processed + specially. See QObject::deleteLater() for more details. + + \value ExcludeUserInputEvents Do not process user input events, + such as ButtonPress and KeyPress. Note that the events are not + discarded; they will be delivered the next time processEvents() is + called without the ExcludeUserInputEvents flag. + + \value ExcludeSocketNotifiers Do not process socket notifier + events. Note that the events are not discarded; they will be + delivered the next time processEvents() is called without the + ExcludeSocketNotifiers flag. + + \value WaitForMoreEvents Wait for events if no pending events are + available. + + \omitvalue X11ExcludeTimers + \omitvalue ExcludeUserInput + \omitvalue WaitForMore + \omitvalue EventLoopExec + \omitvalue DialogExec + \value DeferredDeletion deprecated - do not use. + + \sa processEvents() +*/ + +/*! + Constructs an event loop object with the given \a parent. +*/ +QEventLoop::QEventLoop(QObject *parent) + : QObject(*new QEventLoopPrivate, parent) +{ + Q_D(QEventLoop); + if (!QCoreApplication::instance()) { + qWarning("QEventLoop: Cannot be used without QApplication"); + } else if (!d->threadData->eventDispatcher) { + QThreadPrivate::createEventDispatcher(d->threadData); + } +} + +/*! + Destroys the event loop object. +*/ +QEventLoop::~QEventLoop() +{ } + + +/*! + Processes pending events that match \a flags until there are no + more events to process. Returns true if pending events were handled; + otherwise returns false. + + This function is especially useful if you have a long running + operation and want to show its progress without allowing user + input; i.e. by using the \l ExcludeUserInputEvents flag. + + This function is simply a wrapper for + QAbstractEventDispatcher::processEvents(). See the documentation + for that function for details. +*/ +bool QEventLoop::processEvents(ProcessEventsFlags flags) +{ + Q_D(QEventLoop); + if (!d->threadData->eventDispatcher) + return false; + if (flags & DeferredDeletion) + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + return d->threadData->eventDispatcher->processEvents(flags); +} + +/*! + Enters the main event loop and waits until exit() is called. + Returns the value that was passed to exit(). + + If \a flags are specified, only events of the types allowed by + the \a flags will be processed. + + It is necessary to call this function to start event handling. The + main event loop receives events from the window system and + dispatches these to the application widgets. + + Generally speaking, no user interaction can take place before + calling exec(). As a special case, modal widgets like QMessageBox + can be used before calling exec(), because modal widgets + use their own local event loop. + + To make your application perform idle processing (i.e. executing a + special function whenever there are no pending events), use a + QTimer with 0 timeout. More sophisticated idle processing schemes + can be achieved using processEvents(). + + \sa QApplication::quit(), exit(), processEvents() +*/ +int QEventLoop::exec(ProcessEventsFlags flags) +{ + Q_D(QEventLoop); + if (d->threadData->quitNow) + return -1; + + if (d->inExec) { + qWarning("QEventLoop::exec: instance %p has already called exec()", this); + return -1; + } + d->inExec = true; + d->exit = false; + ++d->threadData->loopLevel; + d->threadData->eventLoops.push(this); + + // remove posted quit events when entering a new event loop + if (qApp->thread() == thread()) + QCoreApplication::removePostedEvents(qApp, QEvent::Quit); + +#if defined(QT_NO_EXCEPTIONS) + while (!d->exit) + processEvents(flags | WaitForMoreEvents | EventLoopExec); +#else + try { + while (!d->exit) + processEvents(flags | WaitForMoreEvents | EventLoopExec); + } catch (...) { + qWarning("Qt has caught an exception thrown from an event handler. Throwing\n" + "exceptions from an event handler is not supported in Qt. You must\n" + "reimplement QApplication::notify() and catch all exceptions there.\n"); + + // copied from below + QEventLoop *eventLoop = d->threadData->eventLoops.pop(); + Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error"); + Q_UNUSED(eventLoop); // --release warning + d->inExec = false; + --d->threadData->loopLevel; + + throw; + } +#endif + + // copied above + QEventLoop *eventLoop = d->threadData->eventLoops.pop(); + Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error"); + Q_UNUSED(eventLoop); // --release warning + d->inExec = false; + --d->threadData->loopLevel; + + return d->returnCode; +} + +/*! + Process pending events that match \a flags for a maximum of \a + maxTime milliseconds, or until there are no more events to + process, whichever is shorter. + This function is especially useful if you have a long running + operation and want to show its progress without allowing user + input, i.e. by using the \l ExcludeUserInputEvents flag. + + \bold{Notes:} + \list + \o This function does not process events continuously; it + returns after all available events are processed. + \o Specifying the \l WaitForMoreEvents flag makes no sense + and will be ignored. + \endlist +*/ +void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime) +{ + Q_D(QEventLoop); + if (!d->threadData->eventDispatcher) + return; + + QTime start; + start.start(); + if (flags & DeferredDeletion) + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + while (processEvents(flags & ~WaitForMoreEvents)) { + if (start.elapsed() > maxTime) + break; + if (flags & DeferredDeletion) + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + } +} + +/*! + Tells the event loop to exit with a return code. + + After this function has been called, the event loop returns from + the call to exec(). The exec() function returns \a returnCode. + + By convention, a \a returnCode of 0 means success, and any non-zero + value indicates an error. + + Note that unlike the C library function of the same name, this + function \e does return to the caller -- it is event processing that + stops. + + \sa QCoreApplication::quit(), quit(), exec() +*/ +void QEventLoop::exit(int returnCode) +{ + Q_D(QEventLoop); + if (!d->threadData->eventDispatcher) + return; + + d->returnCode = returnCode; + d->exit = true; + d->threadData->eventDispatcher->interrupt(); +} + +/*! + Returns true if the event loop is running; otherwise returns + false. The event loop is considered running from the time when + exec() is called until exit() is called. + + \sa exec() exit() + */ +bool QEventLoop::isRunning() const +{ + Q_D(const QEventLoop); + return !d->exit; +} + +/*! + Wakes up the event loop. + + \sa QAbstractEventDispatcher::wakeUp() +*/ +void QEventLoop::wakeUp() +{ + Q_D(QEventLoop); + if (!d->threadData->eventDispatcher) + return; + d->threadData->eventDispatcher->wakeUp(); +} + +/*! + Tells the event loop to exit normally. + + Same as exit(0). + + \sa QCoreApplication::quit(), exit() +*/ +void QEventLoop::quit() +{ exit(0); } + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventloop.h b/src/corelib/kernel/qeventloop.h new file mode 100644 index 0000000..81ec339 --- /dev/null +++ b/src/corelib/kernel/qeventloop.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVENTLOOP_H +#define QEVENTLOOP_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QEventLoopPrivate; + +class Q_CORE_EXPORT QEventLoop : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QEventLoop) + +public: + explicit QEventLoop(QObject *parent = 0); + ~QEventLoop(); + + enum ProcessEventsFlag { + AllEvents = 0x00, + ExcludeUserInputEvents = 0x01, + ExcludeSocketNotifiers = 0x02, + WaitForMoreEvents = 0x04, +#ifdef QT3_SUPPORT + ExcludeUserInput = ExcludeUserInputEvents, + WaitForMore = WaitForMoreEvents, +#endif + X11ExcludeTimers = 0x08 +#ifdef QT_DEPRECATED + , DeferredDeletion = 0x10 +#endif + , EventLoopExec = 0x20 + , DialogExec = 0x40 + }; + Q_DECLARE_FLAGS(ProcessEventsFlags, ProcessEventsFlag) + + bool processEvents(ProcessEventsFlags flags = AllEvents); + void processEvents(ProcessEventsFlags flags, int maximumTime); + + int exec(ProcessEventsFlags flags = AllEvents); + void exit(int returnCode = 0); + bool isRunning() const; + + void wakeUp(); + +public Q_SLOTS: + void quit(); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QEventLoop::ProcessEventsFlags) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QEVENTLOOP_H diff --git a/src/corelib/kernel/qfunctions_p.h b/src/corelib/kernel/qfunctions_p.h new file mode 100644 index 0000000..15f5fec --- /dev/null +++ b/src/corelib/kernel/qfunctions_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qfunctions_*. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +#ifndef QFUNCTIONS_P_H +#define QFUNCTIONS_P_H + +#include <QtCore/qglobal.h> + +#if defined(Q_OS_WINCE) +# include "QtCore/qfunctions_wince.h" +#endif + +#ifdef Q_CC_RVCT +// rvct doesn't see static operators when using our qalgorithms +# define Q_STATIC_GLOBAL_OPERATOR inline +# define Q_STATIC_GLOBAL_INLINE_OPERATOR inline +#else +# define Q_STATIC_GLOBAL_OPERATOR static +# define Q_STATIC_GLOBAL_INLINE_OPERATOR static inline +#endif + +QT_BEGIN_HEADER +QT_END_HEADER + +#endif + diff --git a/src/corelib/kernel/qfunctions_wince.cpp b/src/corelib/kernel/qfunctions_wince.cpp new file mode 100644 index 0000000..1c929c7 --- /dev/null +++ b/src/corelib/kernel/qfunctions_wince.cpp @@ -0,0 +1,453 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifdef _WIN32_WCE //Q_OS_WINCE + +#include <windows.h> +#include <winbase.h> +#include <kfuncs.h> +#include <stdio.h> +#include <altcecrt.h> + +#include "qplatformdefs.h" +#include "qfunctions_wince.h" +#include "qstring.h" +#include "qbytearray.h" +#include "qhash.h" + +QT_USE_NAMESPACE + +#ifdef __cplusplus +extern "C" { +#endif + +wchar_t* CEPrivConvCharToWide(const char* string) +{ + size_t length = strlen(string); + wchar_t* wString = new wchar_t[length +1]; + for (unsigned int i = 0; i < (length +1); i++) + wString[i] = string[i]; + return wString; +} + +// Time ------------------------------------------------------------- +time_t qt_wince_ftToTime_t( const FILETIME ft ) +{ + ULARGE_INTEGER li; + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + + // 100-nanosec to seconds + li.QuadPart /= 10000000; + + // FILETIME is from 1601-01-01 T 00:00:00 + // time_t is from 1970-01-01 T 00:00:00 + // 1970 - 1601 = 369 year (89 leap years) + // + // ((369y*365d) + 89d) *24h *60min *60sec + // = 11644473600 seconds + li.QuadPart -= 11644473600; + return li.LowPart; +} + +FILETIME qt_wince_time_tToFt( time_t tt ) +{ + ULARGE_INTEGER li; + li.QuadPart = tt; + li.QuadPart += 11644473600; + li.QuadPart *= 10000000; + + FILETIME ft; + ft.dwLowDateTime = li.LowPart; + ft.dwHighDateTime = li.HighPart; + return ft; +} + +// File I/O --------------------------------------------------------- +int errno = 0; + +int qt_wince__getdrive( void ) +{ + return 1; +} + +int qt_wince__waccess( const WCHAR *path, int pmode ) +{ + DWORD res = GetFileAttributes( path ); + if ( 0xFFFFFFFF == res ) + return -1; + + if ( (pmode & W_OK) && (res & FILE_ATTRIBUTE_READONLY) ) + return -1; + + if ( (pmode & X_OK) && !(res & FILE_ATTRIBUTE_DIRECTORY) ) { + QString file = QString::fromUtf16(reinterpret_cast<const ushort *> (path)); + if ( !(file.endsWith(QString::fromLatin1(".exe")) || + file.endsWith(QString::fromLatin1(".com"))) ) + return -1; + } + + return 0; +} + +int qt_wince_open( const char *filename, int oflag, int pmode ) +{ + QString fn( QString::fromLatin1(filename) ); + return _wopen( (WCHAR*)fn.utf16(), oflag, pmode ); +} + +int qt_wince__wopen( const WCHAR *filename, int oflag, int /*pmode*/ ) +{ + WCHAR *flag; + + if ( oflag & _O_APPEND ) { + if ( oflag & _O_WRONLY ) { + flag = L"a"; + } else if ( oflag & _O_RDWR ) { + flag = L"a+"; + } + } else if (oflag & _O_BINARY) { + if ( oflag & _O_WRONLY ) { + flag = L"wb"; + } else if ( oflag & _O_RDWR ) { + flag = L"w+b"; // slightly different from "r+" where the file must exist + } else if ( oflag & _O_RDONLY ) { + flag = L"rb"; + } else { + flag = L"b"; + } + } else { + if ( oflag & _O_WRONLY ) { + flag = L"wt"; + } else if ( oflag & _O_RDWR ) { + flag = L"w+t"; // slightly different from "r+" where the file must exist + } else if ( oflag & _O_RDONLY ) { + flag = L"rt"; + } else { + flag = L"t"; + } + } + + int retval = (int)_wfopen( filename, flag ); + return (retval == NULL) ? -1 : retval; +} + +long qt_wince__lseek( int handle, long offset, int origin ) +{ + return fseek( (FILE*)handle, offset, origin ); +} + +int qt_wince__read( int handle, void *buffer, unsigned int count ) +{ + return fread( buffer, 1, count, (FILE*)handle ); +} + +int qt_wince__write( int handle, const void *buffer, unsigned int count ) +{ + return fwrite( buffer, 1, count, (FILE*)handle ); +} + +int qt_wince__close( int handle ) +{ + if (!handle) + return 0; + return fclose( (FILE*)handle ); +} + +FILE *qt_wince__fdopen(int handle, const char* /*mode*/) +{ + return (FILE*)handle; +} + +FILE *qt_wince_fdopen( int handle, const char* /*mode*/ ) +{ + return (FILE*)handle; +} + +void qt_wince_rewind( FILE *stream ) +{ + fseek( stream, 0L, SEEK_SET ); +} + +int qt_wince___fileno(FILE *f) +{ + return (int) _fileno(f); +} + +FILE *qt_wince_tmpfile( void ) +{ + static long i = 0; + char name[16]; + sprintf( name, "tmp%i", i++ ); + return fopen( name, "r+" ); +} + +int qt_wince__mkdir(const char *dirname) +{ + return CreateDirectory(reinterpret_cast<const wchar_t *> (QString(QString::fromLatin1(dirname)).utf16()), 0) ? 0 : -1; +} + +int qt_wince__rmdir(const char *dirname) +{ + return RemoveDirectory(reinterpret_cast<const wchar_t *> (QString::fromLatin1(dirname).utf16())) ? 0 : -1; +} + +int qt_wince__access( const char *path, int pmode ) +{ + return _waccess(reinterpret_cast<const wchar_t *> (QString::fromLatin1(path).utf16()),pmode); +} + +int qt_wince__rename( const char *oldname, const char *newname ) +{ + return !MoveFile(reinterpret_cast<const wchar_t *> (QString::fromLatin1(oldname).utf16()), reinterpret_cast<const wchar_t *> (QString::fromLatin1(newname).utf16())); +} + +int qt_wince__remove( const char *name ) +{ + return !DeleteFile(reinterpret_cast<const wchar_t *> (QString::fromLatin1(name).utf16())); +} + +int qt_wince_stat( const char *path, struct stat *buffer ) +{ + WIN32_FIND_DATA finfo; + HANDLE ff = FindFirstFile( reinterpret_cast<const wchar_t *> (QString::fromLatin1(path).utf16()), &finfo ); + + if ( ff == INVALID_HANDLE_VALUE ) + return -1; + + buffer->st_ctime = qt_wince_ftToTime_t( finfo.ftCreationTime ); + buffer->st_atime = qt_wince_ftToTime_t( finfo.ftLastAccessTime ); + buffer->st_mtime = qt_wince_ftToTime_t( finfo.ftLastWriteTime ); + buffer->st_nlink = 0; + buffer->st_size = finfo.nFileSizeLow; // ### missing high! + buffer->st_mode = (finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR : _S_IFREG; + buffer->st_mode |= (finfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? _O_RDONLY : _O_RDWR; + return (FindClose(ff) == 0); +} + +int qt_wince__fstat( int handle, struct stat *buffer) +{ + BY_HANDLE_FILE_INFORMATION fInfo; + BOOL res = GetFileInformationByHandle((HANDLE)handle, &fInfo); + + buffer->st_ctime = qt_wince_ftToTime_t( fInfo.ftCreationTime ); + buffer->st_atime = qt_wince_ftToTime_t( fInfo.ftLastAccessTime ); + buffer->st_mtime = qt_wince_ftToTime_t( fInfo.ftLastWriteTime ); + buffer->st_nlink = 0; + buffer->st_size = fInfo.nFileSizeLow; // ### missing high! + buffer->st_mode = (fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR : _S_IFREG; + buffer->st_mode |= (fInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? _O_RDONLY : _O_RDWR; + return (res == 0); +} + +int qt_wince_SetErrorMode(int newValue) +{ + static int oldValue; + int result = oldValue; + oldValue = newValue; + return result; +} + +HRESULT qt_wince_CoInitialize(void* reserved) +{ + return CoInitializeEx(reserved, 0); +} + +bool qt_wince__chmod(const char *file, int mode) +{ + return _wchmod( reinterpret_cast<const wchar_t *> (QString::fromLatin1(file).utf16()), mode); +} + +bool qt_wince__wchmod(const WCHAR *file, int mode) +{ + // ### Does not work properly, what about just adding one property? + if(mode&_S_IWRITE) { + return SetFileAttributes(file, FILE_ATTRIBUTE_NORMAL); + } else if((mode&_S_IREAD) && !(mode&_S_IWRITE)) { + return SetFileAttributes(file, FILE_ATTRIBUTE_READONLY); + } + return false; +} + +HANDLE qt_wince_CreateFileA(LPCSTR filename, DWORD access, DWORD share, LPSECURITY_ATTRIBUTES attr, DWORD dispo, DWORD flags, HANDLE tempFile) +{ + return CreateFileW( reinterpret_cast<const wchar_t *>(QString::fromLatin1(filename).utf16()), access, share, attr, dispo, flags, tempFile); +} + +// Graphics --------------------------------------------------------- +BOOL qt_wince_SetWindowOrgEx( HDC /*hdc*/, int /*X*/, int /*Y*/, LPPOINT /*lpPoint*/) { + return TRUE; +} + +// Threading -------------------------------------------------------- +HANDLE qt_wince__beginthread(void( *start_address )( void * ), unsigned stack_size, void *arglist) +{ + unsigned initflag = 0; + if (stack_size > 0) + initflag |= STACK_SIZE_PARAM_IS_A_RESERVATION; + return CreateThread(NULL, stack_size, (LPTHREAD_START_ROUTINE)start_address, arglist, initflag, NULL); +} + +unsigned long qt_wince__beginthreadex( void *security, + unsigned stack_size, + unsigned (__stdcall *start_address)(void *), + void *arglist, + unsigned initflag, + unsigned *thrdaddr) +{ + if (stack_size > 0) + initflag |= STACK_SIZE_PARAM_IS_A_RESERVATION; + return (unsigned long) + CreateThread( (LPSECURITY_ATTRIBUTES)security, + (DWORD)stack_size, + (LPTHREAD_START_ROUTINE)start_address, + (LPVOID)arglist, + (DWORD)initflag | CREATE_SUSPENDED, + (LPDWORD)thrdaddr); +} + +void qt_wince__endthreadex(unsigned nExitCode) { + ExitThread((DWORD)nExitCode); +} + +void *qt_wince_bsearch(const void *key, + const void *base, + size_t num, + size_t size, + int (__cdecl *compare)(const void *, const void *)) +{ + size_t low = 0; + size_t high = num - 1; + while (low <= high) { + unsigned int mid = ((unsigned) (low + high)) >> 1; + int c = compare(key, (char*)base + mid * size); + if (c < 0) + high = mid - 1; + else if (c > 0) + low = mid + 1; + else + return (char*) base + mid * size; + } + return (NULL); +} + +void *lfind(const void* key, const void* base, size_t* elements, size_t size, + int (__cdecl *compare)(const void*, const void*)) +{ + const char* current = (char*) base; + const char* const end = (char*) (current + (*elements) * size); + while (current != end) { + if (compare(current, key) == 0) + return (void*)current; + current += size; + } + return 0; +} + +DWORD qt_wince_GetThreadLocale(void) +{ + return GetUserDefaultLCID(); +} + +void *qt_wince_calloc( size_t num, size_t size ) +{ + void *ptr = malloc( num * size ); + if( ptr ) + memset( ptr, 0, num * size ); + return ptr; +} + +// _getpid is currently only used for creating a temporary filename +int qt_wince__getpid() +{ + return qAbs((int)GetCurrentProcessId()); +} + +#ifdef __cplusplus +} // extern "C" +#endif +// Environment ------------------------------------------------------ +inline QHash<QByteArray, QByteArray>& qt_app_environment() +{ + static QHash<QByteArray, QByteArray> internalEnvironment; + return internalEnvironment; +} + +errno_t qt_wince_getenv_s(size_t* sizeNeeded, char* buffer, size_t bufferSize, const char* varName) +{ + if (!sizeNeeded) + return EINVAL; + + if (!qt_app_environment().contains(varName)) { + if (buffer) + buffer[0] = '\0'; + return ENOENT; + } + + QByteArray value = qt_app_environment().value(varName); + if (!value.endsWith('\0')) // win32 guarantees terminated string + value.append('\0'); + + if (bufferSize < (size_t)value.size()) { + *sizeNeeded = value.size(); + return 0; + } + + strcpy(buffer, value.constData()); + return 0; +} + +errno_t qt_wince__putenv_s(const char* varName, const char* value) +{ + QByteArray input = value; + if (input.isEmpty()) { + if (qt_app_environment().contains(varName)) + qt_app_environment().remove(varName); + } else { + // win32 guarantees terminated string + if (!input.endsWith('\0')) + input.append('\0'); + qt_app_environment()[varName] = input; + } + + return 0; +} + +#endif // Q_OS_WINCE diff --git a/src/corelib/kernel/qfunctions_wince.h b/src/corelib/kernel/qfunctions_wince.h new file mode 100644 index 0000000..123bd23 --- /dev/null +++ b/src/corelib/kernel/qfunctions_wince.h @@ -0,0 +1,396 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUNCTIONS_WCE_H +#define QFUNCTIONS_WCE_H +#ifdef Q_OS_WINCE +#include <stdio.h> +#include <stdlib.h> +#include <windows.h> +#include <winuser.h> +#include <winbase.h> +#include <objbase.h> +#include <kfuncs.h> +#include <ctype.h> +#include <time.h> +#include <crtdefs.h> +#include <altcecrt.h> +#include <winsock.h> +#include <ceconfig.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +#ifdef QT_BUILD_CORE_LIB +QT_MODULE(Core) +#endif + +QT_END_NAMESPACE +QT_END_HEADER + + +// The standard SDK misses this define... +#define _control87 _controlfp + +#if !defined __cplusplus +#define bool int +#define true 1 +#define false 0 +#endif + +// Environment ------------------------------------------------------ +errno_t qt_wince_getenv_s(size_t*, char*, size_t, const char*); +errno_t qt_wince__putenv_s(const char*, const char*); + +#ifdef __cplusplus // have this as tiff plugin is written in C +extern "C" { +#endif + +#define SetWindowLongA SetWindowLong +#define GetWindowLongA GetWindowLong +#define SendMessageA SendMessage + +#if !defined(NO_ERRNO_H) +#define NO_ERRNO_H +#endif + +// Environment ------------------------------------------------------ +int qt_wince__getpid(void); + + +// Time ------------------------------------------------------------- +#ifndef _TM_DEFINED +#define _TM_DEFINED +struct tm { + int tm_sec; /* seconds after the minute - [0,59] */ + int tm_min; /* minutes after the hour - [0,59] */ + int tm_hour; /* hours since midnight - [0,23] */ + int tm_mday; /* day of the month - [1,31] */ + int tm_mon; /* months since January - [0,11] */ + int tm_year; /* years since 1900 */ + int tm_wday; /* days since Sunday - [0,6] */ + int tm_yday; /* days since January 1 - [0,365] */ + int tm_isdst; /* daylight savings time flag */ +}; +#endif // _TM_DEFINED + +FILETIME qt_wince_time_tToFt( time_t tt ); + +// File I/O --------------------------------------------------------- +#define _O_RDONLY 0x0001 +#define _O_RDWR 0x0002 +#define _O_WRONLY 0x0004 +#define _O_CREAT 0x0008 +#define _O_TRUNC 0x0010 +#define _O_APPEND 0x0020 +#define _O_EXCL 0x0040 + +#define O_RDONLY _O_RDONLY +#define O_RDWR _O_RDWR +#define O_WRONLY _O_WRONLY +#define O_CREAT _O_CREAT +#define O_TRUNC _O_TRUNC +#define O_APPEND _O_APPEND +#define O_EXCL _O_EXCL + +#define _S_IFMT 0x0600 +#define _S_IFDIR 0x0200 +#define _S_IFCHR 0x0100 +#define _S_IFREG 0x0400 +#define _S_IREAD 0x0010 +#define _S_IWRITE 0x0008 + +#define S_IFMT _S_IFMT +#define S_IFDIR _S_IFDIR +#define S_IFCHR _S_IFCHR +#define S_IFREG _S_IFREG +#define S_IREAD _S_IREAD +#define S_IWRITE _S_IWRITE + +#ifndef _IOFBF +#define _IOFBF 0x0000 +#endif + +#ifndef _IOLBF +#define _IOLBF 0x0040 +#endif + +#ifndef _IONBF +#define _IONBF 0x0004 +#endif + +// Regular Berkeley error constants +#ifndef _STAT_DEFINED +#define _STAT_DEFINED +struct stat +{ + int st_mode; + int st_size; + int st_nlink; + time_t st_mtime; + time_t st_atime; + time_t st_ctime; +}; +#endif + +typedef int mode_t; +extern int errno; + +int qt_wince__getdrive( void ); +int qt_wince__waccess( const WCHAR *path, int pmode ); +int qt_wince__wopen( const WCHAR *filename, int oflag, int pmode ); +long qt_wince__lseek( int handle, long offset, int origin ); +int qt_wince__read( int handle, void *buffer, unsigned int count ); +int qt_wince__write( int handle, const void *buffer, unsigned int count ); +int qt_wince__close( int handle ); +FILE *qt_wince__fdopen(int handle, const char *mode); +FILE *qt_wince_fdopen(int handle, const char *mode); +void qt_wince_rewind( FILE *stream ); +int qt_wince___fileno(FILE *); +FILE *qt_wince_tmpfile( void ); + +int qt_wince__mkdir(const char *dirname); +int qt_wince__rmdir(const char *dirname); +int qt_wince__access( const char *path, int pmode ); +int qt_wince__rename( const char *oldname, const char *newname ); +int qt_wince__remove( const char *name ); +int qt_wince_open( const char *filename, int oflag, int pmode ); +int qt_wince_stat( const char *path, struct stat *buffer ); +int qt_wince__fstat( int handle, struct stat *buffer); + +#define SEM_FAILCRITICALERRORS 0x0001 +#define SEM_NOOPENFILEERRORBOX 0x0002 +int qt_wince_SetErrorMode(int); +HRESULT qt_wince_CoInitialize(void* reserved); + +bool qt_wince__chmod(const char *file, int mode); +bool qt_wince__wchmod(const WCHAR *file, int mode); + +#pragma warning(disable: 4273) +HANDLE qt_wince_CreateFileA(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); + +// Printer ---------------------------------------------------------- +#define ETO_GLYPH_INDEX 0x0010 + +// Graphics --------------------------------------------------------- +#ifndef SM_CXCURSOR +# define SM_CXCURSOR 13 +#endif +#ifndef SM_CYCURSOR +# define SM_CYCURSOR 14 +#endif +BOOL qt_wince_SetWindowOrgEx( HDC hdc, int X, int Y, LPPOINT lpPoint ); + +// Other stuff ------------------------------------------------------ +#define MWMO_ALERTABLE 0x0002 +// ### not the real values +#define CREATE_NO_WINDOW 2 +#define CF_HDROP 15 + +void *qt_wince_calloc(size_t num, size_t size); +#if !defined(TLS_OUT_OF_INDEXES) +# define TLS_OUT_OF_INDEXES 0xffffffff +#endif +DWORD qt_wince_GetThreadLocale(void); + +HANDLE qt_wince__beginthread(void( *start_address )( void * ), unsigned stack_size, void *arglist); + +unsigned long qt_wince__beginthreadex( void *security, + unsigned stack_size, + unsigned (__stdcall *start_address)(void *), + void *arglist, + unsigned initflag, + unsigned *thrdaddr ); +void qt_wince__endthreadex(unsigned nExitCode); + + +// bsearch is needed for building the tiff plugin +// otherwise it could go into qguifunctions_wce +void *qt_wince_bsearch(const void *key, + const void *base, + size_t num, + size_t size, + int (__cdecl *compare)(const void *, const void *)); + +// Missing typedefs +#ifndef _TIME_T_DEFINED +typedef unsigned long time_t; +#define _TIME_T_DEFINED +#endif +typedef HANDLE HDROP; + +#ifndef WS_THICKFRAME +#define WS_THICKFRAME WS_DLGFRAME +#endif + +typedef UINT UWORD; + +// Missing definitions: not necessary equal to their Win32 values +// (the goal is to just have a clean compilation of MFC) +#define WS_MAXIMIZE 0 +#define WS_MINIMIZE 0 +#ifndef WS_EX_TOOLWINDOW +#define WS_EX_TOOLWINDOW 0 +#endif +#define WS_EX_NOPARENTNOTIFY 0 +#define WM_ENTERIDLE 0x0121 +#define WM_PRINT WM_PAINT +#define WM_NCCREATE (0x0081) +#define WM_PARENTNOTIFY 0 +#define WM_NCDESTROY (WM_APP-1) +#ifndef SW_RESTORE +#define SW_RESTORE (SW_SHOWNORMAL) +#endif +#define SW_NORMAL (SW_SHOWNORMAL) +#define WAIT_OBJECT_0 0x00000000L +#define DEFAULT_GUI_FONT SYSTEM_FONT +#ifndef SWP_NOREDRAW +#define SWP_NOREDRAW 0 +#endif +#define WSAGETSELECTEVENT(lParam) LOWORD(lParam) +#define HWND_TOPMOST ((HWND)-1) +#define HWND_NOTOPMOST ((HWND)-2) +#define PS_DOT 2 +#define PD_ALLPAGES 0 +#define PD_USEDEVMODECOPIES 0 +#define PD_NOSELECTION 0 +#define PD_HIDEPRINTTOFILE 0 +#define PD_NOPAGENUMS 0 +#define CF_METAFILEPICT 3 +#define MM_ANISOTROPIC 8 +#define KF_ALTDOWN 0x2000 +#define SPI_GETWORKAREA 48 + +#ifndef WM_SETCURSOR + #define WM_SETCURSOR 0x0020 + #define IDC_ARROW MAKEINTRESOURCE(32512) + #define IDC_IBEAM MAKEINTRESOURCE(32513) + #define IDC_WAIT MAKEINTRESOURCE(32514) + #define IDC_CROSS MAKEINTRESOURCE(32515) + #define IDC_UPARROW MAKEINTRESOURCE(32516) + #define IDC_SIZE MAKEINTRESOURCE(32646) + #define IDC_ICON MAKEINTRESOURCE(32512) + #define IDC_SIZENWSE MAKEINTRESOURCE(32642) + #define IDC_SIZENESW MAKEINTRESOURCE(32643) + #define IDC_SIZEWE MAKEINTRESOURCE(32644) + #define IDC_SIZENS MAKEINTRESOURCE(32645) + #define IDC_SIZEALL MAKEINTRESOURCE(32646) + #define IDC_NO MAKEINTRESOURCE(32648) + #define IDC_APPSTARTING MAKEINTRESOURCE(32650) + #define IDC_HELP MAKEINTRESOURCE(32651) + #define IDC_HAND MAKEINTRESOURCE(32649) +#endif + +#define GMEM_MOVEABLE LMEM_MOVEABLE +#define GPTR LPTR + +// WinCE: CESYSGEN prunes the following FRP defines, +// and INTERNET_TRANSFER_TYPE_ASCII breaks in wininet.h +#undef FTP_TRANSFER_TYPE_ASCII +#define FTP_TRANSFER_TYPE_ASCII 0x00000001 +#undef FTP_TRANSFER_TYPE_BINARY +#define FTP_TRANSFER_TYPE_BINARY 0x00000002 + +typedef DWORD OLE_COLOR; + +// Define the Windows Styles which are not defined by MS +#ifndef WS_POPUPWINDOW +#define WS_POPUPWINDOW WS_POPUP|WS_BORDER|WS_SYSMENU|WS_CAPTION +#endif + +#ifndef WS_OVERLAPPEDWINDOW +#define WS_OVERLAPPEDWINDOW WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX +#endif + +#ifndef WS_TILED +#define WS_TILED WS_OVERLAPPED +#endif + +#ifndef WS_TILEDWINDOW +#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW +#endif + +#ifndef WS_EX_CAPTIONOKBTN +#define WS_EX_CAPTIONOKBTN 0x80000000L +#endif + +#ifndef WS_EX_NODRAG +#define WS_EX_NODRAG 0x40000000L +#endif + +// As Windows CE lacks some standard functions used in Qt, these got +// reimplented. Other projects do this as well and to not fill the +// global namespace with this implementation, prepend qt_wince* and use +// these versions inside of Qt. +// The other declarations available in this file are being used per +// define inside qplatformdefs.h of the corresponding WinCE mkspec. +#define getenv_s(a,b,c,d) qt_wince_getenv_s(a,b,c,d) +#define _putenv_s(a,b) qt_wince__putenv_s(a,b) +#define _getpid() qt_wince__getpid() +#define time_tToFt(a) qt_wince_time_tToFt(a) +#define _getdrive() qt_wince__getdrive() +#define _waccess(a,b) qt_wince__waccess(a,b) +#define _wopen(a,b,c) qt_wince__wopen(a,b,c) +#define _fdopen(a,b) qt_wince__fdopen(a,b) +#define fdopen(a,b) qt_wince_fdopen(a,b) +#define rewind(a) qt_wince_rewind(a) +#define tmpfile() qt_wince_tmpfile() +#define _rename(a,b) qt_wince__rename(a,b) +#define _remove(a) qt_wince__remove(a) +#define SetErrorMode(a) qt_wince_SetErrorMode(a) +#define CoInitialize(a) qt_wince_CoInitialize(a) +#define _chmod(a,b) qt_wince__chmod(a,b) +#define _wchmod(a,b) qt_wince__wchmod(a,b) +#define CreateFileA(a,b,c,d,e,f,g) qt_wince_CreateFileA(a,b,c,d,e,f,g) +#define SetWindowOrgEx(a,b,c,d) qt_wince_SetWindowOrgEx(a,b,c,d) +#define calloc(a,b) qt_wince_calloc(a,b) +#define GetThreadLocale() qt_wince_GetThreadLocale() +#define _beginthread(a,b,c) qt_wince__beginthread(a,b,c) +#define _beginthreadex(a,b,c,d,e,f) qt_wince__beginthreadex(a,b,c,d,e,f) +#define _endthreadex(a) qt_wince__endthreadex(a) +#define bsearch(a,b,c,d,e) qt_wince_bsearch(a,b,c,d,e) + +#ifdef __cplusplus +} // Extern C. +#endif + +#endif // Q_OS_WINCE +#endif // QFUNCTIONS_WCE_H diff --git a/src/corelib/kernel/qmath.h b/src/corelib/kernel/qmath.h new file mode 100644 index 0000000..d8e0230 --- /dev/null +++ b/src/corelib/kernel/qmath.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMATH_H +#define QMATH_H + +#include <math.h> + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +inline int qCeil(qreal v) +{ +#ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return int(ceilf(v)); + else +#endif + return int(ceil(v)); +} + +inline int qFloor(qreal v) +{ +#ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return int(floorf(v)); + else +#endif + return int(floor(v)); +} + +inline qreal qSin(qreal v) +{ +#ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return sinf(v); + else +#endif + return sin(v); +} + +inline qreal qCos(qreal v) +{ +#ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return cosf(v); + else +#endif + return cos(v); +} + +inline qreal qAcos(qreal v) +{ +#ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return acosf(v); + else +#endif + return acos(v); +} + +inline qreal qSqrt(qreal v) +{ +#ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return sqrtf(v); + else +#endif + return sqrt(v); +} + +inline qreal qLn(qreal v) +{ +#ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return logf(v); + else +#endif + return log(v); +} + +inline qreal qPow(qreal x, qreal y) +{ +#ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return powf(x, y); + else +#endif + return pow(x, y); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMATH_H diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp new file mode 100644 index 0000000..719398c --- /dev/null +++ b/src/corelib/kernel/qmetaobject.cpp @@ -0,0 +1,2555 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmetaobject.h" +#include "qmetatype.h" +#include "qobject.h" + +#include <qcoreapplication.h> +#include <qcoreevent.h> +#include <qdatastream.h> +#include <qstringlist.h> +#include <qthread.h> +#include <qvarlengtharray.h> +#include <qvariant.h> +#include <qhash.h> +#include <qdebug.h> +#include <qsemaphore.h> + +#include "private/qobject_p.h" +#include "private/qmetaobject_p.h" + +#include <ctype.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMetaObject + + \brief The QMetaObject class contains meta-information about Qt + objects. + + \ingroup objectmodel + + The Qt \l{Meta-Object System} in Qt is responsible for the + signals and slots inter-object communication mechanism, runtime + type information, and the Qt property system. A single + QMetaObject instance is created for each QObject subclass that is + used in an application, and this instance stores all the + meta-information for the QObject subclass. This object is + available as QObject::metaObject(). + + This class is not normally required for application programming, + but it is useful if you write meta-applications, such as scripting + engines or GUI builders. + + The functions you are most likely to find useful are these: + \list + \o className() returns the name of a class. + \o superClass() returns the superclass's meta-object. + \o method() and methodCount() provide information + about a class's meta-methods (signals, slots and other + \l{Q_INVOKABLE}{invokable} member functions). + \o enumerator() and enumeratorCount() and provide information about + a class's enumerators. + \o propertyCount() and property() provide information about a + class's properties. + \o constructor() and constructorCount() provide information + about a class's meta-constructors. + \endlist + + The index functions indexOfConstructor(), indexOfMethod(), + indexOfEnumerator(), and indexOfProperty() map names of constructors, + member functions, enumerators, or properties to indexes in the + meta-object. For example, Qt uses indexOfMethod() internally when you + connect a signal to a slot. + + Classes can also have a list of \e{name}--\e{value} pairs of + additional class information, stored in QMetaClassInfo objects. + The number of pairs is returned by classInfoCount(), single pairs + are returned by classInfo(), and you can search for pairs with + indexOfClassInfo(). + + \sa QMetaClassInfo, QMetaEnum, QMetaMethod, QMetaProperty, QMetaType, + {Meta-Object System} +*/ + +/*! + \enum QMetaObject::Call + + \internal + + \value InvokeSlot + \value EmitSignal + \value ReadProperty + \value WriteProperty + \value ResetProperty + \value QueryPropertyDesignable + \value QueryPropertyScriptable + \value QueryPropertyStored + \value QueryPropertyEditable + \value QueryPropertyUser + \value CreateInstance +*/ + +/*! + \enum QMetaMethod::Access + + This enum describes the access level of a method, following the conventions used in C++. + + \value Private + \value Protected + \value Public +*/ + +// do not touch without touching the moc as well +enum PropertyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, +// Override = 0x00000200, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000, + Notify = 0x00400000 +}; + +enum MethodFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + AccessMask = 0x03, //mask + + MethodMethod = 0x00, + MethodSignal = 0x04, + MethodSlot = 0x08, + MethodConstructor = 0x0c, + MethodTypeMask = 0x0c, + + MethodCompatibility = 0x10, + MethodCloned = 0x20, + MethodScriptable = 0x40 +}; + +struct QMetaObjectPrivate +{ + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + int enumeratorCount, enumeratorData; + int constructorCount, constructorData; +}; + +static inline const QMetaObjectPrivate *priv(const uint* data) +{ return reinterpret_cast<const QMetaObjectPrivate*>(data); } + + +/*! + \since 4.5 + + Constructs a new instance of this class. You can pass up to ten arguments + (\a val0, \a val1, \a val2, \a val3, \a val4, \a val5, \a val6, \a val7, + \a val8, and \a val9) to the constructor. Returns the new object, or 0 if + no suitable constructor is available. + + Note that only constructors that are declared with the Q_INVOKABLE + modifier are made available through the meta-object system. + + \sa Q_ARG(), constructor() +*/ +QObject *QMetaObject::newInstance(QGenericArgument val0, + QGenericArgument val1, + QGenericArgument val2, + QGenericArgument val3, + QGenericArgument val4, + QGenericArgument val5, + QGenericArgument val6, + QGenericArgument val7, + QGenericArgument val8, + QGenericArgument val9) const +{ + QVarLengthArray<char, 512> sig; + sig.append(className(), qstrlen(className())); + sig.append('('); + + enum { MaximumParamCount = 10 }; + const char *typeNames[] = {val0.name(), val1.name(), val2.name(), val3.name(), val4.name(), + val5.name(), val6.name(), val7.name(), val8.name(), val9.name()}; + + int paramCount; + for (paramCount = 0; paramCount < MaximumParamCount; ++paramCount) { + int len = qstrlen(typeNames[paramCount]); + if (len <= 0) + break; + sig.append(typeNames[paramCount], len); + sig.append(','); + } + if (paramCount == 0) + sig.append(')'); // no parameters + else + sig[sig.size() - 1] = ')'; + sig.append('\0'); + + int idx = indexOfConstructor(sig.constData()); + if (idx < 0) { + QByteArray norm = QMetaObject::normalizedSignature(sig.constData()); + idx = indexOfConstructor(norm.constData()); + } + if (idx < 0) + return 0; + + QVariant ret(QMetaType::QObjectStar, (void*)0); + void *param[] = {ret.data(), val0.data(), val1.data(), val2.data(), val3.data(), val4.data(), + val5.data(), val6.data(), val7.data(), val8.data(), val9.data()}; + + if (static_metacall(CreateInstance, idx, param) >= 0) + return 0; + return *reinterpret_cast<QObject**>(param[0]); +} + +/*! + \internal +*/ +int QMetaObject::static_metacall(Call cl, int idx, void **argv) const +{ + if (priv(d.data)->revision < 2) + return 0; + const QMetaObjectExtraData *extra = (const QMetaObjectExtraData*)(d.extradata); + if (!extra || !extra->static_metacall) + return 0; + return extra->static_metacall(cl, idx, argv); +} + +/*! + \fn const char *QMetaObject::className() const + + Returns the class name. + + \sa superClass() +*/ + +/*! + \fn QMetaObject *QMetaObject::superClass() const + + Returns the meta-object of the superclass, or 0 if there is no + such object. + + \sa className() +*/ + +/*! + \internal + + Returns \a obj if object \a obj inherits from this + meta-object; otherwise returns 0. +*/ +QObject *QMetaObject::cast(QObject *obj) const +{ + if (obj) { + const QMetaObject *m = obj->metaObject(); + do { + if (m == this) + return const_cast<QObject*>(obj); + } while ((m = m->d.superdata)); + } + return 0; +} + +#ifndef QT_NO_TRANSLATION +/*! + \internal +*/ +QString QMetaObject::tr(const char *s, const char *c) const +{ + return QCoreApplication::translate(d.stringdata, s, c, QCoreApplication::CodecForTr); +} + +/*! + \internal +*/ +QString QMetaObject::tr(const char *s, const char *c, int n) const +{ + return QCoreApplication::translate(d.stringdata, s, c, QCoreApplication::CodecForTr, n); +} + +/*! + \internal +*/ +QString QMetaObject::trUtf8(const char *s, const char *c) const +{ + return QCoreApplication::translate(d.stringdata, s, c, QCoreApplication::UnicodeUTF8); +} + +/*! + \internal +*/ +QString QMetaObject::trUtf8(const char *s, const char *c, int n) const +{ + return QCoreApplication::translate(d.stringdata, s, c, QCoreApplication::UnicodeUTF8, n); +} +#endif // QT_NO_TRANSLATION + +/*! + Returns the method offset for this class; i.e. the index position + of this class's first member function. + + The offset is the sum of all the methods in the class's + superclasses (which is always positive since QObject has the + deleteLater() slot and a destroyed() signal). + + \sa method(), methodCount(), indexOfMethod() +*/ +int QMetaObject::methodOffset() const +{ + int offset = 0; + const QMetaObject *m = d.superdata; + while (m) { + offset += priv(m->d.data)->methodCount; + m = m->d.superdata; + } + return offset; +} + + +/*! + Returns the enumerator offset for this class; i.e. the index + position of this class's first enumerator. + + If the class has no superclasses with enumerators, the offset is + 0; otherwise the offset is the sum of all the enumerators in the + class's superclasses. + + \sa enumerator(), enumeratorCount(), indexOfEnumerator() +*/ +int QMetaObject::enumeratorOffset() const +{ + int offset = 0; + const QMetaObject *m = d.superdata; + while (m) { + offset += priv(m->d.data)->enumeratorCount; + m = m->d.superdata; + } + return offset; +} + +/*! + Returns the property offset for this class; i.e. the index + position of this class's first property. + + The offset is the sum of all the properties in the class's + superclasses (which is always positive since QObject has the + name() property). + + \sa property(), propertyCount(), indexOfProperty() +*/ +int QMetaObject::propertyOffset() const +{ + int offset = 0; + const QMetaObject *m = d.superdata; + while (m) { + offset += priv(m->d.data)->propertyCount; + m = m->d.superdata; + } + return offset; +} + +/*! + Returns the class information offset for this class; i.e. the + index position of this class's first class information item. + + If the class has no superclasses with class information, the + offset is 0; otherwise the offset is the sum of all the class + information items in the class's superclasses. + + \sa classInfo(), classInfoCount(), indexOfClassInfo() +*/ +int QMetaObject::classInfoOffset() const +{ + int offset = 0; + const QMetaObject *m = d.superdata; + while (m) { + offset += priv(m->d.data)->classInfoCount; + m = m->d.superdata; + } + return offset; +} + +/*! + \since 4.5 + + Returns the number of constructors in this class. + + \sa constructor(), indexOfConstructor() +*/ +int QMetaObject::constructorCount() const +{ + if (priv(d.data)->revision < 2) + return 0; + return priv(d.data)->constructorCount; +} + +/*! + Returns the number of methods in this class, including the number of + properties provided by each base class. These include signals and slots + as well as normal member functions. + + Use code like the following to obtain a QStringList containing the methods + specific to a given class: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp methodCount + + \sa method(), methodOffset(), indexOfMethod() +*/ +int QMetaObject::methodCount() const +{ + int n = priv(d.data)->methodCount; + const QMetaObject *m = d.superdata; + while (m) { + n += priv(m->d.data)->methodCount; + m = m->d.superdata; + } + return n; +} + +/*! + Returns the number of enumerators in this class. + + \sa enumerator(), enumeratorOffset(), indexOfEnumerator() +*/ +int QMetaObject::enumeratorCount() const +{ + int n = priv(d.data)->enumeratorCount; + const QMetaObject *m = d.superdata; + while (m) { + n += priv(m->d.data)->enumeratorCount; + m = m->d.superdata; + } + return n; +} + +/*! + Returns the number of properties in this class, including the number of + properties provided by each base class. + + Use code like the following to obtain a QStringList containing the properties + specific to a given class: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp propertyCount + + \sa property(), propertyOffset(), indexOfProperty() +*/ +int QMetaObject::propertyCount() const +{ + int n = priv(d.data)->propertyCount; + const QMetaObject *m = d.superdata; + while (m) { + n += priv(m->d.data)->propertyCount; + m = m->d.superdata; + } + return n; +} + +/*! + Returns the number of items of class information in this class. + + \sa classInfo(), classInfoOffset(), indexOfClassInfo() +*/ +int QMetaObject::classInfoCount() const +{ + int n = priv(d.data)->classInfoCount; + const QMetaObject *m = d.superdata; + while (m) { + n += priv(m->d.data)->classInfoCount; + m = m->d.superdata; + } + return n; +} + +/*! + \since 4.5 + + Finds \a constructor and returns its index; otherwise returns -1. + + Note that the \a constructor has to be in normalized form, as returned + by normalizedSignature(). + + \sa constructor(), constructorCount(), normalizedSignature() +*/ +int QMetaObject::indexOfConstructor(const char *constructor) const +{ + if (priv(d.data)->revision < 2) + return -1; + for (int i = priv(d.data)->constructorCount-1; i >= 0; --i) { + if (strcmp(constructor, d.stringdata + + d.data[priv(d.data)->constructorData + 5*i]) == 0) { + return i; + } + } + return -1; +} + +/*! + Finds \a method and returns its index; otherwise returns -1. + + Note that the \a method has to be in normalized form, as returned + by normalizedSignature(). + + \sa method(), methodCount(), methodOffset(), normalizedSignature() +*/ +int QMetaObject::indexOfMethod(const char *method) const +{ + int i = -1; + const QMetaObject *m = this; + while (m && i < 0) { + for (i = priv(m->d.data)->methodCount-1; i >= 0; --i) + if (strcmp(method, m->d.stringdata + + m->d.data[priv(m->d.data)->methodData + 5*i]) == 0) { + i += m->methodOffset(); + break; + } + m = m->d.superdata; + } + return i; +} + +/*! + Finds \a signal and returns its index; otherwise returns -1. + + This is the same as indexOfMethod(), except that it will return + -1 if the method exists but isn't a signal. + + Note that the \a signal has to be in normalized form, as returned + by normalizedSignature(). + + \sa indexOfMethod(), normalizedSignature(), method(), methodCount(), methodOffset() +*/ +int QMetaObject::indexOfSignal(const char *signal) const +{ + int i = -1; + const QMetaObject *m = this; + while (m && i < 0) { + for (i = priv(m->d.data)->methodCount-1; i >= 0; --i) + if ((m->d.data[priv(m->d.data)->methodData + 5*i + 4] & MethodTypeMask) == MethodSignal + && strcmp(signal, m->d.stringdata + + m->d.data[priv(m->d.data)->methodData + 5*i]) == 0) { + i += m->methodOffset(); + break; + } + m = m->d.superdata; + } +#ifndef QT_NO_DEBUG + if (i >= 0 && m && m->d.superdata) { + int conflict = m->d.superdata->indexOfMethod(signal); + if (conflict >= 0) + qWarning("QMetaObject::indexOfSignal:%s: Conflict with %s::%s", + m->d.stringdata, m->d.superdata->d.stringdata, signal); + } +#endif + return i; +} + +/*! + Finds \a slot and returns its index; otherwise returns -1. + + This is the same as indexOfMethod(), except that it will return + -1 if the method exists but isn't a slot. + + \sa indexOfMethod(), method(), methodCount(), methodOffset() +*/ +int QMetaObject::indexOfSlot(const char *slot) const +{ + int i = -1; + const QMetaObject *m = this; + while (m && i < 0) { + for (i = priv(m->d.data)->methodCount-1; i >= 0; --i) + if ((m->d.data[priv(m->d.data)->methodData + 5*i + 4] & MethodTypeMask) == MethodSlot + && strcmp(slot, m->d.stringdata + + m->d.data[priv(m->d.data)->methodData + 5*i]) == 0) { + i += m->methodOffset(); + break; + } + m = m->d.superdata; + } + return i; +} + +static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, const char *name) +{ + while (self) { + if (strcmp(self->d.stringdata, name) == 0) + return self; + if (self->d.extradata) { + const QMetaObject **e; + if (priv(self->d.data)->revision < 2) { + e = (const QMetaObject**)(self->d.extradata); + } else { + const QMetaObjectExtraData *extra = (const QMetaObjectExtraData*)(self->d.extradata); + e = extra->objects; + } + if (e) { + while (*e) { + if (const QMetaObject *m =QMetaObject_findMetaObject((*e), name)) + return m; + ++e; + } + } + } + self = self->d.superdata; + } + return self; +} + +/*! + Finds enumerator \a name and returns its index; otherwise returns + -1. + + \sa enumerator(), enumeratorCount(), enumeratorOffset() +*/ +int QMetaObject::indexOfEnumerator(const char *name) const +{ + int i = -1; + const QMetaObject *m = this; + while (m && i < 0) { + for (i = priv(m->d.data)->enumeratorCount-1; i >= 0; --i) + if (strcmp(name, m->d.stringdata + + m->d.data[priv(m->d.data)->enumeratorData + 4*i]) == 0) { + i += m->enumeratorOffset(); + break; + } + m = m->d.superdata; + } + return i; +} + +/*! + Finds property \a name and returns its index; otherwise returns + -1. + + \sa property(), propertyCount(), propertyOffset() +*/ +int QMetaObject::indexOfProperty(const char *name) const +{ + int i = -1; + const QMetaObject *m = this; + while (m && i < 0) { + for (i = priv(m->d.data)->propertyCount-1; i >= 0; --i) + if (strcmp(name, m->d.stringdata + + m->d.data[priv(m->d.data)->propertyData + 3*i]) == 0) { + i += m->propertyOffset(); + break; + } + m = m->d.superdata; + } + return i; +} + +/*! + Finds class information item \a name and returns its index; + otherwise returns -1. + + \sa classInfo(), classInfoCount(), classInfoOffset() +*/ +int QMetaObject::indexOfClassInfo(const char *name) const +{ + int i = -1; + const QMetaObject *m = this; + while (m && i < 0) { + for (i = priv(m->d.data)->classInfoCount-1; i >= 0; --i) + if (strcmp(name, m->d.stringdata + + m->d.data[priv(m->d.data)->classInfoData + 2*i]) == 0) { + i += m->classInfoOffset(); + break; + } + m = m->d.superdata; + } + return i; +} + +/*! + \since 4.5 + + Returns the meta-data for the constructor with the given \a index. + + \sa constructorCount(), newInstance() +*/ +QMetaMethod QMetaObject::constructor(int index) const +{ + int i = index; + QMetaMethod result; + if (priv(d.data)->revision >= 2 && i >= 0 && i < priv(d.data)->constructorCount) { + result.mobj = this; + result.handle = priv(d.data)->constructorData + 5*i; + } + return result; +} + +/*! + Returns the meta-data for the method with the given \a index. + + \sa methodCount(), methodOffset(), indexOfMethod() +*/ +QMetaMethod QMetaObject::method(int index) const +{ + int i = index; + i -= methodOffset(); + if (i < 0 && d.superdata) + return d.superdata->method(index); + + QMetaMethod result; + if (i >= 0 && i < priv(d.data)->methodCount) { + result.mobj = this; + result.handle = priv(d.data)->methodData + 5*i; + } + return result; +} + +/*! + Returns the meta-data for the enumerator with the given \a index. + + \sa enumeratorCount(), enumeratorOffset(), indexOfEnumerator() +*/ +QMetaEnum QMetaObject::enumerator(int index) const +{ + int i = index; + i -= enumeratorOffset(); + if (i < 0 && d.superdata) + return d.superdata->enumerator(index); + + QMetaEnum result; + if (i >= 0 && i < priv(d.data)->enumeratorCount) { + result.mobj = this; + result.handle = priv(d.data)->enumeratorData + 4*i; + } + return result; +} + +/*! + Returns the meta-data for the property with the given \a index. + If no such property exists, a null QMetaProperty is returned. + + \sa propertyCount(), propertyOffset(), indexOfProperty() +*/ +QMetaProperty QMetaObject::property(int index) const +{ + int i = index; + i -= propertyOffset(); + if (i < 0 && d.superdata) + return d.superdata->property(index); + + QMetaProperty result; + if (i >= 0 && i < priv(d.data)->propertyCount) { + int handle = priv(d.data)->propertyData + 3*i; + int flags = d.data[handle + 2]; + const char *type = d.stringdata + d.data[handle + 1]; + result.mobj = this; + result.handle = handle; + result.idx = i; + + if (flags & EnumOrFlag) { + result.menum = enumerator(indexOfEnumerator(type)); + if (!result.menum.isValid()) { + QByteArray enum_name = type; + QByteArray scope_name = d.stringdata; + int s = enum_name.lastIndexOf("::"); + if (s > 0) { + scope_name = enum_name.left(s); + enum_name = enum_name.mid(s + 2); + } + const QMetaObject *scope = 0; + if (scope_name == "Qt") + scope = &QObject::staticQtMetaObject; + else + scope = QMetaObject_findMetaObject(this, scope_name); + if (scope) + result.menum = scope->enumerator(scope->indexOfEnumerator(enum_name)); + } + } + } + return result; +} + +/*! + \since 4.2 + + Returns the property that has the \c USER flag set to true. + + \sa QMetaProperty::isUser() +*/ +QMetaProperty QMetaObject::userProperty() const +{ + const int propCount = propertyCount(); + for (int i = propCount - 1; i >= 0; --i) { + const QMetaProperty prop = property(i); + if (prop.isUser()) + return prop; + } + return QMetaProperty(); +} + +/*! + Returns the meta-data for the item of class information with the + given \a index. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp 0 + + \sa classInfoCount(), classInfoOffset(), indexOfClassInfo() + */ +QMetaClassInfo QMetaObject::classInfo(int index) const +{ + int i = index; + i -= classInfoOffset(); + if (i < 0 && d.superdata) + return d.superdata->classInfo(index); + + QMetaClassInfo result; + if (i >= 0 && i < priv(d.data)->classInfoCount) { + result.mobj = this; + result.handle = priv(d.data)->classInfoData + 2*i; + } + return result; +} + +/*! + Returns true if the \a signal and \a method arguments are + compatible; otherwise returns false. + + Both \a signal and \a method are expected to be normalized. + + \sa normalizedSignature() +*/ +bool QMetaObject::checkConnectArgs(const char *signal, const char *method) +{ + const char *s1 = signal; + const char *s2 = method; + while (*s1++ != '(') { } // scan to first '(' + while (*s2++ != '(') { } + if (*s2 == ')' || qstrcmp(s1,s2) == 0) // method has no args or + return true; // exact match + int s1len = qstrlen(s1); + int s2len = qstrlen(s2); + if (s2len < s1len && strncmp(s1,s2,s2len-1)==0 && s1[s2len-1]==',') + return true; // method has less args + return false; +} + +static void qRemoveWhitespace(const char *s, char *d) +{ + char last = 0; + while (*s && is_space(*s)) + s++; + while (*s) { + while (*s && !is_space(*s)) + last = *d++ = *s++; + while (*s && is_space(*s)) + s++; + if (*s && ((is_ident_char(*s) && is_ident_char(last)) + || ((*s == ':') && (last == '<')))) { + last = *d++ = ' '; + } + } + *d = '\0'; +} + +static char *qNormalizeType(char *d, int &templdepth, QByteArray &result) +{ + const char *t = d; + while (*d && (templdepth + || (*d != ',' && *d != ')'))) { + if (*d == '<') + ++templdepth; + if (*d == '>') + --templdepth; + ++d; + } + if (strncmp("void", t, d - t) != 0) + result += normalizeTypeInternal(t, d); + + return d; +} + + +/*! + \since 4.2 + + Normalizes a \a type. + + See QMetaObject::normalizedSignature() for a description on how + Qt normalizes. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp 1 + + \sa normalizedSignature() + */ +QByteArray QMetaObject::normalizedType(const char *type) +{ + QByteArray result; + + if (!type || !*type) + return result; + + QVarLengthArray<char> stackbuf((int)strlen(type)); + qRemoveWhitespace(type, stackbuf.data()); + int templdepth = 0; + qNormalizeType(stackbuf.data(), templdepth, result); + + return result; +} + +/*! + Normalizes the signature of the given \a method. + + Qt uses normalized signatures to decide whether two given signals + and slots are compatible. Normalization reduces whitespace to a + minimum, moves 'const' to the front where appropriate, removes + 'const' from value types and replaces const references with + values. + + \sa checkConnectArgs(), normalizedType() + */ +QByteArray QMetaObject::normalizedSignature(const char *method) +{ + QByteArray result; + if (!method || !*method) + return result; + int len = int(strlen(method)); + char stackbuf[64]; + char *buf = (len >= 64 ? new char[len+1] : stackbuf); + qRemoveWhitespace(method, buf); + char *d = buf; + + result.reserve(len); + + int argdepth = 0; + int templdepth = 0; + while (*d) { + if (argdepth == 1) + d = qNormalizeType(d, templdepth, result); + if (*d == '(') + ++argdepth; + if (*d == ')') + --argdepth; + result += *d++; + } + + if (buf != stackbuf) + delete [] buf; + return result; +} + +enum { MaximumParamCount = 11 }; // up to 10 arguments + 1 return value + +/*! + Invokes the \a member (a signal or a slot name) on the object \a + obj. Returns true if the member could be invoked. Returns false + if there is no such member or the parameters did not match. + + The invocation can be either synchronous or asynchronous, + depending on \a type: + + \list + \o If \a type is Qt::DirectConnection, the member will be invoked immediately. + + \o If \a type is Qt::QueuedConnection, + a QEvent will be sent and the member is invoked as soon as the application + enters the main event loop. + + \o If \a type is Qt::AutoConnection, the member is invoked + synchronously if \a obj lives in the same thread as the + caller; otherwise it will invoke the member asynchronously. + \endlist + + The return value of the \a member function call is placed in \a + ret. If the invocation is asynchronous, the return value cannot + be evaluated. You can pass up to ten arguments (\a val0, \a val1, + \a val2, \a val3, \a val4, \a val5, \a val6, \a val7, \a val8, + and \a val9) to the \a member function. + + QGenericArgument and QGenericReturnArgument are internal + helper classes. Because signals and slots can be dynamically + invoked, you must enclose the arguments using the Q_ARG() and + Q_RETURN_ARG() macros. Q_ARG() takes a type name and a + const reference of that type; Q_RETURN_ARG() takes a type name + and a non-const reference. + + You only need to pass the name of the signal or slot to this function, + not the entire signature. For example, to asynchronously invoke + the \l{QPushButton::animateClick()}{animateClick()} slot on a + QPushButton, use the following code: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp 2 + + With asynchronous method invocations, the parameters must be of + types that are known to Qt's meta-object system, because Qt needs + to copy the arguments to store them in an event behind the + scenes. If you try to use a queued connection and get the error + message + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp 3 + + call qRegisterMetaType() to register the data type before you + call invokeMethod(). + + To synchronously invoke the \c compute(QString, int, double) slot on + some arbitrary object \c obj retrieve its return value: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp 4 + + If the "compute" slot does not take exactly one QString, one int + and one double in the specified order, the call will fail. + + \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaMethod::invoke() +*/ +bool QMetaObject::invokeMethod(QObject *obj, + const char *member, + Qt::ConnectionType type, + QGenericReturnArgument ret, + QGenericArgument val0, + QGenericArgument val1, + QGenericArgument val2, + QGenericArgument val3, + QGenericArgument val4, + QGenericArgument val5, + QGenericArgument val6, + QGenericArgument val7, + QGenericArgument val8, + QGenericArgument val9) +{ + if (!obj) + return false; + + QVarLengthArray<char, 512> sig; + int len = qstrlen(member); + if (len <= 0) + return false; + sig.append(member, len); + sig.append('('); + + const char *typeNames[] = {ret.name(), val0.name(), val1.name(), val2.name(), val3.name(), + val4.name(), val5.name(), val6.name(), val7.name(), val8.name(), + val9.name()}; + + int paramCount; + for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) { + len = qstrlen(typeNames[paramCount]); + if (len <= 0) + break; + sig.append(typeNames[paramCount], len); + sig.append(','); + } + if (paramCount == 1) + sig.append(')'); // no parameters + else + sig[sig.size() - 1] = ')'; + sig.append('\0'); + + int idx = obj->metaObject()->indexOfMethod(sig.constData()); + if (idx < 0) { + QByteArray norm = QMetaObject::normalizedSignature(sig.constData()); + idx = obj->metaObject()->indexOfMethod(norm.constData()); + } + + if (idx < 0 || idx >= obj->metaObject()->methodCount()) + return false; + QMetaMethod method = obj->metaObject()->method(idx); + return method.invoke(obj, type, ret, + val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); +} + +/*! \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member, + QGenericReturnArgument ret, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()); + \overload invokeMethod() + + This overload always invokes the member using the connection type Qt::AutoConnection. +*/ + +/*! \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member, + Qt::ConnectionType type, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) + + \overload invokeMethod() + + This overload can be used if the return value of the member is of no interest. +*/ + +/*! + \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) + + \overload invokeMethod() + + This overload invokes the member using the connection type Qt::AutoConnection and + ignores return values. +*/ + +/*! + \class QMetaMethod + + \brief The QMetaMethod class provides meta-data about a member + function. + + \ingroup objectmodel + + A QMetaMethod has a methodType(), a signature(), a list of + parameterTypes() and parameterNames(), a return typeName(), a + tag(), and an access() specifier. You can use invoke() to invoke + the method on an arbitrary QObject. + + \sa QMetaObject, QMetaEnum, QMetaProperty, {Qt's Property System} +*/ + +/*! + \enum QMetaMethod::Attributes + + \internal + + \value Compatibility + \value Cloned + \value Scriptable +*/ + +/*! + \fn const QMetaObject *QMetaMethod::enclosingMetaObject() const + \internal +*/ + +/*! + \enum QMetaMethod::MethodType + + \value Method The function is a plain member function. + \value Signal The function is a signal. + \value Slot The function is a slot. + \value Constructor The function is a constructor. +*/ + +/*! + \fn QMetaMethod::QMetaMethod() + \internal +*/ + +/*! + Returns the signature of this method (e.g., + \c{setValue(double)}). + + \sa parameterTypes(), parameterNames() +*/ +const char *QMetaMethod::signature() const +{ + if (!mobj) + return 0; + return mobj->d.stringdata + mobj->d.data[handle]; +} + +/*! + Returns a list of parameter types. + + \sa parameterNames(), signature() +*/ +QList<QByteArray> QMetaMethod::parameterTypes() const +{ + QList<QByteArray> list; + if (!mobj) + return list; + const char *signature = mobj->d.stringdata + mobj->d.data[handle]; + while (*signature && *signature != '(') + ++signature; + while (*signature && *signature != ')' && *++signature != ')') { + const char *begin = signature; + int level = 0; + while (*signature && (level > 0 || *signature != ',') && *signature != ')') { + if (*signature == '<') + ++level; + else if (*signature == '>') + --level; + ++signature; + } + list += QByteArray(begin, signature - begin); + } + return list; +} + +/*! + Returns a list of parameter names. + + \sa parameterTypes(), signature() +*/ +QList<QByteArray> QMetaMethod::parameterNames() const +{ + QList<QByteArray> list; + if (!mobj) + return list; + const char *names = mobj->d.stringdata + mobj->d.data[handle + 1]; + if (*names == 0) { + // do we have one or zero arguments? + const char *signature = mobj->d.stringdata + mobj->d.data[handle]; + while (*signature && *signature != '(') + ++signature; + if (*++signature != ')') + list += QByteArray(); + } else { + --names; + do { + const char *begin = ++names; + while (*names && *names != ',') + ++names; + list += QByteArray(begin, names - begin); + } while (*names); + } + return list; +} + + +/*! + Returns the return type of this method, or an empty string if the + return type is \e void. +*/ +const char *QMetaMethod::typeName() const +{ + if (!mobj) + return 0; + return mobj->d.stringdata + mobj->d.data[handle + 2]; +} + +/*! + Returns the tag associated with this method. + + Tags are special macros recognized by \c moc that make it + possible to add extra information about a method. For the moment, + \c moc doesn't support any special tags. +*/ +const char *QMetaMethod::tag() const +{ + if (!mobj) + return 0; + return mobj->d.stringdata + mobj->d.data[handle + 3]; +} + + +/*! \internal */ +int QMetaMethod::attributes() const +{ + if (!mobj) + return false; + return ((mobj->d.data[handle + 4])>>4); +} + +/*! + Returns the access specification of this method (private, + protected, or public). + + Signals are always protected, meaning that you can only emit them + from the class or from a subclass. + + \sa methodType() +*/ +QMetaMethod::Access QMetaMethod::access() const +{ + if (!mobj) + return Private; + return (QMetaMethod::Access)(mobj->d.data[handle + 4] & AccessMask); +} + +/*! + Returns the type of this method (signal, slot, or method). + + \sa access() +*/ +QMetaMethod::MethodType QMetaMethod::methodType() const +{ + if (!mobj) + return QMetaMethod::Method; + return (QMetaMethod::MethodType)((mobj->d.data[handle + 4] & MethodTypeMask)>>2); +} + +/*! + Invokes this method on the object \a object. Returns true if the member could be invoked. + Returns false if there is no such member or the parameters did not match. + + The invocation can be either synchronous or asynchronous, depending on the + \a connectionType: + + \list + \o If \a connectionType is Qt::DirectConnection, the member will be invoked immediately. + + \o If \a connectionType is Qt::QueuedConnection, + a QEvent will be posted and the member is invoked as soon as the application + enters the main event loop. + + \o If \a connectionType is Qt::AutoConnection, the member is invoked + synchronously if \a object lives in the same thread as the + caller; otherwise it will invoke the member asynchronously. + \endlist + + The return value of this method call is placed in \a + returnValue. If the invocation is asynchronous, the return value cannot + be evaluated. You can pass up to ten arguments (\a val0, \a val1, + \a val2, \a val3, \a val4, \a val5, \a val6, \a val7, \a val8, + and \a val9) to this method call. + + QGenericArgument and QGenericReturnArgument are internal + helper classes. Because signals and slots can be dynamically + invoked, you must enclose the arguments using the Q_ARG() and + Q_RETURN_ARG() macros. Q_ARG() takes a type name and a + const reference of that type; Q_RETURN_ARG() takes a type name + and a non-const reference. + + To asynchronously invoke the + \l{QPushButton::animateClick()}{animateClick()} slot on a + QPushButton: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp 6 + + With asynchronous method invocations, the parameters must be of + types that are known to Qt's meta-object system, because Qt needs + to copy the arguments to store them in an event behind the + scenes. If you try to use a queued connection and get the error + message + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp 7 + + call qRegisterMetaType() to register the data type before you + call QMetaMethod::invoke(). + + To synchronously invoke the \c compute(QString, int, double) slot on + some arbitrary object \c obj retrieve its return value: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp 8 + + QMetaObject::normalizedSignature() is used here to ensure that the format + of the signature is what invoke() expects. E.g. extra whitespace is + removed. + + If the "compute" slot does not take exactly one QString, one int + and one double in the specified order, the call will fail. + + \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod() +*/ +bool QMetaMethod::invoke(QObject *object, + Qt::ConnectionType connectionType, + QGenericReturnArgument returnValue, + QGenericArgument val0, + QGenericArgument val1, + QGenericArgument val2, + QGenericArgument val3, + QGenericArgument val4, + QGenericArgument val5, + QGenericArgument val6, + QGenericArgument val7, + QGenericArgument val8, + QGenericArgument val9) const +{ + if (!object || !mobj) + return false; + + // check return type + if (returnValue.data()) { + const char *retType = typeName(); + if (qstrcmp(returnValue.name(), retType) != 0) { + // normalize the return value as well + // the trick here is to make a function signature out of the return type + // so that we can call normalizedSignature() and avoid duplicating code + QByteArray unnormalized; + int len = qstrlen(returnValue.name()); + + unnormalized.reserve(len + 3); + unnormalized = "_("; // the function is called "_" + unnormalized.append(returnValue.name()); + unnormalized.append(')'); + + QByteArray normalized = QMetaObject::normalizedSignature(unnormalized.constData()); + normalized.truncate(normalized.length() - 1); // drop the ending ')' + + if (qstrcmp(normalized.constData() + 2, retType) != 0) + return false; + } + } + + // check argument count (we don't allow invoking a method if given too few arguments) + const char *typeNames[] = { + returnValue.name(), + val0.name(), + val1.name(), + val2.name(), + val3.name(), + val4.name(), + val5.name(), + val6.name(), + val7.name(), + val8.name(), + val9.name() + }; + int paramCount; + for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) { + if (qstrlen(typeNames[paramCount]) <= 0) + break; + } + int metaMethodArgumentCount = 0; + { + // based on QMetaObject::parameterNames() + const char *names = mobj->d.stringdata + mobj->d.data[handle + 1]; + if (*names == 0) { + // do we have one or zero arguments? + const char *signature = mobj->d.stringdata + mobj->d.data[handle]; + while (*signature && *signature != '(') + ++signature; + if (*++signature != ')') + ++metaMethodArgumentCount; + } else { + --names; + do { + ++names; + while (*names && *names != ',') + ++names; + ++metaMethodArgumentCount; + } while (*names); + } + } + if (paramCount <= metaMethodArgumentCount) + return false; + + // check connection type + QThread *currentThread = QThread::currentThread(); + QThread *objectThread = object->thread(); + if (connectionType == Qt::AutoConnection) { + connectionType = currentThread == objectThread + ? Qt::DirectConnection + : Qt::QueuedConnection; + } + + // invoke! + void *param[] = { + returnValue.data(), + val0.data(), + val1.data(), + val2.data(), + val3.data(), + val4.data(), + val5.data(), + val6.data(), + val7.data(), + val8.data(), + val9.data() + }; + // recompute the methodIndex by reversing the arithmetic in QMetaObject::property() + int methodIndex = ((handle - priv(mobj->d.data)->methodData) / 5) + mobj->methodOffset(); + if (connectionType == Qt::DirectConnection) { + return object->qt_metacall(QMetaObject::InvokeMetaMethod, methodIndex, param) < 0; + } else { + if (returnValue.data()) { + qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in " + "queued connections"); + return false; + } + + int nargs = 1; // include return type + void **args = (void **) qMalloc(paramCount * sizeof(void *)); + int *types = (int *) qMalloc(paramCount * sizeof(int)); + types[0] = 0; // return type + args[0] = 0; + + for (int i = 1; i < paramCount; ++i) { + types[i] = QMetaType::type(typeNames[i]); + if (types[i]) { + args[i] = QMetaType::construct(types[i], param[i]); + ++nargs; + } else if (param[i]) { + qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'", + typeNames[i]); + for (int x = 1; x < i; ++x) { + if (types[x] && args[x]) + QMetaType::destroy(types[x], args[x]); + } + qFree(types); + qFree(args); + return false; + } + } + + if (connectionType == Qt::QueuedConnection) { + QCoreApplication::postEvent(object, new QMetaCallEvent(methodIndex, + 0, + -1, + nargs, + types, + args)); + } else { + if (currentThread == objectThread) { + qWarning("QMetaMethod::invoke: Dead lock detected in " + "BlockingQueuedConnection: Receiver is %s(%p)", + mobj->className(), object); + } + + // blocking queued connection +#ifdef QT_NO_THREAD + QCoreApplication::postEvent(object, new QMetaCallEvent(methodIndex, + 0, + -1, + nargs, + types, + args)); +#else + QSemaphore semaphore; + QCoreApplication::postEvent(object, new QMetaCallEvent(methodIndex, + 0, + -1, + nargs, + types, + args, + &semaphore)); + semaphore.acquire(); +#endif // QT_NO_THREAD + } + } + return true; +} + +/*! \fn bool QMetaMethod::invoke(QObject *object, + QGenericReturnArgument returnValue, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) const + \overload invoke() + + This overload always invokes this method using the connection type Qt::AutoConnection. +*/ + +/*! \fn bool QMetaMethod::invoke(QObject *object, + Qt::ConnectionType connectionType, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) const + + \overload invoke() + + This overload can be used if the return value of the member is of no interest. +*/ + +/*! + \fn bool QMetaMethod::invoke(QObject *object, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) const + + \overload invoke() + + This overload invokes this method using the + connection type Qt::AutoConnection and ignores return values. +*/ + +/*! + \class QMetaEnum + \brief The QMetaEnum class provides meta-data about an enumerator. + + \ingroup objectmodel + + Use name() for the enumerator's name. The enumerator's keys (names + of each enumerated item) are returned by key(); use keyCount() to find + the number of keys. isFlag() returns whether the enumerator is + meant to be used as a flag, meaning that its values can be combined + using the OR operator. + + The conversion functions keyToValue(), valueToKey(), keysToValue(), + and valueToKeys() allow conversion between the integer + representation of an enumeration or set value and its literal + representation. The scope() function returns the class scope this + enumerator was declared in. + + \sa QMetaObject, QMetaMethod, QMetaProperty +*/ + +/*! + \fn bool QMetaEnum::isValid() const + + Returns true if this enum is valid (has a name); otherwise returns + false. + + \sa name() +*/ + +/*! + \fn const QMetaObject *QMetaEnum::enclosingMetaObject() const + \internal +*/ + + +/*! + \fn QMetaEnum::QMetaEnum() + \internal +*/ + +/*! + Returns the name of the enumerator (without the scope). + + For example, the Qt::AlignmentFlag enumeration has \c + AlignmentFlag as the name and \l Qt as the scope. + + \sa isValid(), scope() +*/ +const char *QMetaEnum::name() const +{ + if (!mobj) + return 0; + return mobj->d.stringdata + mobj->d.data[handle]; +} + +/*! + Returns the number of keys. + + \sa key() +*/ +int QMetaEnum::keyCount() const +{ + if (!mobj) + return 0; + return mobj->d.data[handle + 2]; +} + + +/*! + Returns the key with the given \a index, or 0 if no such key exists. + + \sa keyCount(), value(), valueToKey() +*/ +const char *QMetaEnum::key(int index) const +{ + if (!mobj) + return 0; + int count = mobj->d.data[handle + 2]; + int data = mobj->d.data[handle + 3]; + if (index >= 0 && index < count) + return mobj->d.stringdata + mobj->d.data[data + 2*index]; + return 0; +} + +/*! + Returns the value with the given \a index; or returns -1 if there + is no such value. + + \sa keyCount(), key(), keyToValue() +*/ +int QMetaEnum::value(int index) const +{ + if (!mobj) + return 0; + int count = mobj->d.data[handle + 2]; + int data = mobj->d.data[handle + 3]; + if (index >= 0 && index < count) + return mobj->d.data[data + 2*index + 1]; + return -1; +} + + +/*! + Returns true if this enumerator is used as a flag; otherwise returns + false. + + When used as flags, enumerators can be combined using the OR + operator. + + \sa keysToValue(), valueToKeys() +*/ +bool QMetaEnum::isFlag() const +{ + return mobj && mobj->d.data[handle + 1]; +} + + +/*! + Returns the scope this enumerator was declared in. + + For example, the Qt::AlignmentFlag enumeration has \c Qt as + the scope and \c AlignmentFlag as the name. + + \sa name() +*/ +const char *QMetaEnum::scope() const +{ + return mobj?mobj->d.stringdata : 0; +} + +/*! + Returns the integer value of the given enumeration \a key, or -1 + if \a key is not defined. + + For flag types, use keysToValue(). + + \sa valueToKey(), isFlag(), keysToValue() +*/ +int QMetaEnum::keyToValue(const char *key) const +{ + if (!mobj || !key) + return -1; + uint scope = 0; + const char *qualified_key = key; + const char *s = key + qstrlen(key); + while (s > key && *s != ':') + --s; + if (s > key && *(s-1)==':') { + scope = s - key - 1; + key += scope + 2; + } + int count = mobj->d.data[handle + 2]; + int data = mobj->d.data[handle + 3]; + for (int i = 0; i < count; ++i) + if ((!scope || (qstrlen(mobj->d.stringdata) == scope && strncmp(qualified_key, mobj->d.stringdata, scope) == 0)) + && strcmp(key, mobj->d.stringdata + mobj->d.data[data + 2*i]) == 0) + return mobj->d.data[data + 2*i + 1]; + return -1; +} + +/*! + Returns the string that is used as the name of the given + enumeration \a value, or 0 if \a value is not defined. + + For flag types, use valueToKeys(). + + \sa isFlag(), valueToKeys() +*/ +const char* QMetaEnum::valueToKey(int value) const +{ + if (!mobj) + return 0; + int count = mobj->d.data[handle + 2]; + int data = mobj->d.data[handle + 3]; + for (int i = 0; i < count; ++i) + if (value == (int)mobj->d.data[data + 2*i + 1]) + return mobj->d.stringdata + mobj->d.data[data + 2*i]; + return 0; +} + +/*! + Returns the value derived from combining together the values of + the \a keys using the OR operator, or -1 if \a keys is not + defined. Note that the strings in \a keys must be '|'-separated. + + \sa isFlag(), valueToKey(), valueToKeys() +*/ +int QMetaEnum::keysToValue(const char *keys) const +{ + if (!mobj) + return -1; + QStringList l = QString::fromLatin1(keys).split(QLatin1Char('|')); + //#### TODO write proper code, do not use QStringList + int value = 0; + int count = mobj->d.data[handle + 2]; + int data = mobj->d.data[handle + 3]; + for (int li = 0; li < l.size(); ++li) { + QString trimmed = l.at(li).trimmed(); + QByteArray qualified_key = trimmed.toLatin1(); + const char *key = qualified_key.constData(); + uint scope = 0; + const char *s = key + qstrlen(key); + while (s > key && *s != ':') + --s; + if (s > key && *(s-1)==':') { + scope = s - key - 1; + key += scope + 2; + } + int i; + for (i = count-1; i >= 0; --i) + if ((!scope || (qstrlen(mobj->d.stringdata) == scope && strncmp(qualified_key.constData(), mobj->d.stringdata, scope) == 0)) + && strcmp(key, mobj->d.stringdata + mobj->d.data[data + 2*i]) == 0) { + value |= mobj->d.data[data + 2*i + 1]; + break; + } + if (i < 0) + value |= -1; + } + return value; +} + +/*! + Returns a byte array of '|'-separated keys that represents the + given \a value. + + \sa isFlag(), valueToKey(), keysToValue() +*/ +QByteArray QMetaEnum::valueToKeys(int value) const +{ + QByteArray keys; + if (!mobj) + return keys; + int count = mobj->d.data[handle + 2]; + int data = mobj->d.data[handle + 3]; + int v = value; + for(int i = 0; i < count; i++) { + int k = mobj->d.data[data + 2*i + 1]; + if ((k != 0 && (v & k) == k ) || (k == value)) { + v = v & ~k; + if (!keys.isEmpty()) + keys += '|'; + keys += mobj->d.stringdata + mobj->d.data[data + 2*i]; + } + } + return keys; +} + +static QByteArray qualifiedName(const QMetaEnum &e) +{ + return QByteArray(e.scope()) + "::" + e.name(); +} + +/*! + \class QMetaProperty + \brief The QMetaProperty class provides meta-data about a property. + + \ingroup objectmodel + + A property has a name() and a type(), as well as various + attributes that specify its behavior: isReadable(), isWritable(), + isDesignable(), isScriptable(), and isStored(). + + If the property is an enumeration, isEnumType() returns true; if the + property is an enumeration that is also a flag (i.e. its values + can be combined using the OR operator), isEnumType() and + isFlagType() both return true. The enumerator for these types is + available from enumerator(). + + The property's values are set and retrieved with read(), write(), + and reset(); they can also be changed through QObject's set and get + functions. See QObject::setProperty() and QObject::property() for + details. + + You get property meta-data through an object's meta-object. See + QMetaObject::property() and QMetaObject::propertyCount() for + details. + + \sa QMetaObject, QMetaEnum, QMetaMethod, {Qt's Property System} +*/ + +/*! + \fn bool QMetaProperty::isValid() const + + Returns true if this property is valid (readable); otherwise + returns false. + + \sa isReadable() +*/ + +/*! + \fn const QMetaObject *QMetaProperty::enclosingMetaObject() const + \internal +*/ + +/*! + \internal +*/ +QMetaProperty::QMetaProperty() + : mobj(0), handle(0), idx(0) +{ +} + + +/*! + Returns this property's name. + + \sa type(), typeName() +*/ +const char *QMetaProperty::name() const +{ + if (!mobj) + return 0; + int handle = priv(mobj->d.data)->propertyData + 3*idx; + return mobj->d.stringdata + mobj->d.data[handle]; +} + +/*! + Returns the name of this property's type. + + \sa type(), name() +*/ +const char *QMetaProperty::typeName() const +{ + if (!mobj) + return 0; + int handle = priv(mobj->d.data)->propertyData + 3*idx; + return mobj->d.stringdata + mobj->d.data[handle + 1]; +} + +/*! + Returns this property's type. The return value is one + of the values of the QVariant::Type enumeration. + + \sa userType(), typeName(), name() +*/ +QVariant::Type QMetaProperty::type() const +{ + if (!mobj) + return QVariant::Invalid; + int handle = priv(mobj->d.data)->propertyData + 3*idx; + uint flags = mobj->d.data[handle + 2]; + + uint type = flags >> 24; + if (type == 0xff) // special value for QVariant + type = QVariant::LastType; + if (type) + return QVariant::Type(type); + if (isEnumType()) { + int enumMetaTypeId = QMetaType::type(qualifiedName(menum)); + if (enumMetaTypeId == 0) + return QVariant::Int; + } + + return QVariant::UserType; +} + +/*! + \since 4.2 + + Returns this property's user type. The return value is one + of the values that are registered with QMetaType, or 0 if + the type is not registered. + + \sa type(), QMetaType, typeName() + */ +int QMetaProperty::userType() const +{ + QVariant::Type tp = type(); + if (tp != QVariant::UserType) + return tp; + if (isEnumType()) { + int enumMetaTypeId = QMetaType::type(qualifiedName(menum)); + return enumMetaTypeId; + } + return QMetaType::type(typeName()); +} + +/*! + Returns true if the property's type is an enumeration value that + is used as a flag; otherwise returns false. + + Flags can be combined using the OR operator. A flag type is + implicitly also an enum type. + + \sa isEnumType(), enumerator(), QMetaEnum::isFlag() +*/ + +bool QMetaProperty::isFlagType() const +{ + return isEnumType() && menum.isFlag(); +} + +/*! + Returns true if the property's type is an enumeration value; + otherwise returns false. + + \sa enumerator(), isFlagType() +*/ +bool QMetaProperty::isEnumType() const +{ + if (!mobj) + return false; + int handle = priv(mobj->d.data)->propertyData + 3*idx; + int flags = mobj->d.data[handle + 2]; + return (flags & EnumOrFlag) && menum.name(); +} + +/*! + \internal + + Returns true if the property has a C++ setter function that + follows Qt's standard "name" / "setName" pattern. Designer and uic + query hasStdCppSet() in order to avoid expensive + QObject::setProperty() calls. All properties in Qt [should] follow + this pattern. +*/ +bool QMetaProperty::hasStdCppSet() const +{ + if (!mobj) + return false; + int handle = priv(mobj->d.data)->propertyData + 3*idx; + int flags = mobj->d.data[handle + 2]; + return (flags & StdCppSet); +} + +/*! + Returns the enumerator if this property's type is an enumerator + type; otherwise the returned value is undefined. + + \sa isEnumType(), isFlagType() +*/ +QMetaEnum QMetaProperty::enumerator() const +{ + return menum; +} + +/*! + Reads the property's value from the given \a object. Returns the value + if it was able to read it; otherwise returns an invalid variant. + + \sa write(), reset(), isReadable() +*/ +QVariant QMetaProperty::read(const QObject *object) const +{ + if (!object || !mobj) + return QVariant(); + + uint t = QVariant::Int; + if (isEnumType()) { + /* + try to create a QVariant that can be converted to this enum + type (only works if the enum has already been registered + with QMetaType) + */ + int enumMetaTypeId = QMetaType::type(qualifiedName(menum)); + if (enumMetaTypeId != 0) + t = enumMetaTypeId; + } else { + int handle = priv(mobj->d.data)->propertyData + 3*idx; + uint flags = mobj->d.data[handle + 2]; + const char *typeName = mobj->d.stringdata + mobj->d.data[handle + 1]; + t = (flags >> 24); + if (t == 0xff) // special value for QVariant + t = QVariant::LastType; + if (t == QVariant::Invalid) + t = QMetaType::type(typeName); + if (t == QVariant::Invalid) + t = QVariant::nameToType(typeName); + if (t == QVariant::Invalid || t == QVariant::UserType) { + if (t == QVariant::Invalid) + qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property '%s::%s'", typeName, mobj->className(), name()); + return QVariant(); + } + } + QVariant value; + void *argv[2] = { 0, &value }; + if (t == QVariant::LastType) { + argv[0] = &value; + } else { + value = QVariant(t, (void*)0); + argv[0] = value.data(); + } + const_cast<QObject*>(object)->qt_metacall(QMetaObject::ReadProperty, + idx + mobj->propertyOffset(), + argv); + if (argv[1] == 0) + // "value" was changed + return value; + if (t != QVariant::LastType && argv[0] != value.data()) + // pointer or reference + return QVariant((QVariant::Type)t, argv[0]); + return value; +} + +/*! + Writes \a value as the property's value to the given \a object. Returns + true if the write succeeded; otherwise returns false. + + \sa read(), reset(), isWritable() +*/ +bool QMetaProperty::write(QObject *object, const QVariant &value) const +{ + if (!object || !isWritable()) + return false; + + QVariant v = value; + uint t = QVariant::Invalid; + if (isEnumType()) { + if (v.type() == QVariant::String +#ifdef QT3_SUPPORT + || v.type() == QVariant::CString +#endif + ) { + if (isFlagType()) + v = QVariant(menum.keysToValue(value.toByteArray())); + else + v = QVariant(menum.keyToValue(value.toByteArray())); + } else if (v.type() != QVariant::Int && v.type() != QVariant::UInt) { + int enumMetaTypeId = QMetaType::type(qualifiedName(menum)); + if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData()) + return false; + v = QVariant(*reinterpret_cast<const int *>(v.constData())); + } + v.convert(QVariant::Int); + } else { + int handle = priv(mobj->d.data)->propertyData + 3*idx; + uint flags = mobj->d.data[handle + 2]; + t = flags >> 24; + if (t == 0xff) // special value for QVariant + t = QVariant::LastType; + if (t == QVariant::Invalid) { + const char *typeName = mobj->d.stringdata + mobj->d.data[handle + 1]; + const char *vtypeName = value.typeName(); + if (vtypeName && strcmp(typeName, vtypeName) == 0) + t = value.userType(); + else + t = QVariant::nameToType(typeName); + } + if (t == QVariant::Invalid) + return false; + if (t != QVariant::LastType && t != (uint)value.userType() && (t < QMetaType::User && !v.convert((QVariant::Type)t))) + return false; + } + + void *argv[2] = { 0, &v }; + if (t == QVariant::LastType) + argv[0] = &v; + else + argv[0] = v.data(); + object->qt_metacall(QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv); + return true; +} + +/*! + Resets the property for the given \a object with a reset method. + Returns true if the reset worked; otherwise returns false. + + Reset methods are optional; only a few properties support them. + + \sa read(), write() +*/ +bool QMetaProperty::reset(QObject *object) const +{ + if (!object || !mobj || !isResettable()) + return false; + void *argv[] = { 0 }; + object->qt_metacall(QMetaObject::ResetProperty, idx + mobj->propertyOffset(), argv); + return true; +} + +/*! + Returns true if this property can be reset to a default value; otherwise + returns false. + + \sa reset() +*/ +bool QMetaProperty::isResettable() const +{ + if (!mobj) + return false; + int flags = mobj->d.data[handle + 2]; + return flags & Resettable; +} + +/*! + Returns true if this property is readable; otherwise returns false. + + \sa isWritable(), read(), isValid() + */ +bool QMetaProperty::isReadable() const +{ + if (!mobj) + return false; + int flags = mobj->d.data[handle + 2]; + return flags & Readable; +} + +/*! + Returns true if this property has a corresponding change notify signal; + otherwise returns false. + + \sa notifySignal() + */ +bool QMetaProperty::hasNotifySignal() const +{ + if (!mobj) + return false; + int flags = mobj->d.data[handle + 2]; + return flags & Notify; +} + +/*! + \since 4.5 + + Returns the QMetaMethod instance of the property change notifying signal if + one was specified, otherwise returns an invalid QMetaMethod. + + \sa hasNotifySignal() + */ +QMetaMethod QMetaProperty::notifySignal() const +{ + int id = notifySignalIndex(); + if (id != -1) + return mobj->method(id); + else + return QMetaMethod(); +} + +/*! + Returns the index of the property change notifying signal if one was + specified, otherwise returns -1. + + \sa hasNotifySignal() + */ +int QMetaProperty::notifySignalIndex() const +{ + if (hasNotifySignal()) { + int offset = priv(mobj->d.data)->propertyData + + priv(mobj->d.data)->propertyCount * 3 + idx; + return mobj->d.data[offset] + mobj->methodOffset(); + } else { + return -1; + } +} + +/*! + Returns true if this property is writable; otherwise returns + false. + + \sa isReadable(), write() + */ +bool QMetaProperty::isWritable() const +{ + if (!mobj) + return false; + int flags = mobj->d.data[handle + 2]; + return flags & Writable; +} + + +/*! + Returns true if this property is designable for the given \a object; + otherwise returns false. + + If no \a object is given, the function returns false if the + \c{Q_PROPERTY()}'s \c DESIGNABLE attribute is false; otherwise + returns true (if the attribute is true or is a function or expression). + + \sa isScriptable(), isStored() +*/ +bool QMetaProperty::isDesignable(const QObject *object) const +{ + if (!mobj) + return false; + int flags = mobj->d.data[handle + 2]; + bool b = flags & Designable; + if (object) { + void *argv[] = { &b }; + const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyDesignable, + idx + mobj->propertyOffset(), argv); + } + return b; + + +} + +/*! + Returns true if the property is scriptable for the given \a object; + otherwise returns false. + + If no \a object is given, the function returns false if the + \c{Q_PROPERTY()}'s \c SCRIPTABLE attribute is false; otherwise returns + true (if the attribute is true or is a function or expression). + + \sa isDesignable(), isStored() +*/ +bool QMetaProperty::isScriptable(const QObject *object) const +{ + if (!mobj) + return false; + int flags = mobj->d.data[handle + 2]; + bool b = flags & Scriptable; + if (object) { + void *argv[] = { &b }; + const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyScriptable, + idx + mobj->propertyOffset(), argv); + } + return b; +} + +/*! + Returns true if the property is stored for \a object; otherwise returns + false. + + If no \a object is given, the function returns false if the + \c{Q_PROPERTY()}'s \c STORED attribute is false; otherwise returns + true (if the attribute is true or is a function or expression). + + \sa isDesignable(), isScriptable() +*/ +bool QMetaProperty::isStored(const QObject *object) const +{ + if (!mobj) + return false; + int flags = mobj->d.data[handle + 2]; + bool b = flags & Stored; + if (object) { + void *argv[] = { &b }; + const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyStored, + idx + mobj->propertyOffset(), argv); + } + return b; +} + +/*! + Returns true if this property is designated as the \c USER + property, i.e., the one that the user can edit for \a object or + that is significant in some other way. Otherwise it returns + false. e.g., the \c text property is the \c USER editable property + of a QLineEdit. + + If \a object is null, the function returns false if the \c + {Q_PROPERTY()}'s \c USER attribute is false. Otherwise it returns + true. + + \sa QMetaObject::userProperty(), isDesignable(), isScriptable() +*/ +bool QMetaProperty::isUser(const QObject *object) const +{ + if (!mobj) + return false; + int flags = mobj->d.data[handle + 2]; + bool b = flags & User; + if (object) { + void *argv[] = { &b }; + const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyUser, + idx + mobj->propertyOffset(), argv); + } + return b; +} + +/*! + \obsolete + + Returns true if the property is editable for the given \a object; + otherwise returns false. + + If no \a object is given, the function returns false if the + \c{Q_PROPERTY()}'s \c EDITABLE attribute is false; otherwise returns + true (if the attribute is true or is a function or expression). + + \sa isDesignable(), isScriptable(), isStored() +*/ +bool QMetaProperty::isEditable(const QObject *object) const +{ + if (!mobj) + return false; + int flags = mobj->d.data[handle + 2]; + bool b = flags & Editable; + if (object) { + void *argv[] = { &b }; + const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyEditable, + idx + mobj->propertyOffset(), argv); + } + return b; +} + +/*! + \class QMetaClassInfo + + \brief The QMetaClassInfo class provides additional information + about a class. + + \ingroup objectmodel + + Class information items are simple \e{name}--\e{value} pairs that + are specified using Q_CLASSINFO() in the source code. The + information can be retrieved using name() and value(). For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetaobject.cpp 5 + + This mechanism is free for you to use in your Qt applications. Qt + doesn't use it for any of its classes. + + \sa QMetaObject +*/ + + +/*! + \fn QMetaClassInfo::QMetaClassInfo() + \internal +*/ + +/*! + \fn const QMetaObject *QMetaClassInfo::enclosingMetaObject() const + \internal +*/ + +/*! + Returns the name of this item. + + \sa value() +*/ +const char *QMetaClassInfo::name() const +{ + if (!mobj) + return 0; + return mobj->d.stringdata + mobj->d.data[handle]; +} + +/*! + Returns the value of this item. + + \sa name() +*/ +const char* QMetaClassInfo::value() const +{ + if (!mobj) + return 0; + return mobj->d.stringdata + mobj->d.data[handle + 1]; +} + +/*! + \macro QGenericArgument Q_ARG(Type, const Type &value) + \relates QMetaObject + + This macro takes a \a Type and a \a value of that type and + returns a \l QGenericArgument object that can be passed to + QMetaObject::invokeMethod(). + + \sa Q_RETURN_ARG() +*/ + +/*! + \macro QGenericReturnArgument Q_RETURN_ARG(Type, Type &value) + \relates QMetaObject + + This macro takes a \a Type and a non-const reference to a \a + value of that type and returns a QGenericReturnArgument object + that can be passed to QMetaObject::invokeMethod(). + + \sa Q_ARG() +*/ + +/*! + \class QGenericArgument + + \brief The QGenericArgument class is an internal helper class for + marshalling arguments. + + This class should never be used directly. Please use the \l Q_ARG() + macro instead. + + \sa Q_ARG(), QMetaObject::invokeMethod(), QGenericReturnArgument +*/ + +/*! + \fn QGenericArgument::QGenericArgument(const char *name, const void *data) + + Constructs a QGenericArgument object with the given \a name and \a data. +*/ + +/*! + \fn QGenericArgument::data () const + + Returns the data set in the constructor. +*/ + +/*! + \fn QGenericArgument::name () const + + Returns the name set in the constructor. +*/ + +/*! + \class QGenericReturnArgument + + \brief The QGenericReturnArgument class is an internal helper class for + marshalling arguments. + + This class should never be used directly. Please use the + Q_RETURN_ARG() macro instead. + + \sa Q_RETURN_ARG(), QMetaObject::invokeMethod(), QGenericArgument +*/ + +/*! + \fn QGenericReturnArgument::QGenericReturnArgument(const char *name, void *data) + + Constructs a QGenericReturnArgument object with the given \a name + and \a data. +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h new file mode 100644 index 0000000..18c488a --- /dev/null +++ b/src/corelib/kernel/qmetaobject.h @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETAOBJECT_H +#define QMETAOBJECT_H + +#include <QtCore/qobjectdefs.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +template <typename T> class QList; + +class Q_CORE_EXPORT QMetaMethod +{ +public: + inline QMetaMethod() : mobj(0),handle(0) {} + + const char *signature() const; + const char *typeName() const; + QList<QByteArray> parameterTypes() const; + QList<QByteArray> parameterNames() const; + const char *tag() const; + enum Access { Private, Protected, Public }; + Access access() const; + enum MethodType { Method, Signal, Slot, Constructor }; + MethodType methodType() const; + enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 }; + int attributes() const; + + inline const QMetaObject *enclosingMetaObject() const { return mobj; } + + bool invoke(QObject *object, + Qt::ConnectionType connectionType, + QGenericReturnArgument returnValue, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) const; + inline bool invoke(QObject *object, + QGenericReturnArgument returnValue, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) const + { + return invoke(object, Qt::AutoConnection, returnValue, + val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); + } + inline bool invoke(QObject *object, + Qt::ConnectionType connectionType, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) const + { + return invoke(object, connectionType, QGenericReturnArgument(), + val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); + } + inline bool invoke(QObject *object, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) const + { + return invoke(object, Qt::AutoConnection, QGenericReturnArgument(), + val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); + } + +private: + const QMetaObject *mobj; + uint handle; + friend struct QMetaObject; +}; +Q_DECLARE_TYPEINFO(QMetaMethod, Q_MOVABLE_TYPE); + +class Q_CORE_EXPORT QMetaEnum +{ +public: + inline QMetaEnum() : mobj(0),handle(0) {} + + const char *name() const; + bool isFlag() const; + + int keyCount() const; + const char *key(int index) const; + int value(int index) const; + + const char *scope() const; + + int keyToValue(const char *key) const; + const char* valueToKey(int value) const; + int keysToValue(const char * keys) const; + QByteArray valueToKeys(int value) const; + + inline const QMetaObject *enclosingMetaObject() const { return mobj; } + + inline bool isValid() const { return name() != 0; } +private: + const QMetaObject *mobj; + uint handle; + friend struct QMetaObject; +}; +Q_DECLARE_TYPEINFO(QMetaEnum, Q_MOVABLE_TYPE); + +class Q_CORE_EXPORT QMetaProperty +{ +public: + QMetaProperty(); + + const char *name() const; + const char *typeName() const; + QVariant::Type type() const; + int userType() const; + + bool isReadable() const; + bool isWritable() const; + bool isResettable() const; + bool isDesignable(const QObject *obj = 0) const; + bool isScriptable(const QObject *obj = 0) const; + bool isStored(const QObject *obj = 0) const; + bool isEditable(const QObject *obj = 0) const; + bool isUser(const QObject *obj = 0) const; + + bool isFlagType() const; + bool isEnumType() const; + QMetaEnum enumerator() const; + + bool hasNotifySignal() const; + QMetaMethod notifySignal() const; + int notifySignalIndex() const; + + QVariant read(const QObject *obj) const; + bool write(QObject *obj, const QVariant &value) const; + bool reset(QObject *obj) const; + + bool hasStdCppSet() const; + inline bool isValid() const { return isReadable(); } + inline const QMetaObject *enclosingMetaObject() const { return mobj; } + +private: + const QMetaObject *mobj; + uint handle; + int idx; + QMetaEnum menum; + friend struct QMetaObject; +}; + +class Q_CORE_EXPORT QMetaClassInfo +{ +public: + inline QMetaClassInfo() : mobj(0),handle(0) {} + const char *name() const; + const char *value() const; + inline const QMetaObject *enclosingMetaObject() const { return mobj; } +private: + const QMetaObject *mobj; + uint handle; + friend struct QMetaObject; +}; +Q_DECLARE_TYPEINFO(QMetaClassInfo, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMETAOBJECT_H diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h new file mode 100644 index 0000000..2e0dbb2 --- /dev/null +++ b/src/corelib/kernel/qmetaobject_p.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETAOBJECT_P_H +#define QMETAOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of moc. This header file may change from version to version without notice, +// or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +#ifndef UTILS_H +// mirrored in moc's utils.h +static inline bool is_ident_char(char s) +{ + return ((s >= 'a' && s <= 'z') + || (s >= 'A' && s <= 'Z') + || (s >= '0' && s <= '9') + || s == '_' + ); +} + +static inline bool is_space(char s) +{ + return (s == ' ' || s == '\t'); +} +#endif + +// This code is shared with moc.cpp +static QByteArray normalizeTypeInternal(const char *t, const char *e, bool fixScope = false, bool adjustConst = true) +{ + int len = e - t; + /* + Convert 'char const *' into 'const char *'. Start at index 1, + not 0, because 'const char *' is already OK. + */ + QByteArray constbuf; + for (int i = 1; i < len; i++) { + if ( t[i] == 'c' + && strncmp(t + i + 1, "onst", 4) == 0 + && (i + 5 >= len || !is_ident_char(t[i + 5])) + && !is_ident_char(t[i-1]) + ) { + constbuf = QByteArray(t, len); + if (is_space(t[i-1])) + constbuf.remove(i-1, 6); + else + constbuf.remove(i, 5); + constbuf.prepend("const "); + t = constbuf.data(); + e = constbuf.data() + constbuf.length(); + break; + } + /* + We musn't convert 'char * const *' into 'const char **' + and we must beware of 'Bar<const Bla>'. + */ + if (t[i] == '&' || t[i] == '*' ||t[i] == '<') + break; + } + if (adjustConst && e > t + 6 && strncmp("const ", t, 6) == 0) { + if (*(e-1) == '&') { // treat const reference as value + t += 6; + --e; + } else if (is_ident_char(*(e-1))) { // treat const value as value + t += 6; + } + } + QByteArray result; + result.reserve(len); + +#if 1 + // consume initial 'const ' + if (strncmp("const ", t, 6) == 0) { + t+= 6; + result += "const "; + } +#endif + + // some type substitutions for 'unsigned x' + if (strncmp("unsigned", t, 8) == 0) { + // make sure "unsigned" is an isolated word before making substitutions + if (!t[8] || !is_ident_char(t[8])) { + if (strncmp(" int", t+8, 4) == 0) { + t += 8+4; + result += "uint"; + } else if (strncmp(" long", t+8, 5) == 0) { + if ((strlen(t + 8 + 5) < 4 || strncmp(t + 8 + 5, " int", 4) != 0) // preserve '[unsigned] long int' + && (strlen(t + 8 + 5) < 5 || strncmp(t + 8 + 5, " long", 5) != 0) // preserve '[unsigned] long long' + ) { + t += 8+5; + result += "ulong"; + } + } else if (strncmp(" short", t+8, 6) != 0 // preserve unsigned short + && strncmp(" char", t+8, 5) != 0) { // preserve unsigned char + // treat rest (unsigned) as uint + t += 8; + result += "uint"; + } + } + } else { + // discard 'struct', 'class', and 'enum'; they are optional + // and we don't want them in the normalized signature + struct { + const char *keyword; + int len; + } optional[] = { + { "struct ", 7 }, + { "class ", 6 }, + { "enum ", 5 }, + { 0, 0 } + }; + int i = 0; + do { + if (strncmp(optional[i].keyword, t, optional[i].len) == 0) { + t += optional[i].len; + break; + } + } while (optional[++i].keyword != 0); + } + + while (t != e) { + char c = *t++; + if (fixScope && c == ':' && *t == ':' ) { + ++t; + c = *t++; + int i = result.size() - 1; + while (i >= 0 && is_ident_char(result.at(i))) + --i; + result.resize(i + 1); + } + result += c; + if (c == '<') { + //template recursion + const char* tt = t; + int templdepth = 1; + while (t != e) { + c = *t++; + if (c == '<') + ++templdepth; + if (c == '>') + --templdepth; + if (templdepth == 0) { + result += normalizeTypeInternal(tt, t-1, fixScope, false); + result += c; + if (*t == '>') + result += ' '; // avoid >> + break; + } + } + } + } + + return result; +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp new file mode 100644 index 0000000..be60055 --- /dev/null +++ b/src/corelib/kernel/qmetatype.cpp @@ -0,0 +1,1355 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmetatype.h" +#include "qobjectdefs.h" +#include "qdatetime.h" +#include "qbytearray.h" +#include "qreadwritelock.h" +#include "qstring.h" +#include "qstringlist.h" +#include "qvector.h" +#include "qlocale.h" + +#ifdef QT_BOOTSTRAPPED +# ifndef QT_NO_GEOM_VARIANT +# define QT_NO_GEOM_VARIANT +# endif +#else +# include "qbitarray.h" +# include "qurl.h" +# include "qvariant.h" +#endif + +#ifndef QT_NO_GEOM_VARIANT +# include "qsize.h" +# include "qpoint.h" +# include "qrect.h" +# include "qline.h" +#endif + +QT_BEGIN_NAMESPACE + +#define NS(x) QT_PREPEND_NAMESPACE(x) + +/*! + \macro Q_DECLARE_METATYPE(Type) + \relates QMetaType + + This macro makes the type \a Type known to QMetaType as long as it + provides a public default constructor, a public copy constructor, + and a public destructor. It is needed to use the type \a Type as a + custom type in QVariant. + + Ideally, this macro should be placed below the declaration of + the class or struct. If that is not possible, it can be put in + a private header file which has to be included every time that + type is used in a QVariant. + + Adding a Q_DECLARE_METATYPE() makes the type known to all template + based functions, including QVariant. Note that if you intend to + use the type in \e queued signal and slot connections or in + QObject's property system, you also have to call + qRegisterMetaType() since the names are resolved at runtime. + + This example shows a typical use case of Q_DECLARE_METATYPE(): + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetatype.cpp 0 + + If \c MyStruct is in a namespace, the Q_DECLARE_METATYPE() macro + has to be outside the namespace: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetatype.cpp 1 + + Since \c{MyStruct} is now known to QMetaType, it can be used in QVariant: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetatype.cpp 2 + + \sa qRegisterMetaType() +*/ + +/*! + \enum QMetaType::Type + + These are the built-in types supported by QMetaType: + + \value Void \c void + \value Bool \c bool + \value Int \c int + \value UInt \c{unsigned int} + \value Double \c double + \value QChar QChar + \value QString QString + \value QByteArray QByteArray + + \value VoidStar \c{void *} + \value Long \c{long} + \value LongLong LongLong + \value Short \c{short} + \value Char \c{char} + \value ULong \c{unsigned long} + \value ULongLong ULongLong + \value UShort \c{unsigned short} + \value UChar \c{unsigned char} + \value Float \c float + \value QObjectStar QObject * + \value QWidgetStar QWidget * + + \value QColorGroup QColorGroup + \value QCursor QCursor + \value QDate QDate + \value QSize QSize + \value QTime QTime + \value QVariantList QVariantList + \value QPolygon QPolygon + \value QColor QColor + \value QSizeF QSizeF + \value QRectF QRectF + \value QLine QLine + \value QTextLength QTextLength + \value QStringList QStringList + \value QVariantMap QVariantMap + \value QVariantHash QVariantHash + \value QIcon QIcon + \value QPen QPen + \value QLineF QLineF + \value QTextFormat QTextFormat + \value QRect QRect + \value QPoint QPoint + \value QUrl QUrl + \value QRegExp QRegExp + \value QDateTime QDateTime + \value QPointF QPointF + \value QPalette QPalette + \value QFont QFont + \value QBrush QBrush + \value QRegion QRegion + \value QBitArray QBitArray + \value QImage QImage + \value QKeySequence QKeySequence + \value QSizePolicy QSizePolicy + \value QPixmap QPixmap + \value QLocale QLocale + \value QBitmap QBitmap + \value QMatrix QMatrix + \value QTransform QTransform + + \value User Base value for user types + + \omitvalue FirstCoreExtType + \omitvalue FirstGuiType + \omitvalue LastCoreExtType + \omitvalue LastCoreType + \omitvalue LastGuiType + + Additional types can be registered using Q_DECLARE_METATYPE(). + + \sa type(), typeName() +*/ + +/*! + \class QMetaType + \brief The QMetaType class manages named types in the meta-object system. + + \ingroup objectmodel + \threadsafe + + The class is used as a helper to marshall types in QVariant and + in queued signals and slots connections. It associates a type + name to a type so that it can be created and destructed + dynamically at run-time. Declare new types with Q_DECLARE_METATYPE() + to make them available to QVariant and other template-based functions. + Call qRegisterMetaType() to make type available to non-template based + functions, such as the queued signal and slot connections. + + Any class or struct that has a public default + constructor, a public copy constructor, and a public destructor + can be registered. + + The following code allocates and destructs an instance of + \c{MyClass}: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetatype.cpp 3 + + If we want the stream operators \c operator<<() and \c + operator>>() to work on QVariant objects that store custom types, + the custom type must provide \c operator<<() and \c operator>>() + operators. + + \sa Q_DECLARE_METATYPE(), QVariant::setValue(), QVariant::value(), QVariant::fromValue() +*/ + +/* Note: these MUST be in the order of the enums */ +static const struct { const char * typeName; int type; } types[] = { + + /* All Core types */ + {"void", QMetaType::Void}, + {"bool", QMetaType::Bool}, + {"int", QMetaType::Int}, + {"uint", QMetaType::UInt}, + {"qlonglong", QMetaType::LongLong}, + {"qulonglong", QMetaType::ULongLong}, + {"double", QMetaType::Double}, + {"QChar", QMetaType::QChar}, + {"QVariantMap", QMetaType::QVariantMap}, + {"QVariantList", QMetaType::QVariantList}, + {"QString", QMetaType::QString}, + {"QStringList", QMetaType::QStringList}, + {"QByteArray", QMetaType::QByteArray}, + {"QBitArray", QMetaType::QBitArray}, + {"QDate", QMetaType::QDate}, + {"QTime", QMetaType::QTime}, + {"QDateTime", QMetaType::QDateTime}, + {"QUrl", QMetaType::QUrl}, + {"QLocale", QMetaType::QLocale}, + {"QRect", QMetaType::QRect}, + {"QRectF", QMetaType::QRectF}, + {"QSize", QMetaType::QSize}, + {"QSizeF", QMetaType::QSizeF}, + {"QLine", QMetaType::QLine}, + {"QLineF", QMetaType::QLineF}, + {"QPoint", QMetaType::QPoint}, + {"QPointF", QMetaType::QPointF}, + {"QRegExp", QMetaType::QRegExp}, + {"QVariantHash", QMetaType::QVariantHash}, + + /* All GUI types */ + {"QColorGroup", 63}, + {"QFont", QMetaType::QFont}, + {"QPixmap", QMetaType::QPixmap}, + {"QBrush", QMetaType::QBrush}, + {"QColor", QMetaType::QColor}, + {"QPalette", QMetaType::QPalette}, + {"QIcon", QMetaType::QIcon}, + {"QImage", QMetaType::QImage}, + {"QPolygon", QMetaType::QPolygon}, + {"QRegion", QMetaType::QRegion}, + {"QBitmap", QMetaType::QBitmap}, + {"QCursor", QMetaType::QCursor}, + {"QSizePolicy", QMetaType::QSizePolicy}, + {"QKeySequence", QMetaType::QKeySequence}, + {"QPen", QMetaType::QPen}, + {"QTextLength", QMetaType::QTextLength}, + {"QTextFormat", QMetaType::QTextFormat}, + {"QMatrix", QMetaType::QMatrix}, + {"QTransform", QMetaType::QTransform}, + + /* All Metatype builtins */ + {"void*", QMetaType::VoidStar}, + {"long", QMetaType::Long}, + {"short", QMetaType::Short}, + {"char", QMetaType::Char}, + {"ulong", QMetaType::ULong}, + {"ushort", QMetaType::UShort}, + {"uchar", QMetaType::UChar}, + {"float", QMetaType::Float}, + {"QObject*", QMetaType::QObjectStar}, + {"QWidget*", QMetaType::QWidgetStar}, + + /* Type aliases - order doesn't matter */ + {"unsigned long", QMetaType::ULong}, + {"unsigned int", QMetaType::UInt}, + {"unsigned short", QMetaType::UShort}, + {"unsigned char", QMetaType::UChar}, + {"long long", QMetaType::LongLong}, + {"unsigned long long", QMetaType::ULongLong}, + {"qint8", QMetaType::Char}, + {"quint8", QMetaType::UChar}, + {"qint16", QMetaType::Short}, + {"quint16", QMetaType::UShort}, + {"qint32", QMetaType::Int}, + {"quint32", QMetaType::UInt}, + {"qint64", QMetaType::LongLong}, + {"quint64", QMetaType::ULongLong}, + {"QList<QVariant>", QMetaType::QVariantList}, + {"QMap<QString,QVariant>", QMetaType::QVariantMap}, + {"QHash<QString,QVariant>", QMetaType::QVariantHash}, + // let QMetaTypeId2 figure out the type at compile time + {"qreal", QMetaTypeId2<qreal>::MetaType}, + + {0, QMetaType::Void} +}; + +struct QMetaTypeGuiHelper +{ + QMetaType::Constructor constr; + QMetaType::Destructor destr; +#ifndef QT_NO_DATASTREAM + QMetaType::SaveOperator saveOp; + QMetaType::LoadOperator loadOp; +#endif +}; +Q_CORE_EXPORT const QMetaTypeGuiHelper *qMetaTypeGuiHelper = 0; + +class QCustomTypeInfo +{ +public: + QCustomTypeInfo() : typeName(), constr(0), destr(0) +#ifndef QT_NO_DATASTREAM + , saveOp(0), loadOp(0) +#endif + {} + + QByteArray typeName; + QMetaType::Constructor constr; + QMetaType::Destructor destr; +#ifndef QT_NO_DATASTREAM + QMetaType::SaveOperator saveOp; + QMetaType::LoadOperator loadOp; +#endif +}; + +Q_DECLARE_TYPEINFO(QCustomTypeInfo, Q_MOVABLE_TYPE); +Q_GLOBAL_STATIC(QVector<QCustomTypeInfo>, customTypes) +Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock) + +#ifndef QT_NO_DATASTREAM +/*! \internal +*/ +void QMetaType::registerStreamOperators(const char *typeName, SaveOperator saveOp, + LoadOperator loadOp) +{ + int idx = type(typeName); + if (!idx) + return; + + QVector<QCustomTypeInfo> *ct = customTypes(); + if (!ct) + return; + QWriteLocker locker(customTypesLock()); + QCustomTypeInfo &inf = (*ct)[idx - User]; + inf.saveOp = saveOp; + inf.loadOp = loadOp; +} +#endif + +/*! + Returns the type name associated with the given \a type, or 0 if no + matching type was found. The returned pointer must not be deleted. + + \sa type(), isRegistered(), Type +*/ +const char *QMetaType::typeName(int type) +{ + enum { GuiTypeCount = LastGuiType - FirstGuiType }; + + if (type >= 0 && type <= LastCoreType) { + return types[type].typeName; + } else if (type >= FirstGuiType && type <= LastGuiType) { + return types[type - FirstGuiType + LastCoreType + 1].typeName; + } else if (type >= FirstCoreExtType && type <= LastCoreExtType) { + return types[type - FirstCoreExtType + GuiTypeCount + LastCoreType + 2].typeName; + } else if (type >= User) { + const QVector<QCustomTypeInfo> * const ct = customTypes(); + QReadLocker locker(customTypesLock()); + return ct && ct->count() > type - User && !ct->at(type - User).typeName.isEmpty() + ? ct->at(type - User).typeName.constData() + : static_cast<const char *>(0); + } + + return 0; +} + +/*! \internal + Same as QMetaType::type(), but doesn't lock the mutex. +*/ +static int qMetaTypeType_unlocked(const QByteArray &typeName) +{ + int i = 0; + while (types[i].typeName && strcmp(typeName.constData(), types[i].typeName)) + ++i; + if (!types[i].type) { + const QVector<QCustomTypeInfo> * const ct = customTypes(); + if (!ct) + return 0; + + for (int v = 0; v < ct->count(); ++v) { + if (ct->at(v).typeName == typeName) + return v + QMetaType::User; + } + } + return types[i].type; +} + +/*! \internal + + Registers a user type for marshalling, with \a typeName, a \a + destructor, and a \a constructor. Returns the type's handle, + or -1 if the type could not be registered. + */ +int QMetaType::registerType(const char *typeName, Destructor destructor, + Constructor constructor) +{ + QVector<QCustomTypeInfo> *ct = customTypes(); + if (!ct || !typeName || !destructor || !constructor) + return -1; + +#ifdef QT_NO_QOBJECT + NS(QByteArray) normalizedTypeName = typeName; +#else + NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName); +#endif + + QWriteLocker locker(customTypesLock()); + static int currentIdx = User; + int idx = qMetaTypeType_unlocked(normalizedTypeName); + + if (!idx) { + idx = currentIdx++; + ct->resize(ct->count() + 1); + QCustomTypeInfo &inf = (*ct)[idx - User]; + inf.typeName = normalizedTypeName; + inf.constr = constructor; + inf.destr = destructor; + } + return idx; +} + +/*! + \since 4.4 + + Unregisters a user type, with \a typeName. + + \sa type(), typeName() + */ +void QMetaType::unregisterType(const char *typeName) +{ + QVector<QCustomTypeInfo> *ct = customTypes(); + if (!ct || !typeName) + return; + +#ifdef QT_NO_QOBJECT + NS(QByteArray) normalizedTypeName = typeName; +#else + NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName); +#endif + QWriteLocker locker(customTypesLock()); + for (int v = 0; v < ct->count(); ++v) { + if (ct->at(v).typeName == typeName) { + QCustomTypeInfo &inf = (*ct)[v]; + inf.typeName.clear(); + inf.constr = 0; + inf.destr = 0; + } + } +} + +/*! + Returns true if the datatype with ID \a type is registered; + otherwise returns false. + + \sa type(), typeName(), Type +*/ +bool QMetaType::isRegistered(int type) +{ + if (type >= 0 && type < User) { + // predefined type + return true; + } + QReadLocker locker(customTypesLock()); + const QVector<QCustomTypeInfo> * const ct = customTypes(); + return ((type >= User) && (ct && ct->count() > type - User) && !ct->at(type - User).typeName.isEmpty()); +} + +/*! + Returns a handle to the type called \a typeName, or 0 if there is + no such type. + + \sa isRegistered(), typeName(), Type +*/ +int QMetaType::type(const char *typeName) +{ +#ifdef QT_NO_QOBJECT + const NS(QByteArray) normalizedTypeName = typeName; +#else + const NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName); +#endif + + QReadLocker locker(customTypesLock()); + return qMetaTypeType_unlocked(normalizedTypeName); +} + +#ifndef QT_NO_DATASTREAM +/*! + Writes the object pointed to by \a data with the ID \a type to + the given \a stream. Returns true if the object is saved + successfully; otherwise returns false. + + The type must have been registered with qRegisterMetaType() and + qRegisterMetaTypeStreamOperators() beforehand. + + Normally, you should not need to call this function directly. + Instead, use QVariant's \c operator<<(), which relies on save() + to stream custom types. + + \sa load(), qRegisterMetaTypeStreamOperators() +*/ +bool QMetaType::save(QDataStream &stream, int type, const void *data) +{ + if (!data || !isRegistered(type)) + return false; + + switch(type) { + case QMetaType::Void: + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + return false; + case QMetaType::Long: + stream << qlonglong(*static_cast<const long *>(data)); + break; + case QMetaType::Int: + stream << *static_cast<const int *>(data); + break; + case QMetaType::Short: + stream << *static_cast<const short *>(data); + break; + case QMetaType::Char: + // force a char to be signed + stream << *static_cast<const signed char *>(data); + break; + case QMetaType::ULong: + stream << qulonglong(*static_cast<const ulong *>(data)); + break; + case QMetaType::UInt: + stream << *static_cast<const uint *>(data); + break; + case QMetaType::LongLong: + stream << *static_cast<const qlonglong *>(data); + break; + case QMetaType::ULongLong: + stream << *static_cast<const qulonglong *>(data); + break; + case QMetaType::UShort: + stream << *static_cast<const ushort *>(data); + break; + case QMetaType::UChar: + stream << *static_cast<const uchar *>(data); + break; + case QMetaType::Bool: + stream << qint8(*static_cast<const bool *>(data)); + break; + case QMetaType::Float: + stream << *static_cast<const float *>(data); + break; + case QMetaType::Double: + stream << *static_cast<const double *>(data); + break; + case QMetaType::QChar: + stream << *static_cast<const NS(QChar) *>(data); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QVariantMap: + stream << *static_cast<const NS(QVariantMap)*>(data); + break; + case QMetaType::QVariantHash: + stream << *static_cast<const NS(QVariantHash)*>(data); + break; + case QMetaType::QVariantList: + stream << *static_cast<const NS(QVariantList)*>(data); + break; +#endif + case QMetaType::QByteArray: + stream << *static_cast<const NS(QByteArray)*>(data); + break; + case QMetaType::QString: + stream << *static_cast<const NS(QString)*>(data); + break; + case QMetaType::QStringList: + stream << *static_cast<const NS(QStringList)*>(data); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QBitArray: + stream << *static_cast<const NS(QBitArray)*>(data); + break; +#endif + case QMetaType::QDate: + stream << *static_cast<const NS(QDate)*>(data); + break; + case QMetaType::QTime: + stream << *static_cast<const NS(QTime)*>(data); + break; + case QMetaType::QDateTime: + stream << *static_cast<const NS(QDateTime)*>(data); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QUrl: + stream << *static_cast<const NS(QUrl)*>(data); + break; +#endif + case QMetaType::QLocale: + stream << *static_cast<const NS(QLocale)*>(data); + break; +#ifndef QT_NO_GEOM_VARIANT + case QMetaType::QRect: + stream << *static_cast<const NS(QRect)*>(data); + break; + case QMetaType::QRectF: + stream << *static_cast<const NS(QRectF)*>(data); + break; + case QMetaType::QSize: + stream << *static_cast<const NS(QSize)*>(data); + break; + case QMetaType::QSizeF: + stream << *static_cast<const NS(QSizeF)*>(data); + break; + case QMetaType::QLine: + stream << *static_cast<const NS(QLine)*>(data); + break; + case QMetaType::QLineF: + stream << *static_cast<const NS(QLineF)*>(data); + break; + case QMetaType::QPoint: + stream << *static_cast<const NS(QPoint)*>(data); + break; + case QMetaType::QPointF: + stream << *static_cast<const NS(QPointF)*>(data); + break; +#endif +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + stream << *static_cast<const NS(QRegExp)*>(data); + break; +#endif +#ifdef QT3_SUPPORT + case QMetaType::QColorGroup: +#endif + case QMetaType::QFont: + case QMetaType::QPixmap: + case QMetaType::QBrush: + case QMetaType::QColor: + case QMetaType::QPalette: + case QMetaType::QIcon: + case QMetaType::QImage: + case QMetaType::QPolygon: + case QMetaType::QRegion: + case QMetaType::QBitmap: + case QMetaType::QCursor: + case QMetaType::QSizePolicy: + case QMetaType::QKeySequence: + case QMetaType::QPen: + case QMetaType::QTextLength: + case QMetaType::QTextFormat: + case QMetaType::QMatrix: + case QMetaType::QTransform: + if (!qMetaTypeGuiHelper) + return false; + qMetaTypeGuiHelper[type - FirstGuiType].saveOp(stream, data); + break; + default: { + const QVector<QCustomTypeInfo> * const ct = customTypes(); + if (!ct) + return false; + + SaveOperator saveOp = 0; + { + QReadLocker locker(customTypesLock()); + saveOp = ct->at(type - User).saveOp; + } + + if (!saveOp) + return false; + saveOp(stream, data); + break; } + } + + return true; +} + +/*! + Reads the object of the specified \a type from the given \a + stream into \a data. Returns true if the object is loaded + successfully; otherwise returns false. + + The type must have been registered with qRegisterMetaType() and + qRegisterMetaTypeStreamOperators() beforehand. + + Normally, you should not need to call this function directly. + Instead, use QVariant's \c operator>>(), which relies on load() + to stream custom types. + + \sa save(), qRegisterMetaTypeStreamOperators() +*/ +bool QMetaType::load(QDataStream &stream, int type, void *data) +{ + if (!data || !isRegistered(type)) + return false; + + switch(type) { + case QMetaType::Void: + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + return false; + case QMetaType::Long: { + qlonglong l; + stream >> l; + *static_cast<long *>(data) = long(l); + break; } + case QMetaType::Int: + stream >> *static_cast<int *>(data); + break; + case QMetaType::Short: + stream >> *static_cast<short *>(data); + break; + case QMetaType::Char: + // force a char to be signed + stream >> *static_cast<signed char *>(data); + break; + case QMetaType::ULong: { + qulonglong ul; + stream >> ul; + *static_cast<ulong *>(data) = ulong(ul); + break; } + case QMetaType::UInt: + stream >> *static_cast<uint *>(data); + break; + case QMetaType::LongLong: + stream >> *static_cast<qlonglong *>(data); + break; + case QMetaType::ULongLong: + stream >> *static_cast<qulonglong *>(data); + break; + case QMetaType::UShort: + stream >> *static_cast<ushort *>(data); + break; + case QMetaType::UChar: + stream >> *static_cast<uchar *>(data); + break; + case QMetaType::Bool: { + qint8 b; + stream >> b; + *static_cast<bool *>(data) = b; + break; } + case QMetaType::Float: + stream >> *static_cast<float *>(data); + break; + case QMetaType::Double: + stream >> *static_cast<double *>(data); + break; + case QMetaType::QChar: + stream >> *static_cast< NS(QChar)*>(data); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QVariantMap: + stream >> *static_cast< NS(QVariantMap)*>(data); + break; + case QMetaType::QVariantHash: + stream >> *static_cast< NS(QVariantHash)*>(data); + break; + case QMetaType::QVariantList: + stream >> *static_cast< NS(QVariantList)*>(data); + break; +#endif + case QMetaType::QByteArray: + stream >> *static_cast< NS(QByteArray)*>(data); + break; + case QMetaType::QString: + stream >> *static_cast< NS(QString)*>(data); + break; + case QMetaType::QStringList: + stream >> *static_cast< NS(QStringList)*>(data); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QBitArray: + stream >> *static_cast< NS(QBitArray)*>(data); + break; +#endif + case QMetaType::QDate: + stream >> *static_cast< NS(QDate)*>(data); + break; + case QMetaType::QTime: + stream >> *static_cast< NS(QTime)*>(data); + break; + case QMetaType::QDateTime: + stream >> *static_cast< NS(QDateTime)*>(data); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QUrl: + stream >> *static_cast< NS(QUrl)*>(data); + break; +#endif + case QMetaType::QLocale: + stream >> *static_cast< NS(QLocale)*>(data); + break; +#ifndef QT_NO_GEOM_VARIANT + case QMetaType::QRect: + stream >> *static_cast< NS(QRect)*>(data); + break; + case QMetaType::QRectF: + stream >> *static_cast< NS(QRectF)*>(data); + break; + case QMetaType::QSize: + stream >> *static_cast< NS(QSize)*>(data); + break; + case QMetaType::QSizeF: + stream >> *static_cast< NS(QSizeF)*>(data); + break; + case QMetaType::QLine: + stream >> *static_cast< NS(QLine)*>(data); + break; + case QMetaType::QLineF: + stream >> *static_cast< NS(QLineF)*>(data); + break; + case QMetaType::QPoint: + stream >> *static_cast< NS(QPoint)*>(data); + break; + case QMetaType::QPointF: + stream >> *static_cast< NS(QPointF)*>(data); + break; +#endif +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + stream >> *static_cast< NS(QRegExp)*>(data); + break; +#endif +#ifdef QT3_SUPPORT + case QMetaType::QColorGroup: +#endif + case QMetaType::QFont: + case QMetaType::QPixmap: + case QMetaType::QBrush: + case QMetaType::QColor: + case QMetaType::QPalette: + case QMetaType::QIcon: + case QMetaType::QImage: + case QMetaType::QPolygon: + case QMetaType::QRegion: + case QMetaType::QBitmap: + case QMetaType::QCursor: + case QMetaType::QSizePolicy: + case QMetaType::QKeySequence: + case QMetaType::QPen: + case QMetaType::QTextLength: + case QMetaType::QTextFormat: + case QMetaType::QMatrix: + case QMetaType::QTransform: + if (!qMetaTypeGuiHelper) + return false; + qMetaTypeGuiHelper[type - FirstGuiType].loadOp(stream, data); + break; + default: { + const QVector<QCustomTypeInfo> * const ct = customTypes(); + if (!ct) + return false; + + LoadOperator loadOp = 0; + { + QReadLocker locker(customTypesLock()); + loadOp = ct->at(type - User).loadOp; + } + + if (!loadOp) + return false; + loadOp(stream, data); + break; } + } + return true; +} +#endif + +/*! + Returns a copy of \a copy, assuming it is of type \a type. If \a + copy is zero, creates a default type. + + \sa destroy(), isRegistered(), Type +*/ +void *QMetaType::construct(int type, const void *copy) +{ + if (copy) { + switch(type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + return new void *(*static_cast<void* const *>(copy)); + case QMetaType::Long: + return new long(*static_cast<const long*>(copy)); + case QMetaType::Int: + return new int(*static_cast<const int*>(copy)); + case QMetaType::Short: + return new short(*static_cast<const short*>(copy)); + case QMetaType::Char: + return new char(*static_cast<const char*>(copy)); + case QMetaType::ULong: + return new ulong(*static_cast<const ulong*>(copy)); + case QMetaType::UInt: + return new uint(*static_cast<const uint*>(copy)); + case QMetaType::LongLong: + return new qlonglong(*static_cast<const qlonglong*>(copy)); + case QMetaType::ULongLong: + return new qulonglong(*static_cast<const qulonglong*>(copy)); + case QMetaType::UShort: + return new ushort(*static_cast<const ushort*>(copy)); + case QMetaType::UChar: + return new uchar(*static_cast<const uchar*>(copy)); + case QMetaType::Bool: + return new bool(*static_cast<const bool*>(copy)); + case QMetaType::Float: + return new float(*static_cast<const float*>(copy)); + case QMetaType::Double: + return new double(*static_cast<const double*>(copy)); + case QMetaType::QChar: + return new NS(QChar)(*static_cast<const NS(QChar)*>(copy)); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QVariantMap: + return new NS(QVariantMap)(*static_cast<const NS(QVariantMap)*>(copy)); + case QMetaType::QVariantHash: + return new NS(QVariantHash)(*static_cast<const NS(QVariantHash)*>(copy)); + case QMetaType::QVariantList: + return new NS(QVariantList)(*static_cast<const NS(QVariantList)*>(copy)); +#endif + case QMetaType::QByteArray: + return new NS(QByteArray)(*static_cast<const NS(QByteArray)*>(copy)); + case QMetaType::QString: + return new NS(QString)(*static_cast<const NS(QString)*>(copy)); + case QMetaType::QStringList: + return new NS(QStringList)(*static_cast<const NS(QStringList)*>(copy)); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QBitArray: + return new NS(QBitArray)(*static_cast<const NS(QBitArray)*>(copy)); +#endif + case QMetaType::QDate: + return new NS(QDate)(*static_cast<const NS(QDate)*>(copy)); + case QMetaType::QTime: + return new NS(QTime)(*static_cast<const NS(QTime)*>(copy)); + case QMetaType::QDateTime: + return new NS(QDateTime)(*static_cast<const NS(QDateTime)*>(copy)); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QUrl: + return new NS(QUrl)(*static_cast<const NS(QUrl)*>(copy)); +#endif + case QMetaType::QLocale: + return new NS(QLocale)(*static_cast<const NS(QLocale)*>(copy)); +#ifndef QT_NO_GEOM_VARIANT + case QMetaType::QRect: + return new NS(QRect)(*static_cast<const NS(QRect)*>(copy)); + case QMetaType::QRectF: + return new NS(QRectF)(*static_cast<const NS(QRectF)*>(copy)); + case QMetaType::QSize: + return new NS(QSize)(*static_cast<const NS(QSize)*>(copy)); + case QMetaType::QSizeF: + return new NS(QSizeF)(*static_cast<const NS(QSizeF)*>(copy)); + case QMetaType::QLine: + return new NS(QLine)(*static_cast<const NS(QLine)*>(copy)); + case QMetaType::QLineF: + return new NS(QLineF)(*static_cast<const NS(QLineF)*>(copy)); + case QMetaType::QPoint: + return new NS(QPoint)(*static_cast<const NS(QPoint)*>(copy)); + case QMetaType::QPointF: + return new NS(QPointF)(*static_cast<const NS(QPointF)*>(copy)); +#endif +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + return new NS(QRegExp)(*static_cast<const NS(QRegExp)*>(copy)); +#endif + case QMetaType::Void: + return 0; + default: + ; + } + } else { + switch(type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + return new void *; + case QMetaType::Long: + return new long; + case QMetaType::Int: + return new int; + case QMetaType::Short: + return new short; + case QMetaType::Char: + return new char; + case QMetaType::ULong: + return new ulong; + case QMetaType::UInt: + return new uint; + case QMetaType::LongLong: + return new qlonglong; + case QMetaType::ULongLong: + return new qulonglong; + case QMetaType::UShort: + return new ushort; + case QMetaType::UChar: + return new uchar; + case QMetaType::Bool: + return new bool; + case QMetaType::Float: + return new float; + case QMetaType::Double: + return new double; + case QMetaType::QChar: + return new NS(QChar); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QVariantMap: + return new NS(QVariantMap); + case QMetaType::QVariantHash: + return new NS(QVariantHash); + case QMetaType::QVariantList: + return new NS(QVariantList); +#endif + case QMetaType::QByteArray: + return new NS(QByteArray); + case QMetaType::QString: + return new NS(QString); + case QMetaType::QStringList: + return new NS(QStringList); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QBitArray: + return new NS(QBitArray); +#endif + case QMetaType::QDate: + return new NS(QDate); + case QMetaType::QTime: + return new NS(QTime); + case QMetaType::QDateTime: + return new NS(QDateTime); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QUrl: + return new NS(QUrl); +#endif + case QMetaType::QLocale: + return new NS(QLocale); +#ifndef QT_NO_GEOM_VARIANT + case QMetaType::QRect: + return new NS(QRect); + case QMetaType::QRectF: + return new NS(QRectF); + case QMetaType::QSize: + return new NS(QSize); + case QMetaType::QSizeF: + return new NS(QSizeF); + case QMetaType::QLine: + return new NS(QLine); + case QMetaType::QLineF: + return new NS(QLineF); + case QMetaType::QPoint: + return new NS(QPoint); + case QMetaType::QPointF: + return new NS(QPointF); +#endif +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + return new NS(QRegExp); +#endif + case QMetaType::Void: + return 0; + default: + ; + } + } + + Constructor constr = 0; + if (type >= FirstGuiType && type <= LastGuiType) { + if (!qMetaTypeGuiHelper) + return 0; + constr = qMetaTypeGuiHelper[type - FirstGuiType].constr; + } else { + const QVector<QCustomTypeInfo> * const ct = customTypes(); + QReadLocker locker(customTypesLock()); + if (type < User || !ct || ct->count() <= type - User) + return 0; + if (ct->at(type - User).typeName.isEmpty()) + return 0; + constr = ct->at(type - User).constr; + } + + return constr(copy); +} + +/*! + Destroys the \a data, assuming it is of the \a type given. + + \sa construct(), isRegistered(), Type +*/ +void QMetaType::destroy(int type, void *data) +{ + if (!data) + return; + switch(type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + delete static_cast<void**>(data); + break; + case QMetaType::Long: + delete static_cast<long*>(data); + break; + case QMetaType::Int: + delete static_cast<int*>(data); + break; + case QMetaType::Short: + delete static_cast<short*>(data); + break; + case QMetaType::Char: + delete static_cast<char*>(data); + break; + case QMetaType::ULong: + delete static_cast<ulong*>(data); + break; + case QMetaType::LongLong: + delete static_cast<qlonglong*>(data); + break; + case QMetaType::ULongLong: + delete static_cast<qulonglong*>(data); + break; + case QMetaType::UInt: + delete static_cast<uint*>(data); + break; + case QMetaType::UShort: + delete static_cast<ushort*>(data); + break; + case QMetaType::UChar: + delete static_cast<uchar*>(data); + break; + case QMetaType::Bool: + delete static_cast<bool*>(data); + break; + case QMetaType::Float: + delete static_cast<float*>(data); + break; + case QMetaType::Double: + delete static_cast<double*>(data); + break; + case QMetaType::QChar: + delete static_cast< NS(QChar)* >(data); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QVariantMap: + delete static_cast< NS(QVariantMap)* >(data); + break; + case QMetaType::QVariantHash: + delete static_cast< NS(QVariantHash)* >(data); + break; + case QMetaType::QVariantList: + delete static_cast< NS(QVariantList)* >(data); + break; +#endif + case QMetaType::QByteArray: + delete static_cast< NS(QByteArray)* >(data); + break; + case QMetaType::QString: + delete static_cast< NS(QString)* >(data); + break; + case QMetaType::QStringList: + delete static_cast< NS(QStringList)* >(data); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QBitArray: + delete static_cast< NS(QBitArray)* >(data); + break; +#endif + case QMetaType::QDate: + delete static_cast< NS(QDate)* >(data); + break; + case QMetaType::QTime: + delete static_cast< NS(QTime)* >(data); + break; + case QMetaType::QDateTime: + delete static_cast< NS(QDateTime)* >(data); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QUrl: + delete static_cast< NS(QUrl)* >(data); +#endif + break; + case QMetaType::QLocale: + delete static_cast< NS(QLocale)* >(data); + break; +#ifndef QT_NO_GEOM_VARIANT + case QMetaType::QRect: + delete static_cast< NS(QRect)* >(data); + break; + case QMetaType::QRectF: + delete static_cast< NS(QRectF)* >(data); + break; + case QMetaType::QSize: + delete static_cast< NS(QSize)* >(data); + break; + case QMetaType::QSizeF: + delete static_cast< NS(QSizeF)* >(data); + break; + case QMetaType::QLine: + delete static_cast< NS(QLine)* >(data); + break; + case QMetaType::QLineF: + delete static_cast< NS(QLineF)* >(data); + break; + case QMetaType::QPoint: + delete static_cast< NS(QPoint)* >(data); + break; + case QMetaType::QPointF: + delete static_cast< NS(QPointF)* >(data); + break; +#endif +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + delete static_cast< NS(QRegExp)* >(data); + break; +#endif + case QMetaType::Void: + break; + default: { + const QVector<QCustomTypeInfo> * const ct = customTypes(); + Destructor destr = 0; + if (type >= FirstGuiType && type <= LastGuiType) { + Q_ASSERT(qMetaTypeGuiHelper); + + if (!qMetaTypeGuiHelper) + return; + destr = qMetaTypeGuiHelper[type - FirstGuiType].destr; + } else { + QReadLocker locker(customTypesLock()); + if (type < User || !ct || ct->count() <= type - User) + break; + if (ct->at(type - User).typeName.isEmpty()) + break; + destr = ct->at(type - User).destr; + } + destr(data); + break; } + } +} + +/*! + \fn int qRegisterMetaType(const char *typeName) + \relates QMetaType + \threadsafe + + Registers the type name \a typeName to the type \c{T}. Returns + the internal ID used by QMetaType. Any class or struct that has a + public constructor, a public copy constructor, and a public + destructor can be registered. + + After a type has been registered, you can create and destroy + objects of that type dynamically at run-time. + + This example registers the class \c{MyClass}: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetatype.cpp 4 + + \sa qRegisterMetaTypeStreamOperators(), QMetaType::isRegistered(), + Q_DECLARE_METATYPE() +*/ + +/*! + \fn int qRegisterMetaTypeStreamOperators(const char *typeName) + \relates QMetaType + \threadsafe + + Registers the stream operators for the type \c{T} called \a + typeName. + + Afterward, the type can be streamed using QMetaType::load() and + QMetaType::save(). These functions are used when streaming a + QVariant. + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetatype.cpp 5 + + The stream operators should have the following signatures: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetatype.cpp 6 + + \sa qRegisterMetaType(), QMetaType::isRegistered(), Q_DECLARE_METATYPE() +*/ + +/*! \typedef QMetaType::Destructor + \internal +*/ +/*! \typedef QMetaType::Constructor + \internal +*/ +/*! \typedef QMetaType::SaveOperator + \internal +*/ +/*! \typedef QMetaType::LoadOperator + \internal +*/ + +/*! + \fn int qRegisterMetaType() + \relates QMetaType + \threadsafe + \since 4.2 + + Call this function to register the type \c T. \c T must be declared with + Q_DECLARE_METATYPE(). Returns the meta type Id. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetatype.cpp 7 + + To use the type \c T in QVariant, using Q_DECLARE_METATYPE() is + sufficient. To use the type \c T in queued signal and slot connections, + \c{qRegisterMetaType<T>()} must be called before the first connection + is established. + + Also, to use type \c T with the QObject::property() API, + \c{qRegisterMetaType<T>()} must be called before it is used, typically + in the constructor of the class that uses \c T, or in the \c{main()} + function. + + \sa Q_DECLARE_METATYPE() + */ + +/*! \fn int qMetaTypeId() + \relates QMetaType + \threadsafe + \since 4.1 + + Returns the meta type id of type \c T at compile time. If the + type was not declared with Q_DECLARE_METATYPE(), compilation will + fail. + + Typical usage: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmetatype.cpp 8 + + QMetaType::type() returns the same ID as qMetaTypeId(), but does + a lookup at runtime based on the name of the type. + QMetaType::type() is a bit slower, but compilation succeeds if a + type is not registered. + + \sa Q_DECLARE_METATYPE(), QMetaType::type() +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h new file mode 100644 index 0000000..648f933 --- /dev/null +++ b/src/corelib/kernel/qmetatype.h @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETATYPE_H +#define QMETATYPE_H + +#include <QtCore/qglobal.h> +#include <QtCore/qatomic.h> + +#ifndef QT_NO_DATASTREAM +#include <QtCore/qdatastream.h> +#endif + +#ifdef Bool +#error qmetatype.h must be included before any header file that defines Bool +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class Q_CORE_EXPORT QMetaType { +public: + enum Type { + // these are merged with QVariant + Void = 0, Bool = 1, Int = 2, UInt = 3, LongLong = 4, ULongLong = 5, + Double = 6, QChar = 7, QVariantMap = 8, QVariantList = 9, + QString = 10, QStringList = 11, QByteArray = 12, + QBitArray = 13, QDate = 14, QTime = 15, QDateTime = 16, QUrl = 17, + QLocale = 18, QRect = 19, QRectF = 20, QSize = 21, QSizeF = 22, + QLine = 23, QLineF = 24, QPoint = 25, QPointF = 26, QRegExp = 27, + QVariantHash = 28, LastCoreType = 28 /* QVariantHash */, + + FirstGuiType = 63 /* QColorGroup */, +#ifdef QT3_SUPPORT + QColorGroup = 63, +#endif + QFont = 64, QPixmap = 65, QBrush = 66, QColor = 67, QPalette = 68, + QIcon = 69, QImage = 70, QPolygon = 71, QRegion = 72, QBitmap = 73, + QCursor = 74, QSizePolicy = 75, QKeySequence = 76, QPen = 77, + QTextLength = 78, QTextFormat = 79, QMatrix = 80, QTransform = 81, + LastGuiType = 81 /* QTransform */, + + FirstCoreExtType = 128 /* VoidStar */, + VoidStar = 128, Long = 129, Short = 130, Char = 131, ULong = 132, + UShort = 133, UChar = 134, Float = 135, QObjectStar = 136, QWidgetStar = 137, + LastCoreExtType = 137 /* QWidgetStar */, + + User = 256 + }; + + typedef void (*Destructor)(void *); + typedef void *(*Constructor)(const void *); + +#ifndef QT_NO_DATASTREAM + typedef void (*SaveOperator)(QDataStream &, const void *); + typedef void (*LoadOperator)(QDataStream &, void *); + static void registerStreamOperators(const char *typeName, SaveOperator saveOp, + LoadOperator loadOp); +#endif + static int registerType(const char *typeName, Destructor destructor, + Constructor constructor); + static int type(const char *typeName); + static const char *typeName(int type); + static bool isRegistered(int type); + static void *construct(int type, const void *copy = 0); + static void destroy(int type, void *data); + static void unregisterType(const char *typeName); + +#ifndef QT_NO_DATASTREAM + static bool save(QDataStream &stream, int type, const void *data); + static bool load(QDataStream &stream, int type, void *data); +#endif +}; + +template <typename T> +void qMetaTypeDeleteHelper(T *t) +{ + delete t; +} + +template <typename T> +void *qMetaTypeConstructHelper(const T *t) +{ + if (!t) + return new T; + return new T(*static_cast<const T*>(t)); +} + +#ifndef QT_NO_DATASTREAM +template <typename T> +void qMetaTypeSaveHelper(QDataStream &stream, const T *t) +{ + stream << *t; +} + +template <typename T> +void qMetaTypeLoadHelper(QDataStream &stream, T *t) +{ + stream >> *t; +} +#endif // QT_NO_DATASTREAM + +template <typename T> +int qRegisterMetaType(const char *typeName +#ifndef qdoc + , T * /* dummy */ = 0 +#endif +) +{ + typedef void*(*ConstructPtr)(const T*); + ConstructPtr cptr = qMetaTypeConstructHelper<T>; + typedef void(*DeletePtr)(T*); + DeletePtr dptr = qMetaTypeDeleteHelper<T>; + + return QMetaType::registerType(typeName, reinterpret_cast<QMetaType::Destructor>(dptr), + reinterpret_cast<QMetaType::Constructor>(cptr)); +} + +#ifndef QT_NO_DATASTREAM +template <typename T> +void qRegisterMetaTypeStreamOperators(const char *typeName +#ifndef qdoc + , T * /* dummy */ = 0 +#endif +) +{ + typedef void(*SavePtr)(QDataStream &, const T *); + typedef void(*LoadPtr)(QDataStream &, T *); + SavePtr sptr = qMetaTypeSaveHelper<T>; + LoadPtr lptr = qMetaTypeLoadHelper<T>; + + qRegisterMetaType<T>(typeName); + QMetaType::registerStreamOperators(typeName, reinterpret_cast<QMetaType::SaveOperator>(sptr), + reinterpret_cast<QMetaType::LoadOperator>(lptr)); +} +#endif + +template <typename T> +struct QMetaTypeId +{ + enum { Defined = 0 }; +}; + +template <typename T> +struct QMetaTypeId2 +{ + enum { Defined = QMetaTypeId<T>::Defined }; + static inline int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); } +}; + +template <typename T> +inline int qMetaTypeId( +#ifndef qdoc + T * /* dummy */ = 0 +#endif +) +{ + return QMetaTypeId2<T>::qt_metatype_id(); +} + +template <typename T> +inline int qRegisterMetaType( +#if !defined(qdoc) && !defined(Q_CC_SUN) + T * dummy = 0 +#endif +) +{ +#ifdef Q_CC_SUN + return qMetaTypeId(static_cast<T *>(0)); +#else + return qMetaTypeId(dummy); +#endif +} + +#define Q_DECLARE_METATYPE(TYPE) \ + QT_BEGIN_NAMESPACE \ + template <> \ + struct QMetaTypeId< TYPE > \ + { \ + enum { Defined = 1 }; \ + static int qt_metatype_id() \ + { \ + static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ + if (!metatype_id) \ + metatype_id = qRegisterMetaType< TYPE >(#TYPE); \ + return metatype_id; \ + } \ + }; \ + QT_END_NAMESPACE + +#define Q_DECLARE_BUILTIN_METATYPE(TYPE, NAME) \ + QT_BEGIN_NAMESPACE \ + template<> struct QMetaTypeId2<TYPE> \ + { \ + enum { Defined = 1, MetaType = QMetaType::NAME }; \ + static inline int qt_metatype_id() { return QMetaType::NAME; } \ + }; \ + QT_END_NAMESPACE + +class QString; +class QByteArray; +class QChar; +class QStringList; +class QBitArray; +class QDate; +class QTime; +class QDateTime; +class QUrl; +class QLocale; +class QRect; +class QRectF; +class QSize; +class QSizeF; +class QLine; +class QLineF; +class QPoint; +class QPointF; +#ifndef QT_NO_REGEXP +class QRegExp; +#endif +class QWidget; +class QObject; + +#ifdef QT3_SUPPORT +class QColorGroup; +#endif +class QFont; +class QPixmap; +class QBrush; +class QColor; +class QPalette; +class QIcon; +class QImage; +class QPolygon; +class QRegion; +class QBitmap; +class QCursor; +class QSizePolicy; +class QKeySequence; +class QPen; +class QTextLength; +class QTextFormat; +class QMatrix; +class QTransform; + +QT_END_NAMESPACE + +Q_DECLARE_BUILTIN_METATYPE(QString, QString) +Q_DECLARE_BUILTIN_METATYPE(int, Int) +Q_DECLARE_BUILTIN_METATYPE(uint, UInt) +Q_DECLARE_BUILTIN_METATYPE(bool, Bool) +Q_DECLARE_BUILTIN_METATYPE(double, Double) +Q_DECLARE_BUILTIN_METATYPE(QByteArray, QByteArray) +Q_DECLARE_BUILTIN_METATYPE(QChar, QChar) +Q_DECLARE_BUILTIN_METATYPE(long, Long) +Q_DECLARE_BUILTIN_METATYPE(short, Short) +Q_DECLARE_BUILTIN_METATYPE(char, Char) +Q_DECLARE_BUILTIN_METATYPE(ulong, ULong) +Q_DECLARE_BUILTIN_METATYPE(ushort, UShort) +Q_DECLARE_BUILTIN_METATYPE(uchar, UChar) +Q_DECLARE_BUILTIN_METATYPE(float, Float) +Q_DECLARE_BUILTIN_METATYPE(QObject *, QObjectStar) +Q_DECLARE_BUILTIN_METATYPE(QWidget *, QWidgetStar) +Q_DECLARE_BUILTIN_METATYPE(void *, VoidStar) +Q_DECLARE_BUILTIN_METATYPE(qlonglong, LongLong) +Q_DECLARE_BUILTIN_METATYPE(qulonglong, ULongLong) +Q_DECLARE_BUILTIN_METATYPE(QStringList, QStringList) +Q_DECLARE_BUILTIN_METATYPE(QBitArray, QBitArray) +Q_DECLARE_BUILTIN_METATYPE(QDate, QDate) +Q_DECLARE_BUILTIN_METATYPE(QTime, QTime) +Q_DECLARE_BUILTIN_METATYPE(QDateTime, QDateTime) +Q_DECLARE_BUILTIN_METATYPE(QUrl, QUrl) +Q_DECLARE_BUILTIN_METATYPE(QLocale, QLocale) +Q_DECLARE_BUILTIN_METATYPE(QRect, QRect) +Q_DECLARE_BUILTIN_METATYPE(QRectF, QRectF) +Q_DECLARE_BUILTIN_METATYPE(QSize, QSize) +Q_DECLARE_BUILTIN_METATYPE(QSizeF, QSizeF) +Q_DECLARE_BUILTIN_METATYPE(QLine, QLine) +Q_DECLARE_BUILTIN_METATYPE(QLineF, QLineF) +Q_DECLARE_BUILTIN_METATYPE(QPoint, QPoint) +Q_DECLARE_BUILTIN_METATYPE(QPointF, QPointF) +#ifndef QT_NO_REGEXP +Q_DECLARE_BUILTIN_METATYPE(QRegExp, QRegExp) +#endif + +#ifdef QT3_SUPPORT +Q_DECLARE_BUILTIN_METATYPE(QColorGroup, QColorGroup) +#endif +Q_DECLARE_BUILTIN_METATYPE(QFont, QFont) +Q_DECLARE_BUILTIN_METATYPE(QPixmap, QPixmap) +Q_DECLARE_BUILTIN_METATYPE(QBrush, QBrush) +Q_DECLARE_BUILTIN_METATYPE(QColor, QColor) +Q_DECLARE_BUILTIN_METATYPE(QPalette, QPalette) +Q_DECLARE_BUILTIN_METATYPE(QIcon, QIcon) +Q_DECLARE_BUILTIN_METATYPE(QImage, QImage) +Q_DECLARE_BUILTIN_METATYPE(QPolygon, QPolygon) +Q_DECLARE_BUILTIN_METATYPE(QRegion, QRegion) +Q_DECLARE_BUILTIN_METATYPE(QBitmap, QBitmap) +Q_DECLARE_BUILTIN_METATYPE(QCursor, QCursor) +Q_DECLARE_BUILTIN_METATYPE(QSizePolicy, QSizePolicy) +Q_DECLARE_BUILTIN_METATYPE(QKeySequence, QKeySequence) +Q_DECLARE_BUILTIN_METATYPE(QPen, QPen) +Q_DECLARE_BUILTIN_METATYPE(QTextLength, QTextLength) +Q_DECLARE_BUILTIN_METATYPE(QTextFormat, QTextFormat) +Q_DECLARE_BUILTIN_METATYPE(QMatrix, QMatrix) +Q_DECLARE_BUILTIN_METATYPE(QTransform, QTransform) + +QT_END_HEADER + +#endif // QMETATYPE_H diff --git a/src/corelib/kernel/qmimedata.cpp b/src/corelib/kernel/qmimedata.cpp new file mode 100644 index 0000000..f1c8e53 --- /dev/null +++ b/src/corelib/kernel/qmimedata.cpp @@ -0,0 +1,627 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmimedata.h" + +#include "private/qobject_p.h" +#include "qurl.h" +#include "qstringlist.h" +#include "qtextcodec.h" + +QT_BEGIN_NAMESPACE + +struct QMimeDataStruct +{ + QString format; + QVariant data; +}; + +class QMimeDataPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QMimeData) +public: + void removeData(const QString &format); + void setData(const QString &format, const QVariant &data); + QVariant getData(const QString &format) const; + + QVariant retrieveTypedData(const QString &format, QVariant::Type type) const; + + QList<QMimeDataStruct> dataList; +}; + +void QMimeDataPrivate::removeData(const QString &format) +{ + for (int i=0; i<dataList.size(); i++) { + if (dataList.at(i).format == format) { + dataList.removeAt(i); + return; + } + } +} + +void QMimeDataPrivate::setData(const QString &format, const QVariant &data) +{ + // remove it first if the format is already here. + removeData(format); + QMimeDataStruct mimeData; + mimeData.format = format; + mimeData.data = data; + dataList += mimeData; +} + + +QVariant QMimeDataPrivate::getData(const QString &format) const +{ + QVariant data; + for (int i=0; i<dataList.size(); i++) { + if (dataList.at(i).format == format) { + data = dataList.at(i).data; + break; + } + } + return data; +} + +QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QVariant::Type type) const +{ + Q_Q(const QMimeData); + + QVariant data = q->retrieveData(format, type); + if (data.type() == type || data.type() == QVariant::Invalid) + return data; + + // provide more conversion possiblities than just what QVariant provides + + // URLs can be lists as well... + if ((type == QVariant::Url && data.type() == QVariant::List) + || (type == QVariant::List && data.type() == QVariant::Url)) + return data; + + // images and pixmaps are interchangeable + if ((type == QVariant::Pixmap && data.type() == QVariant::Image) + || (type == QVariant::Image && data.type() == QVariant::Pixmap)) + return data; + + if (data.type() == QVariant::ByteArray) { + // see if we can convert to the requested type + switch(type) { +#ifndef QT_NO_TEXTCODEC + case QVariant::String: { + const QByteArray ba = data.toByteArray(); + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + if (format == QLatin1String("text/html")) + codec = QTextCodec::codecForHtml(ba, codec); + return codec->toUnicode(ba); + } +#endif // QT_NO_TEXTCODEC + case QVariant::Color: { + QVariant newData = data; + newData.convert(QVariant::Color); + return newData; + } + case QVariant::List: { + if (format != QLatin1String("text/uri-list")) + break; + // fall through + } + case QVariant::Url: { + QByteArray ba = data.toByteArray(); + // Qt 3.x will send text/uri-list with a trailing + // null-terminator (that is *not* sent for any other + // text/* mime-type), so chop it off + if (ba.endsWith('\0')) + ba.chop(1); + + QList<QByteArray> urls = ba.split('\n'); + QList<QVariant> list; + for (int i = 0; i < urls.size(); ++i) { + QByteArray ba = urls.at(i).trimmed(); + if (!ba.isEmpty()) + list.append(QUrl::fromEncoded(ba)); + } + return list; + } + default: + break; + } + + } else if (type == QVariant::ByteArray) { + + // try to convert to bytearray + switch(data.type()) { + case QVariant::ByteArray: + case QVariant::Color: + return data.toByteArray(); + break; + case QVariant::String: + return data.toString().toUtf8(); + break; + case QVariant::Url: + return data.toUrl().toEncoded(); + break; + case QVariant::List: { + // has to be list of URLs + QByteArray result; + QList<QVariant> list = data.toList(); + for (int i = 0; i < list.size(); ++i) { + if (list.at(i).type() == QVariant::Url) { + result += list.at(i).toUrl().toEncoded(); + result += "\r\n"; + } + } + if (!result.isEmpty()) + return result; + break; + } + default: + break; + } + } + return data; +} + +/*! + \class QMimeData + \brief The QMimeData class provides a container for data that records information + about its MIME type. + + QMimeData is used to describe information that can be stored in + the \l{QClipboard}{clipboard}, and transferred via the \l{drag + and drop} mechanism. QMimeData objects associate the data that + they hold with the corresponding MIME types to ensure that + information can be safely transferred between applications, and + copied around within the same application. + + QMimeData objects are usually created using \c new and supplied + to QDrag or QClipboard objects. This is to enable Qt to manage + the memory that they use. + + A single QMimeData object can store the same data using several + different formats at the same time. The formats() function + returns a list of the available formats in order of preference. + The data() function returns the raw data associated with a MIME + type, and setData() allows you to set the data for a MIME type. + + For the most common MIME types, QMimeData provides convenience + functions to access the data: + + \table + \header \o Tester \o Getter \o Setter \o MIME Types + \row \o hasText() \o text() \o setText() \o \c text/plain + \row \o hasHtml() \o html() \o setHtml() \o \c text/html + \row \o hasUrls() \o urls() \o setUrls() \o \c text/uri-list + \row \o hasImage() \o imageData() \o setImageData() \o \c image/ * + \row \o hasColor() \o colorData() \o setColorData() \o \c application/x-color + \endtable + + For example, if your write a widget that accepts URL drags, you + would end up writing code like this: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmimedata.cpp 0 + + There are three approaches for storing custom data in a QMimeData + object: + + \list 1 + \o Custom data can be stored directly in a QMimeData object as a + QByteArray using setData(). For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmimedata.cpp 1 + + \o We can subclass QMimeData and reimplement hasFormat(), + formats(), and retrieveData(). + + \o If the drag and drop operation occurs withing a single + application, we can subclass QMimeData and add extra data in + it, and use a qobject_cast() in the receiver's drop event + handler. For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmimedata.cpp 2 + \endlist + + \section1 Platform-Specific MIME Types + + On Windows, formats() will also return custom formats available + in the MIME data, using the \c{x-qt-windows-mime} subtype to + indicate that they represent data in non-standard formats. + The formats will take the following form: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmimedata.cpp 3 + + The following are examples of custom MIME types: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmimedata.cpp 4 + + The \c value declaration of each format describes the way in which the + data is encoded. + + On Windows, the MIME format does not always map directly to the + clipboard formats. Qt provides QWindowsMime to map clipboard + formats to open-standard MIME formats. Similarly, the + QMacPasteboardMime maps MIME to Mac flavors. + + \sa QClipboard, QDragEnterEvent, QDragMoveEvent, QDropEvent, QDrag, + QWindowsMime, QMacPasteboardMime, {Drag and Drop} +*/ + +/*! + Constructs a new MIME data object with no data in it. +*/ +QMimeData::QMimeData() + : QObject(*new QMimeDataPrivate, 0) +{ +} + +/*! + Destroys the MIME data object. +*/ +QMimeData::~QMimeData() +{ +} + +/*! + Returns a list of URLs contained within the MIME data object. + + URLs correspond to the MIME type \c text/uri-list. + + \sa hasUrls(), data() +*/ +QList<QUrl> QMimeData::urls() const +{ + Q_D(const QMimeData); + QVariant data = d->retrieveTypedData(QLatin1String("text/uri-list"), QVariant::List); + QList<QUrl> urls; + if (data.type() == QVariant::Url) + urls.append(data.toUrl()); + else if (data.type() == QVariant::List) { + QList<QVariant> list = data.toList(); + for (int i = 0; i < list.size(); ++i) { + if (list.at(i).type() == QVariant::Url) + urls.append(list.at(i).toUrl()); + } + } + return urls; +} + +/*! + Sets the URLs stored in the MIME data object to those specified by \a urls. + + URLs correspond to the MIME type \c text/uri-list. + + \sa hasUrls(), setData() +*/ +void QMimeData::setUrls(const QList<QUrl> &urls) +{ + Q_D(QMimeData); + QList<QVariant> list; + for (int i = 0; i < urls.size(); ++i) + list.append(urls.at(i)); + + d->setData(QLatin1String("text/uri-list"), list); +} + +/*! + Returns true if the object can return a list of urls; otherwise + returns false. + + URLs correspond to the MIME type \c text/uri-list. + + \sa setUrls(), urls(), hasFormat() +*/ +bool QMimeData::hasUrls() const +{ + return hasFormat(QLatin1String("text/uri-list")); +} + + +/*! + Returns a plain text (MIME type \c text/plain) representation of + the data. + + \sa hasText(), html(), data() +*/ +QString QMimeData::text() const +{ + Q_D(const QMimeData); + QVariant data = d->retrieveTypedData(QLatin1String("text/plain"), QVariant::String); + return data.toString(); +} + +/*! + Sets \a text as the plain text (MIME type \c text/plain) used to + represent the data. + + \sa hasText(), setHtml(), setData() +*/ +void QMimeData::setText(const QString &text) +{ + Q_D(QMimeData); + d->setData(QLatin1String("text/plain"), text); +} + +/*! + Returns true if the object can return plain text (MIME type \c + text/plain); otherwise returns false. + + \sa setText(), text(), hasHtml(), hasFormat() +*/ +bool QMimeData::hasText() const +{ + return hasFormat(QLatin1String("text/plain")); +} + +/*! + Returns a string if the data stored in the object is HTML (MIME + type \c text/html); otherwise returns an empty string. + + \sa hasHtml(), setData() +*/ +QString QMimeData::html() const +{ + Q_D(const QMimeData); + QVariant data = d->retrieveTypedData(QLatin1String("text/html"), QVariant::String); + return data.toString(); +} + +/*! + Sets \a html as the HTML (MIME type \c text/html) used to + represent the data. + + \sa hasHtml(), setText(), setData() +*/ +void QMimeData::setHtml(const QString &html) +{ + Q_D(QMimeData); + d->setData(QLatin1String("text/html"), html); +} + +/*! + Returns true if the object can return HTML (MIME type \c + text/html); otherwise returns false. + + \sa setHtml(), html(), hasFormat() +*/ +bool QMimeData::hasHtml() const +{ + return hasFormat(QLatin1String("text/html")); +} + +/*! + Returns a QVariant storing a QImage if the object can return an + image; otherwise returns a null variant. + + A QVariant is used because QMimeData belongs to the \l QtCore + library, whereas QImage belongs to \l QtGui. To convert the + QVariant to a QImage, simply use qvariant_cast(). For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmimedata.cpp 5 + + \sa hasImage() +*/ +QVariant QMimeData::imageData() const +{ + Q_D(const QMimeData); + return d->retrieveTypedData(QLatin1String("application/x-qt-image"), QVariant::Image); +} + +/*! + Sets the data in the object to the given \a image. + + A QVariant is used because QMimeData belongs to the \l QtCore + library, whereas QImage belongs to \l QtGui. The conversion + from QImage to QVariant is implicit. For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmimedata.cpp 6 + + \sa hasImage(), setData() +*/ +void QMimeData::setImageData(const QVariant &image) +{ + Q_D(QMimeData); + d->setData(QLatin1String("application/x-qt-image"), image); +} + +/*! + Returns true if the object can return an image; otherwise returns + false. + + \sa setImageData(), imageData(), hasFormat() +*/ +bool QMimeData::hasImage() const +{ + return hasFormat(QLatin1String("application/x-qt-image")); +} + +/*! + Returns a color if the data stored in the object represents a + color (MIME type \c application/x-color); otherwise returns a + null variant. + + A QVariant is used because QMimeData belongs to the \l QtCore + library, whereas QColor belongs to \l QtGui. To convert the + QVariant to a QColor, simply use qvariant_cast(). For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qmimedata.cpp 7 + + \sa hasColor(), setColorData(), data() +*/ +QVariant QMimeData::colorData() const +{ + Q_D(const QMimeData); + return d->retrieveTypedData(QLatin1String("application/x-color"), QVariant::Color); +} + +/*! + Sets the color data in the object to the given \a color. + + Colors correspond to the MIME type \c application/x-color. + + \sa hasColor(), setData() +*/ +void QMimeData::setColorData(const QVariant &color) +{ + Q_D(QMimeData); + d->setData(QLatin1String("application/x-color"), color); +} + + +/*! + Returns true if the object can return a color (MIME type \c + application/x-color); otherwise returns false. + + \sa setColorData(), colorData(), hasFormat() +*/ +bool QMimeData::hasColor() const +{ + return hasFormat(QLatin1String("application/x-color")); +} + +/*! + Returns the data stored in the object in the format described by + the MIME type specified by \a mimeType. +*/ +QByteArray QMimeData::data(const QString &mimeType) const +{ + Q_D(const QMimeData); + QVariant data = d->retrieveTypedData(mimeType, QVariant::ByteArray); + return data.toByteArray(); +} + +/*! + Sets the data associated with the MIME type given by \a mimeType + to the specified \a data. + + For the most common types of data, you can call the higher-level + functions setText(), setHtml(), setUrls(), setImageData(), and + setColorData() instead. + + Note that if you want to use a custom data type in an item view drag and drop + operation, you must register it as a Qt \l{QMetaType}{meta type}, using the + Q_DECLARE_METATYPE() macro, and implement stream operators for it. The stream + operators must then be registered with the qRegisterMetaTypeStreamOperators() + function. + + \sa hasFormat(), QMetaType, qRegisterMetaTypeStreamOperators() +*/ +void QMimeData::setData(const QString &mimeType, const QByteArray &data) +{ + Q_D(QMimeData); + d->setData(mimeType, QVariant(data)); +} + +/*! + Returns true if the object can return data for the MIME type + specified by \a mimeType; otherwise returns false. + + For the most common types of data, you can call the higher-level + functions hasText(), hasHtml(), hasUrls(), hasImage(), and + hasColor() instead. + + \sa formats(), setData(), data() +*/ +bool QMimeData::hasFormat(const QString &mimeType) const +{ + return formats().contains(mimeType); +} + +/*! + Returns a list of formats supported by the object. This is a list + of MIME types for which the object can return suitable data. The + formats in the list are in a priority order. + + For the most common types of data, you can call the higher-level + functions hasText(), hasHtml(), hasUrls(), hasImage(), and + hasColor() instead. + + \sa hasFormat(), setData(), data() +*/ +QStringList QMimeData::formats() const +{ + Q_D(const QMimeData); + QStringList list; + for (int i=0; i<d->dataList.size(); i++) + list += d->dataList.at(i).format; + return list; +} + +/*! + Returns a variant with the given \a type containing data for the + MIME type specified by \a mimeType. If the object does not + support the MIME type or variant type given, a null variant is + returned instead. + + This function is called by the general data() getter and by the + convenience getters (text(), html(), urls(), imageData(), and + colorData()). You can reimplement it if you want to store your + data using a custom data structure (instead of a QByteArray, + which is what setData() provides). You would then also need + to reimplement hasFormat() and formats(). + + \sa data() +*/ +QVariant QMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const +{ + Q_UNUSED(type); + Q_D(const QMimeData); + return d->getData(mimeType); +} + +/*! + Removes all the MIME type and data entries in the object. +*/ +void QMimeData::clear() +{ + Q_D(QMimeData); + d->dataList.clear(); +} + +/*! + \since 4.4 + + Removes the data entry for \a mimeType in the object. +*/ +void QMimeData::removeFormat(const QString &mimeType) +{ + Q_D(QMimeData); + d->removeData(mimeType); +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmimedata.h b/src/corelib/kernel/qmimedata.h new file mode 100644 index 0000000..47c5075 --- /dev/null +++ b/src/corelib/kernel/qmimedata.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMIMEDATA_H +#define QMIMEDATA_H + +#include <QtCore/qvariant.h> +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QUrl; +class QMimeDataPrivate; + +class Q_CORE_EXPORT QMimeData : public QObject +{ + Q_OBJECT +public: + QMimeData(); + ~QMimeData(); + + QList<QUrl> urls() const; + void setUrls(const QList<QUrl> &urls); + bool hasUrls() const; + + QString text() const; + void setText(const QString &text); + bool hasText() const; + + QString html() const; + void setHtml(const QString &html); + bool hasHtml() const; + + QVariant imageData() const; + void setImageData(const QVariant &image); + bool hasImage() const; + + QVariant colorData() const; + void setColorData(const QVariant &color); + bool hasColor() const; + + QByteArray data(const QString &mimetype) const; + void setData(const QString &mimetype, const QByteArray &data); + void removeFormat(const QString &mimetype); + + virtual bool hasFormat(const QString &mimetype) const; + virtual QStringList formats() const; + + void clear(); +protected: + virtual QVariant retrieveData(const QString &mimetype, + QVariant::Type preferredType) const; +private: + Q_DISABLE_COPY(QMimeData) + Q_DECLARE_PRIVATE(QMimeData) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMIMEDATA_H diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp new file mode 100644 index 0000000..55cf464 --- /dev/null +++ b/src/corelib/kernel/qobject.cpp @@ -0,0 +1,3818 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qobject.h" +#include "qobject_p.h" + +#include "qabstracteventdispatcher.h" +#include "qcoreapplication.h" +#include "qcoreapplication_p.h" +#include "qvariant.h" +#include "qmetaobject.h" +#include <qregexp.h> +#include <qthread.h> +#include <private/qthread_p.h> +#include <qdebug.h> +#include <qhash.h> +#include <qpair.h> +#include <qvarlengtharray.h> +#include <qset.h> +#include <qsemaphore.h> + +#include <private/qorderedmutexlocker_p.h> + +#include <new> + +#include <ctype.h> +#include <limits.h> + +QT_BEGIN_NAMESPACE + +static int DIRECT_CONNECTION_ONLY = 0; + +static int *queuedConnectionTypes(const QList<QByteArray> &typeNames) +{ + int *types = static_cast<int *>(qMalloc((typeNames.count() + 1) * sizeof(int))); + for (int i = 0; i < typeNames.count(); ++i) { + const QByteArray typeName = typeNames.at(i); + if (typeName.endsWith('*')) + types[i] = QMetaType::VoidStar; + else + types[i] = QMetaType::type(typeName); + + if (!types[i]) { + qWarning("QObject::connect: Cannot queue arguments of type '%s'\n" + "(Make sure '%s' is registered using qRegisterMetaType().)", + typeName.constData(), typeName.constData()); + qFree(types); + return 0; + } + } + types[typeNames.count()] = 0; + + return types; +} + +extern "C" Q_CORE_EXPORT void qt_addObject(QObject *) +{ +} + +extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) +{ +} + +QObjectPrivate::QObjectPrivate(int version) + : threadData(0), currentSender(0), currentChildBeingDeleted(0), connectionLists(0) +{ + if (version != QObjectPrivateVersion) + qFatal("Cannot mix incompatible Qt libraries"); + + // QObjectData initialization + q_ptr = 0; + parent = 0; // no parent yet. It is set by setParent() + isWidget = false; // assume not a widget object + pendTimer = false; // no timers yet + blockSig = false; // not blocking signals + wasDeleted = false; // double-delete catcher + sendChildEvents = true; // if we should send ChildInsert and ChildRemove events to parent + receiveChildEvents = true; + postedEvents = 0; + extraData = 0; + connectedSignals = 0; + inEventHandler = false; + inThreadChangeEvent = false; + deleteWatch = 0; +} + +QObjectPrivate::~QObjectPrivate() +{ + if (deleteWatch) + *deleteWatch = 1; +#ifndef QT_NO_USERDATA + if (extraData) + qDeleteAll(extraData->userData); + delete extraData; +#endif +} + + +int *QObjectPrivate::setDeleteWatch(QObjectPrivate *d, int *w) { + int *old = d->deleteWatch; + d->deleteWatch = w; + return old; +} + + +void QObjectPrivate::resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch) { + if (!deleteWatch) + d->deleteWatch = oldWatch; + + if (oldWatch) + *oldWatch = deleteWatch; +} + + + + + +#ifdef QT3_SUPPORT +void QObjectPrivate::sendPendingChildInsertedEvents() +{ + Q_Q(QObject); + for (int i = 0; i < pendingChildInsertedEvents.size(); ++i) { + QObject *c = pendingChildInsertedEvents.at(i); + if (!c) + continue; + QChildEvent childEvent(QEvent::ChildInserted, c); + QCoreApplication::sendEvent(q, &childEvent); + } + pendingChildInsertedEvents.clear(); +} + +void QObjectPrivate::removePendingChildInsertedEvents(QObject *child) +{ + if (!child) { + pendingChildInsertedEvents.clear(); + return; + } + + // the QObject destructor calls QObject::removeChild, which calls + // QCoreApplication::sendEvent() directly. this can happen while the event + // loop is in the middle of posting events, and when we get here, we may + // not have any more posted events for this object. + + // if this is a child remove event and the child insert hasn't + // been dispatched yet, kill that insert + for (int i = 0; i < pendingChildInsertedEvents.size(); ++i) { + QObject *&c = pendingChildInsertedEvents[i]; + if (c == child) + c = 0; + } +} +#endif + + +class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList> +{ +public: + bool orphaned; + bool dirty; + int inUse; + QObjectPrivate::ConnectionList allsignals; + + QObjectConnectionListVector() + : QVector<QObjectPrivate::ConnectionList>(), orphaned(false), dirty(false), inUse(0) + { } + + const QObjectPrivate::ConnectionList &at(int at) const + { + if (at < 0) + return allsignals; + return QVector<QObjectPrivate::ConnectionList>::at(at); + } + QObjectPrivate::ConnectionList &operator[](int at) + { + if (at < 0) + return allsignals; + return QVector<QObjectPrivate::ConnectionList>::operator[](at); + } +}; + +bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const +{ + Q_Q(const QObject); + int signal_index = q->metaObject()->indexOfSignal(signal); + if (signal_index < 0) + return false; + QMutexLocker locker(&threadData->mutex); + if (connectionLists) { + if (signal_index < connectionLists->count()) { + const ConnectionList &connectionList = connectionLists->at(signal_index); + for (int i = 0; i < connectionList.count(); ++i) { + const QObjectPrivate::Connection &c = connectionList.at(i); + if (c.receiver && c.receiver == receiver) + return true; + } + } + } + return false; +} + +QObjectList QObjectPrivate::receiverList(const char *signal) const +{ + Q_Q(const QObject); + QObjectList returnValue; + int signal_index = q->metaObject()->indexOfSignal(signal); + if (signal_index < 0) + return returnValue; + QMutexLocker locker(&threadData->mutex); + if (connectionLists) { + if (signal_index < connectionLists->count()) { + const ConnectionList &connectionList = connectionLists->at(signal_index); + for (int i = 0; i < connectionList.count(); ++i) { + const QObjectPrivate::Connection &c = connectionList.at(i); + if (c.receiver) + returnValue << c.receiver; + } + } + } + return returnValue; +} + +QObjectList QObjectPrivate::senderList() const +{ + QObjectList returnValue; + QMutexLocker locker(&threadData->mutex); + for (int i = 0; i < senders.count(); ++i) + returnValue << senders.at(i).sender; + return returnValue; +} + +void QObjectPrivate::addConnection(int signal, Connection *c) +{ + if (!connectionLists) + connectionLists = new QObjectConnectionListVector(); + if (signal >= connectionLists->count()) + connectionLists->resize(signal + 1); + + ConnectionList &connectionList = (*connectionLists)[signal]; + connectionList.append(*c); + + cleanConnectionLists(); +} + +void QObjectPrivate::removeReceiver(int signal, QObject *receiver) +{ + if (!connectionLists) + return; + + if (signal >= connectionLists->count()) + return; + + ConnectionList &connectionList = (*connectionLists)[signal]; + for (int i = 0; i < connectionList.count(); ++i) { + Connection &c = connectionList[i]; + if (c.receiver == receiver) { + c.receiver = 0; + if (c.argumentTypes && c.argumentTypes != &DIRECT_CONNECTION_ONLY) { + qFree(c.argumentTypes); + c.argumentTypes = 0; + } + connectionLists->dirty = true; + } + } +} + +void QObjectPrivate::cleanConnectionLists() +{ + if (connectionLists->dirty && !connectionLists->inUse) { + // remove broken connections + for (int signal = -1; signal < connectionLists->count(); ++signal) { + QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal]; + for (int i = 0; i < connectionList.count(); ++i) { + const QObjectPrivate::Connection &c = connectionList.at(i); + if (!c.receiver) + connectionList.removeAt(i--); + } + } + connectionLists->dirty = false; + } +} + +void QObjectPrivate::refSender(QObject *sender, int signal) +{ + for (int i = 0; i < senders.count(); ++i) { + Sender &s = senders[i]; + if (s.sender == sender && s.signal == signal) { + ++s.ref; + return; + } + } + + Sender s = { sender, signal, 1 }; + senders.append(s); +} + +void QObjectPrivate::derefSender(QObject *sender, int signal) +{ + for (int i = 0; i < senders.count(); ++i) { + Sender &s = senders[i]; + if (s.sender == sender && s.signal == signal) { + if (--s.ref == 0) { + senders.removeAt(i); + break; + } + } + } + // Q_ASSERT_X(false, "QObjectPrivate::derefSender", "sender not found"); +} + +void QObjectPrivate::removeSender(QObject *sender, int signal) +{ + for (int i = 0; i < senders.count(); ++i) { + Sender &s = senders[i]; + if (s.sender == sender && s.signal == signal) { + senders.removeAt(i); + return; + } + } + // Q_ASSERT_X(false, "QObjectPrivate::removeSender", "sender not found"); +} + +QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver, + Sender *sender) +{ + Sender *previousSender = receiver->d_func()->currentSender; + receiver->d_func()->currentSender = sender; + return previousSender; +} + +void QObjectPrivate::resetCurrentSender(QObject *receiver, + Sender *currentSender, + Sender *previousSender) +{ + // ref is set to zero when this object is deleted during the metacall + if (currentSender->ref == 1) + receiver->d_func()->currentSender = previousSender; + // if we've recursed, we need to tell the caller about the objects deletion + if (previousSender) + previousSender->ref = currentSender->ref; +} + + +typedef QMultiHash<QObject *, QObject **> GuardHash; +Q_GLOBAL_STATIC(GuardHash, guardHash) +Q_GLOBAL_STATIC(QMutex, guardHashLock) + +/*!\internal + */ +void QMetaObject::addGuard(QObject **ptr) +{ + if (!*ptr) + return; + GuardHash *hash = guardHash(); + if (!hash) { + *ptr = 0; + return; + } + QMutexLocker locker(guardHashLock()); + hash->insert(*ptr, ptr); +} + +/*!\internal + */ +void QMetaObject::removeGuard(QObject **ptr) +{ + if (!*ptr) + return; + GuardHash *hash = guardHash(); + if (!hash) + return; + QMutexLocker locker(guardHashLock()); + GuardHash::iterator it = hash->find(*ptr); + const GuardHash::iterator end = hash->end(); + for (; it.key() == *ptr && it != end; ++it) { + if (it.value() == ptr) { + (void) hash->erase(it); + break; + } + } +} + +/*!\internal + */ +void QMetaObject::changeGuard(QObject **ptr, QObject *o) +{ + GuardHash *hash = guardHash(); + if (!hash) { + *ptr = 0; + return; + } + QMutexLocker locker(guardHashLock()); + if (*ptr) { + GuardHash::iterator it = hash->find(*ptr); + const GuardHash::iterator end = hash->end(); + for (; it.key() == *ptr && it != end; ++it) { + if (it.value() == ptr) { + (void) hash->erase(it); + break; + } + } + } + *ptr = o; + if (*ptr) + hash->insert(*ptr, ptr); +} + +/*! \internal + */ +void QObjectPrivate::clearGuards(QObject *object) +{ + GuardHash *hash = guardHash(); + if (hash) { + QMutexLocker locker(guardHashLock()); + GuardHash::iterator it = hash->find(object); + const GuardHash::iterator end = hash->end(); + while (it.key() == object && it != end) { + *it.value() = 0; + it = hash->erase(it); + } + } +} + +/*! \internal + */ +QMetaCallEvent::QMetaCallEvent(int id, const QObject *sender, int signalId, + int nargs, int *types, void **args, QSemaphore *semaphore) + : QEvent(MetaCall), id_(id), sender_(sender), signalId_(signalId), + nargs_(nargs), types_(types), args_(args), semaphore_(semaphore) +{ } + +/*! \internal + */ +QMetaCallEvent::~QMetaCallEvent() +{ + for (int i = 0; i < nargs_; ++i) { + if (types_[i] && args_[i]) + QMetaType::destroy(types_[i], args_[i]); + } + if (types_) qFree(types_); + if (args_) qFree(args_); +#ifndef QT_NO_THREAD + if (semaphore_) + semaphore_->release(); +#endif +} + +/*! \internal + */ +int QMetaCallEvent::placeMetaCall(QObject *object) +{ + return object->qt_metacall(QMetaObject::InvokeMetaMethod, id_, args_); +} + +/*! + \class QObject + \brief The QObject class is the base class of all Qt objects. + + \ingroup objectmodel + \mainclass + \reentrant + + QObject is the heart of the \l{Qt object model}. The central + feature in this model is a very powerful mechanism for seamless + object communication called \l{signals and slots}. You can + connect a signal to a slot with connect() and destroy the + connection with disconnect(). To avoid never ending notification + loops you can temporarily block signals with blockSignals(). The + protected functions connectNotify() and disconnectNotify() make + it possible to track connections. + + QObjects organize themselves in object trees. When you create a + QObject with another object as parent, the object will + automatically add itself to the parent's children() list. The + parent takes ownership of the object i.e. it will automatically + delete its children in its destructor. You can look for an object + by name and optionally type using findChild() or findChildren(). + + Every object has an objectName() and its class name can be found + via the corresponding metaObject() (see QMetaObject::className()). + You can determine whether the object's class inherits another + class in the QObject inheritance hierarchy by using the + inherits() function. + + When an object is deleted, it emits a destroyed() signal. You can + catch this signal to avoid dangling references to QObjects. + + QObjects can receive events through event() and filter the events + of other objects. See installEventFilter() and eventFilter() for + details. A convenience handler, childEvent(), can be reimplemented + to catch child events. + + Events are delivered in the thread in which the object was + created; see \l{Thread Support in Qt} and thread() for details. + Note that event processing is not done at all for QObjects with no + thread affinity (thread() returns zero). Use the moveToThread() + function to change the thread affinity for an object and its + children (the object cannot be moved if it has a parent). + + Last but not least, QObject provides the basic timer support in + Qt; see QTimer for high-level support for timers. + + Notice that the Q_OBJECT macro is mandatory for any object that + implements signals, slots or properties. You also need to run the + \l{moc}{Meta Object Compiler} on the source file. We strongly + recommend the use of this macro in all subclasses of QObject + regardless of whether or not they actually use signals, slots and + properties, since failure to do so may lead certain functions to + exhibit strange behavior. + + All Qt widgets inherit QObject. The convenience function + isWidgetType() returns whether an object is actually a widget. It + is much faster than + \l{qobject_cast()}{qobject_cast}<QWidget *>(\e{obj}) or + \e{obj}->\l{inherits()}{inherits}("QWidget"). + + Some QObject functions, e.g. children(), return a QObjectList. + QObjectList is a typedef for QList<QObject *>. + + \target No copy constructor + \section1 No copy constructor or assignment operator + + QObject has neither a copy constructor nor an assignment operator. + This is by design. Actually, they are declared, but in a + \c{private} section with the macro Q_DISABLE_COPY(). In fact, all + Qt classes derived from QObject (direct or indirect) use this + macro to declare their copy constructor and assignment operator to + be private. The reasoning is found in the discussion on + \l{Identity vs Value} {Identity vs Value} on the \l{Qt Object + Model} page. + + The main consequence is that you should use pointers to QObject + (or to your QObject subclass) where you might otherwise be tempted + to use your QObject subclass as a value. For example, without a + copy constructor, you can't use a subclass of QObject as the value + to be stored in one of the container classes. You must store + pointers. + + \section2 Auto-Connection + + Qt's meta-object system provides a mechanism to automatically connect + signals and slots between QObject subclasses and their children. As long + as objects are defined with suitable object names, and slots follow a + simple naming convention, this connection can be performed at run-time + by the QMetaObject::connectSlotsByName() function. + + \l uic generates code that invokes this function to enable + auto-connection to be performed between widgets on forms created + with \QD. More information about using auto-connection with \QD is + given in the \l{Using a Designer .ui File in Your Application} section of + the \QD manual. + + \section2 Dynamic Properties + + From Qt 4.2, dynamic properties can be added to and removed from QObject + instances at run-time. Dynamic properties do not need to be declared at + compile-time, yet they provide the same advantages as static properties + and are manipulated using the same API - using property() to read them + and setProperty() to write them. + + From Qt 4.3, dynamic properties are supported by + \l{Qt Designer's Widget Editing Mode#The Property Editor}{Qt Designer}, + and both standard Qt widgets and user-created forms can be given dynamic + properties. + + \sa QMetaObject, QPointer, QObjectCleanupHandler, Q_DISABLE_COPY() + {Object Trees and Object Ownership} +*/ + +/*! + \relates QObject + + Returns a pointer to the object named \a name that inherits \a + type and with a given \a parent. + + Returns 0 if there is no such child. + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 0 +*/ + +void *qt_find_obj_child(QObject *parent, const char *type, const QString &name) +{ + QObjectList list = parent->children(); + if (list.size() == 0) return 0; + for (int i = 0; i < list.size(); ++i) { + QObject *obj = list.at(i); + if (name == obj->objectName() && obj->inherits(type)) + return obj; + } + return 0; +} + + +/***************************************************************************** + QObject member functions + *****************************************************************************/ + +// check the constructor's parent thread argument +static bool check_parent_thread(QObject *parent, + QThreadData *parentThreadData, + QThreadData *currentThreadData) +{ + if (parent && parentThreadData != currentThreadData) { + QThread *parentThread = parentThreadData->thread; + QThread *currentThread = currentThreadData->thread; + qWarning("QObject: Cannot create children for a parent that is in a different thread.\n" + "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)", + parent->metaObject()->className(), + parent, + parentThread ? parentThread->metaObject()->className() : "QThread", + parentThread, + currentThread ? currentThread->metaObject()->className() : "QThread", + currentThread); + return false; + } + return true; +} + +/*! + Constructs an object with parent object \a parent. + + The parent of an object may be viewed as the object's owner. For + instance, a \l{QDialog}{dialog box} is the parent of the \gui OK + and \gui Cancel buttons it contains. + + The destructor of a parent object destroys all child objects. + + Setting \a parent to 0 constructs an object with no parent. If the + object is a widget, it will become a top-level window. + + \sa parent(), findChild(), findChildren() +*/ + +QObject::QObject(QObject *parent) + : d_ptr(new QObjectPrivate) +{ + Q_D(QObject); + qt_addObject(d_ptr->q_ptr = this); + d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current(); + d->threadData->ref(); + if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData)) + parent = 0; + setParent(parent); +} + +#ifdef QT3_SUPPORT +/*! + \overload QObject() + \obsolete + + Creates a new QObject with the given \a parent and object \a name. + */ +QObject::QObject(QObject *parent, const char *name) + : d_ptr(new QObjectPrivate) +{ + Q_D(QObject); + qt_addObject(d_ptr->q_ptr = this); + d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current(); + d->threadData->ref(); + if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData)) + parent = 0; + setParent(parent); + setObjectName(QString::fromAscii(name)); +} +#endif + +/*! \internal + */ +QObject::QObject(QObjectPrivate &dd, QObject *parent) + : d_ptr(&dd) +{ + Q_D(QObject); + qt_addObject(d_ptr->q_ptr = this); + d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current(); + d->threadData->ref(); + if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData)) + parent = 0; + if (d->isWidget) { + if (parent) { + d->parent = parent; + d->parent->d_func()->children.append(this); + } + // no events sent here, this is done at the end of the QWidget constructor + } else { + setParent(parent); + } +} + +/*! + Destroys the object, deleting all its child objects. + + All signals to and from the object are automatically disconnected, and + any pending posted events for the object are removed from the event + queue. However, it is often safer to use deleteLater() rather than + deleting a QObject subclass directly. + + \warning All child objects are deleted. If any of these objects + are on the stack or global, sooner or later your program will + crash. We do not recommend holding pointers to child objects from + outside the parent. If you still do, the destroyed() signal gives + you an opportunity to detect when an object is destroyed. + + \warning Deleting a QObject while pending events are waiting to + be delivered can cause a crash. You must not delete the QObject + directly if it exists in a different thread than the one currently + executing. Use deleteLater() instead, which will cause the event + loop to delete the object after all pending events have been + delivered to it. + + \sa deleteLater() +*/ + +QObject::~QObject() +{ + Q_D(QObject); + if (d->wasDeleted) { +#if defined(QT_DEBUG) + qWarning("QObject: Double deletion detected"); +#endif + return; + } + d->wasDeleted = true; + + d->blockSig = 0; // unblock signals so we always emit destroyed() + + if (!d->isWidget) { + // set all QPointers for this object to zero - note that + // ~QWidget() does this for us, so we don't have to do it twice + QObjectPrivate::clearGuards(this); + } + + emit destroyed(this); + + { + QMutexLocker locker(&d->threadData->mutex); + + // set ref to zero to indicate that this object has been deleted + if (d->currentSender != 0) + d->currentSender->ref = 0; + d->currentSender = 0; + + // disconnect all receivers + if (d->connectionLists) { + ++d->connectionLists->inUse; + for (int signal = -1; signal < d->connectionLists->count(); ++signal) { + QObjectPrivate::ConnectionList &connectionList = (*d->connectionLists)[signal]; + for (int i = 0; i < connectionList.count(); ++i) { + QObjectPrivate::Connection *c = &connectionList[i]; + if (!c->receiver) + continue; + + QMutex *m = &c->receiver->d_func()->threadData->mutex; + bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m); + c = &connectionList[i]; + if (c->receiver) + c->receiver->d_func()->removeSender(this, signal); + if (needToUnlock) + m->unlock(); + + if (c->argumentTypes && c->argumentTypes != &DIRECT_CONNECTION_ONLY) { + qFree(c->argumentTypes); + c->argumentTypes = 0; + } + c->receiver = 0; + } + } + + if (!--d->connectionLists->inUse) { + delete d->connectionLists; + } else { + d->connectionLists->orphaned = true; + } + d->connectionLists = 0; + } + + // disconnect all senders + for (int i = 0; i < d->senders.count(); ++i) { + QObjectPrivate::Sender *s = &d->senders[i]; + if (!s->sender) + continue; + + QMutex *m = &s->sender->d_func()->threadData->mutex; + bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m); + s = &d->senders[i]; + if (s->sender) + s->sender->d_func()->removeReceiver(s->signal, this); + if (needToUnlock) + m->unlock(); + } + + d->senders.clear(); + } + + if (d->pendTimer) { + // unregister pending timers + if (d->threadData->eventDispatcher) + d->threadData->eventDispatcher->unregisterTimers(this); + } + +#ifdef QT3_SUPPORT + d->pendingChildInsertedEvents.clear(); +#endif + + d->eventFilters.clear(); + + if (!d->children.isEmpty()) + d->deleteChildren(); + + qt_removeObject(this); + + QMutexLocker locker2(&d->threadData->postEventList.mutex); + if (d->postedEvents > 0) + QCoreApplicationPrivate::removePostedEvents_unlocked(this, 0, d->threadData); + locker2.unlock(); + + if (d->parent) // remove it from parent object + d->setParent_helper(0); + + d->threadData->deref(); + +#ifdef QT_JAMBI_BUILD + if (d->inEventHandler) { + qWarning("QObject: Do not delete object, '%s', during its event handler!", + objectName().isNull() ? "unnamed" : qPrintable(objectName())); + } +#endif + + delete d; + d_ptr = 0; +} + + +/*! + \fn QMetaObject *QObject::metaObject() const + + Returns a pointer to the meta-object of this object. + + A meta-object contains information about a class that inherits + QObject, e.g. class name, superclass name, properties, signals and + slots. Every QObject subclass that contains the Q_OBJECT macro will have a + meta-object. + + The meta-object information is required by the signal/slot + connection mechanism and the property system. The inherits() + function also makes use of the meta-object. + + If you have no pointer to an actual object instance but still + want to access the meta-object of a class, you can use \l + staticMetaObject. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 1 + + \sa staticMetaObject +*/ + +/*! + \variable QObject::staticMetaObject + + This variable stores the meta-object for the class. + + A meta-object contains information about a class that inherits + QObject, e.g. class name, superclass name, properties, signals and + slots. Every class that contains the Q_OBJECT macro will also have + a meta-object. + + The meta-object information is required by the signal/slot + connection mechanism and the property system. The inherits() + function also makes use of the meta-object. + + If you have a pointer to an object, you can use metaObject() to + retrieve the meta-object associated with that object. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 2 + + \sa metaObject() +*/ + +/*! \fn T *qobject_cast<T *>(QObject *object) + \relates QObject + + Returns the given \a object cast to type T if the object is of type + T (or of a subclass); otherwise returns 0. + + The class T must inherit (directly or indirectly) QObject and be + declared with the \l Q_OBJECT macro. + + A class is considered to inherit itself. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 3 + + The qobject_cast() function behaves similarly to the standard C++ + \c dynamic_cast(), with the advantages that it doesn't require + RTTI support and it works across dynamic library boundaries. + + qobject_cast() can also be used in conjunction with interfaces; + see the \l{tools/plugandpaint}{Plug & Paint} example for details. + + \warning If T isn't declared with the Q_OBJECT macro, this + function's return value is undefined. + + \sa QObject::inherits() +*/ + +/*! + \fn bool QObject::inherits(const char *className) const + + Returns true if this object is an instance of a class that + inherits \a className or a QObject subclass that inherits \a + className; otherwise returns false. + + A class is considered to inherit itself. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 4 + + (\l QLayoutItem is not a QObject.) + + Consider using qobject_cast<Type *>(object) instead. The method + is both faster and safer. + + \sa metaObject(), qobject_cast() +*/ + +/*! + \property QObject::objectName + + \brief the name of this object + + You can find an object by name (and type) using findChild(). You can + find a set of objects with findChildren(). + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 5 + + By default, this property contains an empty string. + + \sa metaObject(), QMetaObject::className() +*/ + +QString QObject::objectName() const +{ + Q_D(const QObject); + return d->objectName; +} + +/* + Sets the object's name to \a name. +*/ +void QObject::setObjectName(const QString &name) +{ + Q_D(QObject); + d->objectName = name; +} + + +#ifdef QT3_SUPPORT +/*! \internal + QObject::child is compat but needs to call itself recursively, + that's why we need this helper. +*/ +static QObject *qChildHelper(const char *objName, const char *inheritsClass, + bool recursiveSearch, const QObjectList &children) +{ + if (children.isEmpty()) + return 0; + + bool onlyWidgets = (inheritsClass && qstrcmp(inheritsClass, "QWidget") == 0); + const QLatin1String oName(objName); + for (int i = 0; i < children.size(); ++i) { + QObject *obj = children.at(i); + if (onlyWidgets) { + if (obj->isWidgetType() && (!objName || obj->objectName() == oName)) + return obj; + } else if ((!inheritsClass || obj->inherits(inheritsClass)) + && (!objName || obj->objectName() == oName)) + return obj; + if (recursiveSearch && (obj = qChildHelper(objName, inheritsClass, + recursiveSearch, obj->children()))) + return obj; + } + return 0; +} + + +/*! + Searches the children and optionally grandchildren of this object, + and returns a child that is called \a objName that inherits \a + inheritsClass. If \a inheritsClass is 0 (the default), any class + matches. + + If \a recursiveSearch is true (the default), child() performs a + depth-first search of the object's children. + + If there is no such object, this function returns 0. If there are + more than one, the first one found is returned. +*/ +QObject* QObject::child(const char *objName, const char *inheritsClass, + bool recursiveSearch) const +{ + Q_D(const QObject); + return qChildHelper(objName, inheritsClass, recursiveSearch, d->children); +} +#endif + +/*! + \fn bool QObject::isWidgetType() const + + Returns true if the object is a widget; otherwise returns false. + + Calling this function is equivalent to calling + inherits("QWidget"), except that it is much faster. +*/ + + +/*! + This virtual function receives events to an object and should + return true if the event \a e was recognized and processed. + + The event() function can be reimplemented to customize the + behavior of an object. + + \sa installEventFilter(), timerEvent(), QApplication::sendEvent(), + QApplication::postEvent(), QWidget::event() +*/ + +bool QObject::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::Timer: + timerEvent((QTimerEvent*)e); + break; + +#ifdef QT3_SUPPORT + case QEvent::ChildInsertedRequest: + d_func()->sendPendingChildInsertedEvents(); + break; +#endif + + case QEvent::ChildAdded: + case QEvent::ChildPolished: +#ifdef QT3_SUPPORT + case QEvent::ChildInserted: +#endif + case QEvent::ChildRemoved: + childEvent((QChildEvent*)e); + break; + + case QEvent::DeferredDelete: + qDeleteInEventHandler(this); + break; + + case QEvent::MetaCall: + { + d_func()->inEventHandler = false; + QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e); + QObjectPrivate::Sender currentSender; + currentSender.sender = const_cast<QObject*>(mce->sender()); + currentSender.signal = mce->signalId(); + currentSender.ref = 1; + QObjectPrivate::Sender * const previousSender = + QObjectPrivate::setCurrentSender(this, ¤tSender); +#if defined(QT_NO_EXCEPTIONS) + mce->placeMetaCall(this); +#else + try { + mce->placeMetaCall(this); + } catch (...) { + QObjectPrivate::resetCurrentSender(this, ¤tSender, previousSender); + throw; + } +#endif + QObjectPrivate::resetCurrentSender(this, ¤tSender, previousSender); + break; + } + + case QEvent::ThreadChange: { + Q_D(QObject); + QThreadData *threadData = d->threadData; + QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher; + if (eventDispatcher) { + // set inThreadChangeEvent to true to tell the dispatcher not to release out timer ids + // back to the pool (since the timer ids are moving to a new thread). + d->inThreadChangeEvent = true; + QList<QPair<int, int> > timers = eventDispatcher->registeredTimers(this); + d->inThreadChangeEvent = false; + if (!timers.isEmpty()) { + eventDispatcher->unregisterTimers(this); + QMetaObject::invokeMethod(this, "_q_reregisterTimers", Qt::QueuedConnection, + Q_ARG(void*, (new QList<QPair<int, int> >(timers)))); + } + } + break; + } + + default: + if (e->type() >= QEvent::User) { + customEvent(e); + break; + } + return false; + } + return true; +} + +/*! + \fn void QObject::timerEvent(QTimerEvent *event) + + This event handler can be reimplemented in a subclass to receive + timer events for the object. + + QTimer provides a higher-level interface to the timer + functionality, and also more general information about timers. The + timer event is passed in the \a event parameter. + + \sa startTimer(), killTimer(), event() +*/ + +void QObject::timerEvent(QTimerEvent *) +{ +} + + +/*! + This event handler can be reimplemented in a subclass to receive + child events. The event is passed in the \a event parameter. + + QEvent::ChildAdded and QEvent::ChildRemoved events are sent to + objects when children are added or removed. In both cases you can + only rely on the child being a QObject, or if isWidgetType() + returns true, a QWidget. (This is because, in the + \l{QEvent::ChildAdded}{ChildAdded} case, the child is not yet + fully constructed, and in the \l{QEvent::ChildRemoved}{ChildRemoved} + case it might have been destructed already). + + QEvent::ChildPolished events are sent to widgets when children + are polished, or when polished children are added. If you receive + a child polished event, the child's construction is usually + completed. However, this is not guaranteed, and multiple polish + events may be delivered during the execution of a widget's + constructor. + + For every child widget, you receive one + \l{QEvent::ChildAdded}{ChildAdded} event, zero or more + \l{QEvent::ChildPolished}{ChildPolished} events, and one + \l{QEvent::ChildRemoved}{ChildRemoved} event. + + The \l{QEvent::ChildPolished}{ChildPolished} event is omitted if + a child is removed immediately after it is added. If a child is + polished several times during construction and destruction, you + may receive several child polished events for the same child, + each time with a different virtual table. + + \sa event() +*/ + +void QObject::childEvent(QChildEvent * /* event */) +{ +} + + +/*! + This event handler can be reimplemented in a subclass to receive + custom events. Custom events are user-defined events with a type + value at least as large as the QEvent::User item of the + QEvent::Type enum, and is typically a QEvent subclass. The event + is passed in the \a event parameter. + + \sa event(), QEvent +*/ +void QObject::customEvent(QEvent * /* event */) +{ +} + + + +/*! + Filters events if this object has been installed as an event + filter for the \a watched object. + + In your reimplementation of this function, if you want to filter + the \a event out, i.e. stop it being handled further, return + true; otherwise return false. + + Example: + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 6 + + Notice in the example above that unhandled events are passed to + the base class's eventFilter() function, since the base class + might have reimplemented eventFilter() for its own internal + purposes. + + \warning If you delete the receiver object in this function, be + sure to return true. Otherwise, Qt will forward the event to the + deleted object and the program might crash. + + \sa installEventFilter() +*/ + +bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */) +{ + return false; +} + +/*! + \fn bool QObject::signalsBlocked() const + + Returns true if signals are blocked; otherwise returns false. + + Signals are not blocked by default. + + \sa blockSignals() +*/ + +/*! + If \a block is true, signals emitted by this object are blocked + (i.e., emitting a signal will not invoke anything connected to it). + If \a block is false, no such blocking will occur. + + The return value is the previous value of signalsBlocked(). + + Note that the destroyed() signal will be emitted even if the signals + for this object have been blocked. + + \sa signalsBlocked() +*/ + +bool QObject::blockSignals(bool block) +{ + Q_D(QObject); + bool previous = d->blockSig; + d->blockSig = block; + return previous; +} + +/*! + Returns the thread in which the object lives. + + \sa moveToThread() +*/ +QThread *QObject::thread() const +{ + return d_func()->threadData->thread; +} + +/*! + Changes the thread affinity for this object and its children. The + object cannot be moved if it has a parent. Event processing will + continue in the \a targetThread. + + To move an object to the main thread, use QApplication::instance() + to retrieve a pointer to the current application, and then use + QApplication::thread() to retrieve the thread in which the + application lives. For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 7 + + If \a targetThread is zero, all event processing for this object + and its children stops. + + Note that all active timers for the object will be reset. The + timers are first stopped in the current thread and restarted (with + the same interval) in the \a targetThread. As a result, constantly + moving an object between threads can postpone timer events + indefinitely. + + A QEvent::ThreadChange event is sent to this object just before + the thread affinity is changed. You can handle this event to + perform any special processing. Note that any new events that are + posted to this object will be handled in the \a targetThread. + + \warning This function is \e not thread-safe; the current thread + must be same as the current thread affinity. In other words, this + function can only "push" an object from the current thread to + another thread, it cannot "pull" an object from any arbitrary + thread to the current thread. + + \sa thread() + */ +void QObject::moveToThread(QThread *targetThread) +{ + Q_D(QObject); + + if (d->threadData->thread == targetThread) { + // object is already in this thread + return; + } + + if (d->parent != 0) { + qWarning("QObject::moveToThread: Cannot move objects with a parent"); + return; + } + if (d->isWidget) { + qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread"); + return; + } + + QThreadData *currentData = QThreadData::current(); + QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : new QThreadData(0); + if (d->threadData->thread == 0 && currentData == targetData) { + // one exception to the rule: we allow moving objects with no thread affinity to the current thread + currentData = d->threadData; + } else if (d->threadData != currentData) { + qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n" + "Cannot move to target thread (%p)\n", + d->threadData->thread, currentData->thread, targetData->thread); + +#ifdef Q_WS_MAC + qWarning("On Mac OS X, you might be loading two sets of Qt binaries into the same process. " + "Check that all plugins are compiled against the right Qt binaries. Export " + "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded."); +#endif + + return; + } + + // prepare to move + d->moveToThread_helper(); + + QOrderedMutexLocker locker(¤tData->postEventList.mutex, + &targetData->postEventList.mutex); + + // keep currentData alive (since we've got it locked) + currentData->ref(); + + // move the object + d_func()->setThreadData_helper(currentData, targetData); + + locker.unlock(); + + // now currentData can commit suicide if it wants to + currentData->deref(); +} + +void QObjectPrivate::moveToThread_helper() +{ + Q_Q(QObject); + QEvent e(QEvent::ThreadChange); + QCoreApplication::sendEvent(q, &e); + for (int i = 0; i < children.size(); ++i) { + QObject *child = children.at(i); + child->d_func()->moveToThread_helper(); + } +} + +void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData) +{ + Q_Q(QObject); + + // move posted events + int eventsMoved = 0; + for (int i = 0; i < currentData->postEventList.size(); ++i) { + const QPostEvent &pe = currentData->postEventList.at(i); + if (!pe.event) + continue; + if (pe.receiver == q) { + // move this post event to the targetList + targetData->postEventList.append(pe); + const_cast<QPostEvent &>(pe).event = 0; + ++eventsMoved; + } + } + if (eventsMoved > 0 && targetData->eventDispatcher) + targetData->eventDispatcher->wakeUp(); + + // the current emitting thread shouldn't restore currentSender after calling moveToThread() + if (currentSender) + currentSender->ref = 0; + currentSender = 0; + + // the current event thread also shouldn't restore the delete watch + inEventHandler = false; + if (deleteWatch) + *deleteWatch = 1; + deleteWatch = 0; + + // set new thread data + targetData->ref(); + threadData->deref(); + threadData = targetData; + + for (int i = 0; i < children.size(); ++i) { + QObject *child = children.at(i); + child->d_func()->setThreadData_helper(currentData, targetData); + } +} + +void QObjectPrivate::_q_reregisterTimers(void *pointer) +{ + Q_Q(QObject); + QList<QPair<int, int> > *timerList = reinterpret_cast<QList<QPair<int, int> > *>(pointer); + QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher; + for (int i = 0; i < timerList->size(); ++i) { + const QPair<int, int> &pair = timerList->at(i); + eventDispatcher->registerTimer(pair.first, pair.second, q); + } + delete timerList; +} + + +// +// The timer flag hasTimer is set when startTimer is called. +// It is not reset when killing the timer because more than +// one timer might be active. +// + +/*! + Starts a timer and returns a timer identifier, or returns zero if + it could not start a timer. + + A timer event will occur every \a interval milliseconds until + killTimer() is called. If \a interval is 0, then the timer event + occurs once every time there are no more window system events to + process. + + The virtual timerEvent() function is called with the QTimerEvent + event parameter class when a timer event occurs. Reimplement this + function to get timer events. + + If multiple timers are running, the QTimerEvent::timerId() can be + used to find out which timer was activated. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 8 + + Note that QTimer's accuracy depends on the underlying operating + system and hardware. Most platforms support an accuracy of 20 + milliseconds; some provide more. If Qt is unable to deliver the + requested number of timer events, it will silently discard some. + + The QTimer class provides a high-level programming interface with + single-shot timers and timer signals instead of events. There is + also a QBasicTimer class that is more lightweight than QTimer and + less clumsy than using timer IDs directly. + + \sa timerEvent(), killTimer(), QTimer::singleShot() +*/ + +int QObject::startTimer(int interval) +{ + Q_D(QObject); + + if (interval < 0) { + qWarning("QObject::startTimer: QTimer cannot have a negative interval"); + return 0; + } + + d->pendTimer = true; // set timer flag + + if (!d->threadData->eventDispatcher) { + qWarning("QObject::startTimer: QTimer can only be used with threads started with QThread"); + return 0; + } + return d->threadData->eventDispatcher->registerTimer(interval, this); +} + +/*! + Kills the timer with timer identifier, \a id. + + The timer identifier is returned by startTimer() when a timer + event is started. + + \sa timerEvent(), startTimer() +*/ + +void QObject::killTimer(int id) +{ + Q_D(QObject); + if (d->threadData->eventDispatcher) + d->threadData->eventDispatcher->unregisterTimer(id); +} + + +/*! + \fn QObject *QObject::parent() const + + Returns a pointer to the parent object. + + \sa children() +*/ + +/*! + \fn const QObjectList &QObject::children() const + + Returns a list of child objects. + The QObjectList class is defined in the \c{<QObject>} header + file as the following: + + \quotefromfile src/corelib/kernel/qobject.h + \skipto /typedef .*QObjectList/ + \printuntil QObjectList + + The first child added is the \l{QList::first()}{first} object in + the list and the last child added is the \l{QList::last()}{last} + object in the list, i.e. new children are appended at the end. + + Note that the list order changes when QWidget children are + \l{QWidget::raise()}{raised} or \l{QWidget::lower()}{lowered}. A + widget that is raised becomes the last object in the list, and a + widget that is lowered becomes the first object in the list. + + \sa findChild(), findChildren(), parent(), setParent() +*/ + +#ifdef QT3_SUPPORT +static void objSearch(QObjectList &result, + const QObjectList &list, + const char *inheritsClass, + bool onlyWidgets, + const char *objName, + QRegExp *rx, + bool recurse) +{ + for (int i = 0; i < list.size(); ++i) { + QObject *obj = list.at(i); + if (!obj) + continue; + bool ok = true; + if (onlyWidgets) + ok = obj->isWidgetType(); + else if (inheritsClass && !obj->inherits(inheritsClass)) + ok = false; + if (ok) { + if (objName) + ok = (obj->objectName() == QLatin1String(objName)); +#ifndef QT_NO_REGEXP + else if (rx) + ok = (rx->indexIn(obj->objectName()) != -1); +#endif + } + if (ok) // match! + result.append(obj); + if (recurse) { + QObjectList clist = obj->children(); + if (!clist.isEmpty()) + objSearch(result, clist, inheritsClass, + onlyWidgets, objName, rx, recurse); + } + } +} + +/*! + \internal + + Searches the children and optionally grandchildren of this object, + and returns a list of those objects that are named or that match + \a objName and inherit \a inheritsClass. If \a inheritsClass is 0 + (the default), all classes match. If \a objName is 0 (the + default), all object names match. + + If \a regexpMatch is true (the default), \a objName is a regular + expression that the objects's names must match. The syntax is that + of a QRegExp. If \a regexpMatch is false, \a objName is a string + and object names must match it exactly. + + Note that \a inheritsClass uses single inheritance from QObject, + the way inherits() does. According to inherits(), QWidget + inherits QObject but not QPaintDevice. This does not quite match + reality, but is the best that can be done on the wide variety of + compilers Qt supports. + + Finally, if \a recursiveSearch is true (the default), queryList() + searches \e{n}th-generation as well as first-generation children. + + If all this seems a bit complex for your needs, the simpler + child() function may be what you want. + + This somewhat contrived example disables all the buttons in this + window: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 9 + + \warning Delete the list as soon you have finished using it. The + list contains pointers that may become invalid at almost any time + without notice (as soon as the user closes a window you may have + dangling pointers, for example). + + \sa child() children(), parent(), inherits(), objectName(), QRegExp +*/ + +QObjectList QObject::queryList(const char *inheritsClass, + const char *objName, + bool regexpMatch, + bool recursiveSearch) const +{ + Q_D(const QObject); + QObjectList list; + bool onlyWidgets = (inheritsClass && qstrcmp(inheritsClass, "QWidget") == 0); +#ifndef QT_NO_REGEXP + if (regexpMatch && objName) { // regexp matching + QRegExp rx(QString::fromLatin1(objName)); + objSearch(list, d->children, inheritsClass, onlyWidgets, 0, &rx, recursiveSearch); + } else +#endif + { + objSearch(list, d->children, inheritsClass, onlyWidgets, objName, 0, recursiveSearch); + } + return list; +} +#endif + +/*! + \fn T *QObject::findChild(const QString &name) const + + Returns the child of this object that can be cast into type T and + that is called \a name, or 0 if there is no such object. + Omitting the \a name argument causes all object names to be matched. + The search is performed recursively. + + If there is more than one child matching the search, the most + direct ancestor is returned. If there are several direct + ancestors, it is undefined which one will be returned. In that + case, findChildren() should be used. + + This example returns a child \l{QPushButton} of \c{parentWidget} + named \c{"button1"}: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 10 + + This example returns a \l{QListWidget} child of \c{parentWidget}: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 11 + + \warning This function is not available with MSVC 6. Use + qFindChild() instead if you need to support that version of the + compiler. + + \sa findChildren(), qFindChild() +*/ + +/*! + \fn QList<T> QObject::findChildren(const QString &name) const + + Returns all children of this object with the given \a name that can be + cast to type T, or an empty list if there are no such objects. + Omitting the \a name argument causes all object names to be matched. + The search is performed recursively. + + The following example shows how to find a list of child \l{QWidget}s of + the specified \c{parentWidget} named \c{widgetname}: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 12 + + This example returns all \c{QPushButton}s that are children of \c{parentWidget}: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 13 + + \warning This function is not available with MSVC 6. Use + qFindChildren() instead if you need to support that version of the + compiler. + + \sa findChild(), qFindChildren() +*/ + +/*! + \fn QList<T> QObject::findChildren(const QRegExp ®Exp) const + \overload findChildren() + + Returns the children of this object that can be cast to type T + and that have names matching the regular expression \a regExp, + or an empty list if there are no such objects. + The search is performed recursively. + + \warning This function is not available with MSVC 6. Use + qFindChildren() instead if you need to support that version of the + compiler. +*/ + +/*! + \fn T qFindChild(const QObject *obj, const QString &name) + \relates QObject + + This function is equivalent to + \a{obj}->\l{QObject::findChild()}{findChild}<T>(\a name). It is + provided as a work-around for MSVC 6, which doesn't support + member template functions. + + \sa QObject::findChild() +*/ + +/*! + \fn QList<T> qFindChildren(const QObject *obj, const QString &name) + \relates QObject + + This function is equivalent to + \a{obj}->\l{QObject::findChildren()}{findChildren}<T>(\a name). It is + provided as a work-around for MSVC 6, which doesn't support + member template functions. + + \sa QObject::findChildren() +*/ + +/*! + \fn QList<T> qFindChildren(const QObject *obj, const QRegExp ®Exp) + \relates QObject + \overload qFindChildren() + + This function is equivalent to + \a{obj}->\l{QObject::findChildren()}{findChildren}<T>(\a regExp). It is + provided as a work-around for MSVC 6, which doesn't support + member template functions. +*/ + +/*! + \internal + \fn T qFindChild(const QObject *obj, const QString &name = QString(), T dummy = 0) + \relates QObject + \overload qFindChildren() + + This function is equivalent to + \a{obj}->\l{QObject::findChild()}{findChild}<T>(\a name). It is + provided as a work-around for MSVC 6, which doesn't support + member template functions. + + \sa QObject::findChild() +*/ + +/*! + \internal + \fn QList<T> qFindChildren(const QObject *obj, const QString &name = QString(), T dummy = 0) + \relates QObject + \overload qFindChildren() + + This function is equivalent to + \a{obj}->\l{QObject::findChildren()}{findChildren}<T>(\a name). It is + provided as a work-around for MSVC 6, which doesn't support + member template functions. + + \sa QObject::findChildren() +*/ + +/*! + \internal +*/ +void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QRegExp *re, + const QMetaObject &mo, QList<void*> *list) +{ + if (!parent || !list) + return; + const QObjectList &children = parent->children(); + QObject *obj; + for (int i = 0; i < children.size(); ++i) { + obj = children.at(i); + if (mo.cast(obj)) { + if (re) { + if (re->indexIn(obj->objectName()) != -1) + list->append(obj); + } else { + if (name.isNull() || obj->objectName() == name) + list->append(obj); + } + } + qt_qFindChildren_helper(obj, name, re, mo, list); + } +} + +/*! \internal + */ +QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo) +{ + if (!parent) + return 0; + const QObjectList &children = parent->children(); + QObject *obj; + int i; + for (i = 0; i < children.size(); ++i) { + obj = children.at(i); + if (mo.cast(obj) && (name.isNull() || obj->objectName() == name)) + return obj; + } + for (i = 0; i < children.size(); ++i) { + obj = qt_qFindChild_helper(children.at(i), name, mo); + if (obj) + return obj; + } + return 0; +} + +/*! + Makes the object a child of \a parent. + + \sa QWidget::setParent() +*/ + +void QObject::setParent(QObject *parent) +{ + Q_D(QObject); + Q_ASSERT(!d->isWidget); + d->setParent_helper(parent); +} + +void QObjectPrivate::deleteChildren() +{ + const bool reallyWasDeleted = wasDeleted; + wasDeleted = true; + // delete children objects + // don't use qDeleteAll as the destructor of the child might + // delete siblings + for (int i = 0; i < children.count(); ++i) { + currentChildBeingDeleted = children.at(i); + children[i] = 0; + delete currentChildBeingDeleted; + } + children.clear(); + currentChildBeingDeleted = 0; + wasDeleted = reallyWasDeleted; +} + +void QObjectPrivate::setParent_helper(QObject *o) +{ + Q_Q(QObject); + if (o == parent) + return; + if (parent) { + QObjectPrivate *parentD = parent->d_func(); + if (parentD->wasDeleted && wasDeleted + && parentD->currentChildBeingDeleted == q) { + // don't do anything since QObjectPrivate::deleteChildren() already + // cleared our entry in parentD->children. + } else { + const int index = parentD->children.indexOf(q); + if (parentD->wasDeleted) { + parentD->children[index] = 0; + } else { + parentD->children.removeAt(index); + if (sendChildEvents && parentD->receiveChildEvents) { + QChildEvent e(QEvent::ChildRemoved, q); + QCoreApplication::sendEvent(parent, &e); + } + } + } + } + parent = o; + if (parent) { + // object hierarchies are constrained to a single thread + if (threadData != parent->d_func()->threadData) { + qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread"); + parent = 0; + return; + } + parent->d_func()->children.append(q); + if(sendChildEvents && parent->d_func()->receiveChildEvents) { + if (!isWidget) { + QChildEvent e(QEvent::ChildAdded, q); + QCoreApplication::sendEvent(parent, &e); +#ifdef QT3_SUPPORT + if (parent->d_func()->pendingChildInsertedEvents.isEmpty()) { + QCoreApplication::postEvent(parent, + new QEvent(QEvent::ChildInsertedRequest), + Qt::HighEventPriority); + } + parent->d_func()->pendingChildInsertedEvents.append(q); +#endif + } + } + } +} + +/*! + \fn void QObject::installEventFilter(QObject *filterObj) + + Installs an event filter \a filterObj on this object. For example: + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 14 + + An event filter is an object that receives all events that are + sent to this object. The filter can either stop the event or + forward it to this object. The event filter \a filterObj receives + events via its eventFilter() function. The eventFilter() function + must return true if the event should be filtered, (i.e. stopped); + otherwise it must return false. + + If multiple event filters are installed on a single object, the + filter that was installed last is activated first. + + Here's a \c KeyPressEater class that eats the key presses of its + monitored objects: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 15 + + And here's how to install it on two widgets: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 16 + + The QShortcut class, for example, uses this technique to intercept + shortcut key presses. + + \warning If you delete the receiver object in your eventFilter() + function, be sure to return true. If you return false, Qt sends + the event to the deleted object and the program will crash. + + Note that the filtering object must be in the same thread as this + object. If \a filterObj is in a different thread, this function does + nothing. If either \a filterObj or this object are moved to a different + thread after calling this function, the event filter will not be + called until both objects have the same thread affinity again (it + is \e not removed). + + \sa removeEventFilter(), eventFilter(), event() +*/ + +void QObject::installEventFilter(QObject *obj) +{ + Q_D(QObject); + if (!obj) + return; + if (d->threadData != obj->d_func()->threadData) { + qWarning("QObject::installEventFilter(): Cannot filter events for objects in a different thread."); + return; + } + + // clean up unused items in the list + d->eventFilters.removeAll((QObject*)0); + d->eventFilters.removeAll(obj); + d->eventFilters.prepend(obj); +} + +/*! + Removes an event filter object \a obj from this object. The + request is ignored if such an event filter has not been installed. + + All event filters for this object are automatically removed when + this object is destroyed. + + It is always safe to remove an event filter, even during event + filter activation (i.e. from the eventFilter() function). + + \sa installEventFilter(), eventFilter(), event() +*/ + +void QObject::removeEventFilter(QObject *obj) +{ + Q_D(QObject); + for (int i = 0; i < d->eventFilters.count(); ++i) { + if (d->eventFilters.at(i) == obj) + d->eventFilters[i] = 0; + } +} + + +/*! + \fn QObject::destroyed(QObject *obj) + + This signal is emitted immediately before the object \a obj is + destroyed, and can not be blocked. + + All the objects's children are destroyed immediately after this + signal is emitted. + + \sa deleteLater(), QPointer +*/ + +/*! + Schedules this object for deletion. + + The object will be deleted when control returns to the event + loop. If the event loop is not running when this function is + called (e.g. deleteLater() is called on an object before + QCoreApplication::exec()), the object will be deleted once the + event loop is started. + + Note that entering and leaving a new event loop (e.g., by opening a modal + dialog) will \e not perform the deferred deletion; for the object to be + deleted, the control must return to the event loop from which + deleteLater() was called. + + \bold{Note:} It is safe to call this function more than once; when the + first deferred deletion event is delivered, any pending events for the + object are removed from the event queue. + + \sa destroyed(), QPointer +*/ +void QObject::deleteLater() +{ + QCoreApplication::postEvent(this, new QEvent(QEvent::DeferredDelete)); +} + +/*! + \fn QString QObject::tr(const char *sourceText, const char *disambiguation, int n) + \reentrant + + Returns a translated version of \a sourceText, optionally based on a + \a disambiguation string and value of \a n for strings containing plurals; + otherwise returns \a sourceText itself if no appropriate translated string + is available. + + See the sections below on Disambiguation and Handling Plurals for more + information about the optional \a disambiguation and \a n parameters. + + QObject and its subclasses obtain translated strings from any translator + objects that have been installed on the application object; see the + QTranslator documentation for details about this mechanism. + + A translatable string is referenced by its translation context; + this is the name of the QObject subclass whose tr() function is invoked, + as in the following example: + + \snippet mainwindows/sdi/mainwindow.cpp implicit tr context + \dots + + Here, the context is \c MainWindow because it is the \c MainWindow::tr() + function that is invoked. Translation contexts can be given explicitly + by fully qualifying the call to tr(); for example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp explicit tr context + + This call obtains the translated text for "Page up" from the \c QScrollBar + context. + + \section1 Defining Translation Contexts + + The translation context for QObject and each QObject subclass is the + class name itself. Developers subclassing QObject must use the + Q_OBJECT macro in their class definition to override the translation + context. This macro sets the context to the name of the subclass. + + If Q_OBJECT is not used in a class definition, the context will be + inherited from the base class. For example, since all QObject-based + classes in Qt provide a context, a new QWidget subclass defined without + a Q_OBJECT macro will use the "QWidget" context if its tr() function + is invoked. + + \section1 Translator Comments + + Developers can include information about each translatable string to + help translators with the translation process. These are extracted + when \l lupdate is used to process the source files. The recommended + way to add comments is to annotate the tr() calls in your code with + comments of the form: + + \tt{//: ...} + + or + + \tt{/*: ... \starslash} + + Examples: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 40 + + In these examples, the comments will be associated with the strings + passed to tr() in the context of each call. + + \section1 Disambiguation + + If the same \a sourceText is used in different roles within the + same context, an additional identifying string may be passed in + \a disambiguation (0 by default). In Qt 4.4 and earlier, this was + the preferred way to pass comments to translators. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 17 + + \section1 Character Encodings + + You can set the encoding for \a sourceText by calling QTextCodec::setCodecForTr(). + By default \a sourceText is assumed to be in Latin-1 encoding. + + \section1 Handling Plurals + + If \a n >= 0, all occurrences of \c %n in the resulting string + are replaced with a decimal representation of \a n. In addition, + depending on \a n's value, the translation text may vary. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 18 + + The table below shows what string is returned depending on the + active translation: + + \table + \header \o \o{3,1} Active Translation + \header \o \a n \o No Translation \o French \o English + \row \o 0 \o "0 message(s) saved" \o "0 message sauvegard\unicode{0xE9}" \o "0 message\bold{s} saved" + \row \o 1 \o "1 message(s) saved" \o "1 message sauvegard\unicode{0xE9}" \o "1 message saved" + \row \o 2 \o "2 message(s) saved" \o "2 message\bold{s} sauvegard\unicode{0xE9}\bold{s}" \o "2 message\bold{s} saved" + \row \o 37 \o "37 message(s) saved" \o "37 message\bold{s} sauvegard\unicode{0xE9}\bold{s}" \o "37 message\bold{s} saved" + \endtable + + This idiom is more flexible than the traditional approach; e.g., + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 19 + + because it also works with target languages that have several + plural forms (e.g., Irish has a special "dual" form that should + be used when \c n is 2), and it handles the \e n == 0 case + correctly for languages such as French that require the singular. + See the \l{Qt Linguist Manual} for details. + + Instead of \c %n, you can use \c %Ln to produce a localized + representation of \a n. The conversion uses the default locale, + set using QLocale::setDefault(). (If no default locale was + specified, the "C" locale is used.) + + \warning This method is reentrant only if all translators are + installed \e before calling this method. Installing or removing + translators while performing translations is not supported. Doing + so will probably result in crashes or other undesirable behavior. + + \sa trUtf8(), QApplication::translate(), QTextCodec::setCodecForTr(), {Internationalization with Qt} +*/ + +/*! + \fn QString QObject::trUtf8(const char *sourceText, const char *disambiguation, int n) + \reentrant + + Returns a translated version of \a sourceText, or + QString::fromUtf8(\a sourceText) if there is no appropriate + version. It is otherwise identical to tr(\a sourceText, \a + disambiguation, \a n). + + Note that using the Utf8 variants of the translation functions + is not required if \c CODECFORTR is already set to UTF-8 in the + qmake project file and QTextCodec::setCodecForTr("UTF-8") is + used. + + \warning This method is reentrant only if all translators are + installed \e before calling this method. Installing or removing + translators while performing translations is not supported. Doing + so will probably result in crashes or other undesirable behavior. + + \warning For portability reasons, we recommend that you use + escape sequences for specifying non-ASCII characters in string + literals to trUtf8(). For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 20 + + \sa tr(), QApplication::translate(), {Internationalization with Qt} +*/ + + + + +/***************************************************************************** + Signals and slots + *****************************************************************************/ + + +const int flagged_locations_count = 2; +static const char* flagged_locations[flagged_locations_count] = {0}; + +const char *qFlagLocation(const char *method) +{ + static int idx = 0; + flagged_locations[idx] = method; + idx = (idx+1) % flagged_locations_count; + return method; +} + +static int extract_code(const char *member) +{ + // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE + return (((int)(*member) - '0') & 0x3); +} + +static const char * extract_location(const char *member) +{ + for (int i = 0; i < flagged_locations_count; ++i) { + if (member == flagged_locations[i]) { + // signature includes location information after the first null-terminator + const char *location = member + qstrlen(member) + 1; + if (*location != '\0') + return location; + return 0; + } + } + return 0; +} + +static bool check_signal_macro(const QObject *sender, const char *signal, + const char *func, const char *op) +{ + int sigcode = extract_code(signal); + if (sigcode != QSIGNAL_CODE) { + if (sigcode == QSLOT_CODE) + qWarning("Object::%s: Attempt to %s non-signal %s::%s", + func, op, sender->metaObject()->className(), signal+1); + else + qWarning("Object::%s: Use the SIGNAL macro to %s %s::%s", + func, op, sender->metaObject()->className(), signal); + return false; + } + return true; +} + +static bool check_method_code(int code, const QObject *object, + const char *method, const char *func) +{ + if (code != QSLOT_CODE && code != QSIGNAL_CODE) { + qWarning("Object::%s: Use the SLOT or SIGNAL macro to " + "%s %s::%s", func, func, object->metaObject()->className(), method); + return false; + } + return true; +} + +static void err_method_notfound(const QObject *object, + const char *method, const char *func) +{ + const char *type = "method"; + switch (extract_code(method)) { + case QSLOT_CODE: type = "slot"; break; + case QSIGNAL_CODE: type = "signal"; break; + } + const char *loc = extract_location(method); + if (strchr(method,')') == 0) // common typing mistake + qWarning("Object::%s: Parentheses expected, %s %s::%s%s%s", + func, type, object->metaObject()->className(), method+1, + loc ? " in ":"\0", loc ? loc : "\0"); + else + qWarning("Object::%s: No such %s %s::%s%s%s", + func, type, object->metaObject()->className(), method+1, + loc ? " in ":"\0", loc ? loc : "\0"); + +} + + +static void err_info_about_objects(const char * func, + const QObject * sender, + const QObject * receiver) +{ + QString a = sender ? sender->objectName() : QString(); + QString b = receiver ? receiver->objectName() : QString(); + if (!a.isEmpty()) + qWarning("Object::%s: (sender name: '%s')", func, a.toLocal8Bit().data()); + if (!b.isEmpty()) + qWarning("Object::%s: (receiver name: '%s')", func, b.toLocal8Bit().data()); +} + +/*! + Returns a pointer to the object that sent the signal, if called in + a slot activated by a signal; otherwise it returns 0. The pointer + is valid only during the execution of the slot that calls this + function from this object's thread context. + + The pointer returned by this function becomes invalid if the + sender is destroyed, or if the slot is disconnected from the + sender's signal. + + \warning This function violates the object-oriented principle of + modularity. However, getting access to the sender might be useful + when many signals are connected to a single slot. + + \warning As mentioned above, the return value of this function is + not valid when the slot is called via a Qt::DirectConnection from + a thread different from this object's thread. Do not use this + function in this type of scenario. + + \sa QSignalMapper +*/ + +QObject *QObject::sender() const +{ + Q_D(const QObject); + + QMutexLocker(&d->threadData->mutex); + if (!d->currentSender) + return 0; + + // Return 0 if d->currentSender isn't in d->senders + bool found = false; + for (int i = 0; !found && i < d->senders.count(); ++i) + found = (d->senders.at(i).sender == d->currentSender->sender); + if (!found) + return 0; + return d->currentSender->sender; +} + +/*! + Returns the number of receivers connected to the \a signal. + + Since both slots and signals can be used as receivers for signals, + and the same connections can be made many times, the number of + receivers is the same as the number of connections made from this + signal. + + When calling this function, you can use the \c SIGNAL() macro to + pass a specific signal: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 21 + + As the code snippet above illustrates, you can use this function + to avoid emitting a signal that nobody listens to. + + \warning This function violates the object-oriented principle of + modularity. However, it might be useful when you need to perform + expensive initialization only if something is connected to a + signal. +*/ + +int QObject::receivers(const char *signal) const +{ + int receivers = 0; + if (signal) { + QByteArray signal_name = QMetaObject::normalizedSignature(signal); + signal = signal_name; +#ifndef QT_NO_DEBUG + if (!check_signal_macro(this, signal, "receivers", "bind")) + return 0; +#endif + signal++; // skip code + const QMetaObject *smeta = this->metaObject(); + int signal_index = smeta->indexOfSignal(signal); + if (signal_index < 0) { +#ifndef QT_NO_DEBUG + err_method_notfound(this, signal-1, "receivers"); +#endif + return false; + } + + Q_D(const QObject); + QMutexLocker locker(&d->threadData->mutex); + if (d->connectionLists) { + if (signal_index < d->connectionLists->count()) { + const QObjectPrivate::ConnectionList &connectionList = + d->connectionLists->at(signal_index); + for (int i = 0; i < connectionList.count(); ++i) { + const QObjectPrivate::Connection &c = connectionList.at(i); + receivers += c.receiver ? 1 : 0; + } + } + } + } + return receivers; +} + +/*! + \threadsafe + + Creates a connection of the given \a type from the \a signal in + the \a sender object to the \a method in the \a receiver object. + Returns true if the connection succeeds; otherwise returns false. + + You must use the \c SIGNAL() and \c SLOT() macros when specifying + the \a signal and the \a method, for example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 22 + + This example ensures that the label always displays the current + scroll bar value. Note that the signal and slots parameters must not + contain any variable names, only the type. E.g. the following would + not work and return false: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 23 + + A signal can also be connected to another signal: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 24 + + In this example, the \c MyWidget constructor relays a signal from + a private member variable, and makes it available under a name + that relates to \c MyWidget. + + A signal can be connected to many slots and signals. Many signals + can be connected to one slot. + + If a signal is connected to several slots, the slots are activated + in an arbitrary order when the signal is emitted. + + The function returns true if it successfully connects the signal + to the slot. It will return false if it cannot create the + connection, for example, if QObject is unable to verify the + existence of either \a signal or \a method, or if their signatures + aren't compatible. + + For every connection you make, a signal is emitted; two signals are emitted + for duplicate connections. You can break all of these connections with a + single disconnect() call. + + The optional \a type parameter describes the type of connection + to establish. In particular, it determines whether a particular + signal is delivered to a slot immediately or queued for delivery + at a later time. If the signal is queued, the parameters must be + of types that are known to Qt's meta-object system, because Qt + needs to copy the arguments to store them in an event behind the + scenes. If you try to use a queued connection and get the error + message + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 25 + + call qRegisterMetaType() to register the data type before you + establish the connection. + + \sa disconnect(), sender(), qRegisterMetaType() +*/ + +bool QObject::connect(const QObject *sender, const char *signal, + const QObject *receiver, const char *method, + Qt::ConnectionType type) +{ + { + const void *cbdata[] = { sender, signal, receiver, method, &type }; + if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata)) + return true; + } + +#ifndef QT_NO_DEBUG + bool warnCompat = true; +#endif + if (type == Qt::AutoCompatConnection) { + type = Qt::AutoConnection; +#ifndef QT_NO_DEBUG + warnCompat = false; +#endif + } + + if (sender == 0 || receiver == 0 || signal == 0 || method == 0) { + qWarning("QObject::connect: Cannot connect %s::%s to %s::%s", + sender ? sender->metaObject()->className() : "(null)", + (signal && *signal) ? signal+1 : "(null)", + receiver ? receiver->metaObject()->className() : "(null)", + (method && *method) ? method+1 : "(null)"); + return false; + } + QByteArray tmp_signal_name; + + if (!check_signal_macro(sender, signal, "connect", "bind")) + return false; + const QMetaObject *smeta = sender->metaObject(); + const char *signal_arg = signal; + ++signal; //skip code + int signal_index = smeta->indexOfSignal(signal); + if (signal_index < 0) { + // check for normalized signatures + tmp_signal_name = QMetaObject::normalizedSignature(signal - 1); + signal = tmp_signal_name.constData() + 1; + + signal_index = smeta->indexOfSignal(signal); + if (signal_index < 0) { + err_method_notfound(sender, signal_arg, "connect"); + err_info_about_objects("connect", sender, receiver); + return false; + } + } + + QByteArray tmp_method_name; + int membcode = extract_code(method); + + if (!check_method_code(membcode, receiver, method, "connect")) + return false; + const char *method_arg = method; + ++method; // skip code + + const QMetaObject *rmeta = receiver->metaObject(); + int method_index = -1; + switch (membcode) { + case QSLOT_CODE: + method_index = rmeta->indexOfSlot(method); + break; + case QSIGNAL_CODE: + method_index = rmeta->indexOfSignal(method); + break; + } + if (method_index < 0) { + // check for normalized methods + tmp_method_name = QMetaObject::normalizedSignature(method); + method = tmp_method_name.constData(); + switch (membcode) { + case QSLOT_CODE: + method_index = rmeta->indexOfSlot(method); + break; + case QSIGNAL_CODE: + method_index = rmeta->indexOfSignal(method); + break; + } + } + + if (method_index < 0) { + err_method_notfound(receiver, method_arg, "connect"); + err_info_about_objects("connect", sender, receiver); + return false; + } + if (!QMetaObject::checkConnectArgs(signal, method)) { + qWarning("QObject::connect: Incompatible sender/receiver arguments" + "\n %s::%s --> %s::%s", + sender->metaObject()->className(), signal, + receiver->metaObject()->className(), method); + return false; + } + + int *types = 0; + if ((type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) + && !(types = queuedConnectionTypes(smeta->method(signal_index).parameterTypes()))) + return false; + +#ifndef QT_NO_DEBUG + { + QMetaMethod smethod = smeta->method(signal_index); + QMetaMethod rmethod = rmeta->method(method_index); + if (warnCompat) { + if(smethod.attributes() & QMetaMethod::Compatibility) { + if (!(rmethod.attributes() & QMetaMethod::Compatibility)) + qWarning("QObject::connect: Connecting from COMPAT signal (%s::%s)", smeta->className(), signal); + } else if(rmethod.attributes() & QMetaMethod::Compatibility && membcode != QSIGNAL_CODE) { + qWarning("QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)", + smeta->className(), signal, rmeta->className(), method); + } + } + } +#endif + QMetaObject::connect(sender, signal_index, receiver, method_index, type, types); + const_cast<QObject*>(sender)->connectNotify(signal - 1); + return true; +} + + +/*! + \fn bool QObject::connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type) const + \overload connect() + \threadsafe + + Connects \a signal from the \a sender object to this object's \a + method. + + Equivalent to connect(\a sender, \a signal, \c this, \a method, \a type). + + Every connection you make emits a signal, so duplicate connections emit + two signals. You can break a connection using disconnect(). + + \sa disconnect() +*/ + +/*! + \threadsafe + + Disconnects \a signal in object \a sender from \a method in object + \a receiver. Returns true if the connection is successfully broken; + otherwise returns false. + + A signal-slot connection is removed when either of the objects + involved are destroyed. + + disconnect() is typically used in three ways, as the following + examples demonstrate. + \list 1 + \i Disconnect everything connected to an object's signals: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 26 + + equivalent to the non-static overloaded function + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 27 + + \i Disconnect everything connected to a specific signal: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 28 + + equivalent to the non-static overloaded function + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 29 + + \i Disconnect a specific receiver: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 30 + + equivalent to the non-static overloaded function + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 31 + + \endlist + + 0 may be used as a wildcard, meaning "any signal", "any receiving + object", or "any slot in the receiving object", respectively. + + The \a sender may never be 0. (You cannot disconnect signals from + more than one object in a single call.) + + If \a signal is 0, it disconnects \a receiver and \a method from + any signal. If not, only the specified signal is disconnected. + + If \a receiver is 0, it disconnects anything connected to \a + signal. If not, slots in objects other than \a receiver are not + disconnected. + + If \a method is 0, it disconnects anything that is connected to \a + receiver. If not, only slots named \a method will be disconnected, + and all other slots are left alone. The \a method must be 0 if \a + receiver is left out, so you cannot disconnect a + specifically-named slot on all objects. + + \sa connect() +*/ +bool QObject::disconnect(const QObject *sender, const char *signal, + const QObject *receiver, const char *method) +{ + if (sender == 0 || (receiver == 0 && method != 0)) { + qWarning("Object::disconnect: Unexpected null parameter"); + return false; + } + + { + const void *cbdata[] = { sender, signal, receiver, method }; + if (QInternal::activateCallbacks(QInternal::DisconnectCallback, (void **) cbdata)) + return true; + } + + const char *signal_arg = signal; + QByteArray signal_name; + bool signal_found = false; + if (signal) { + signal_name = QMetaObject::normalizedSignature(signal); + signal = signal_name; + + if (!check_signal_macro(sender, signal, "disconnect", "unbind")) + return false; + signal++; // skip code + } + + QByteArray method_name; + const char *method_arg = method; + int membcode = -1; + bool method_found = false; + if (method) { + method_name = QMetaObject::normalizedSignature(method); + method = method_name; + membcode = extract_code(method); + if (!check_method_code(membcode, receiver, method, "disconnect")) + return false; + method++; // skip code + } + + /* We now iterate through all the sender's and receiver's meta + * objects in order to also disconnect possibly shadowed signals + * and slots with the same signature. + */ + bool res = false; + const QMetaObject *smeta = sender->metaObject(); + do { + int signal_index = -1; + if (signal) { + signal_index = smeta->indexOfSignal(signal); + if (signal_index < smeta->methodOffset()) + continue; + signal_found = true; + } + + if (!method) { + res |= QMetaObject::disconnect(sender, signal_index, receiver, -1); + } else { + const QMetaObject *rmeta = receiver->metaObject(); + do { + int method_index = rmeta->indexOfMethod(method); + if (method_index >= 0) + while (method_index < rmeta->methodOffset()) + rmeta = rmeta->superClass(); + if (method_index < 0) + break; + res |= QMetaObject::disconnect(sender, signal_index, receiver, method_index); + method_found = true; + } while ((rmeta = rmeta->superClass())); + } + } while (signal && (smeta = smeta->superClass())); + + if (signal && !signal_found) { + err_method_notfound(sender, signal_arg, "disconnect"); + err_info_about_objects("disconnect", sender, receiver); + } else if (method && !method_found) { + err_method_notfound(receiver, method_arg, "disconnect"); + err_info_about_objects("disconnect", sender, receiver); + } + if (res) + const_cast<QObject*>(sender)->disconnectNotify(signal ? (signal - 1) : 0); + return res; +} + + +/*! + \threadsafe + + \fn bool QObject::disconnect(const char *signal, const QObject *receiver, const char *method) + \overload disconnect() + + Disconnects \a signal from \a method of \a receiver. + + A signal-slot connection is removed when either of the objects + involved are destroyed. +*/ + +/*! + \fn bool QObject::disconnect(const QObject *receiver, const char *method) + \overload disconnect() + + Disconnects all signals in this object from \a receiver's \a + method. + + A signal-slot connection is removed when either of the objects + involved are destroyed. +*/ + + +/*! + \fn void QObject::connectNotify(const char *signal) + + This virtual function is called when something has been connected + to \a signal in this object. + + If you want to compare \a signal with a specific signal, use + QLatin1String and the \c SIGNAL() macro as follows: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 32 + + If the signal contains multiple parameters or parameters that + contain spaces, call QMetaObject::normalizedSignature() on + the result of the \c SIGNAL() macro. + + \warning This function violates the object-oriented principle of + modularity. However, it might be useful when you need to perform + expensive initialization only if something is connected to a + signal. + + \sa connect(), disconnectNotify() +*/ + +void QObject::connectNotify(const char *) +{ +} + +/*! + \fn void QObject::disconnectNotify(const char *signal) + + This virtual function is called when something has been + disconnected from \a signal in this object. + + See connectNotify() for an example of how to compare + \a signal with a specific signal. + + \warning This function violates the object-oriented principle of + modularity. However, it might be useful for optimizing access to + expensive resources. + + \sa disconnect(), connectNotify() +*/ + +void QObject::disconnectNotify(const char *) +{ +} + +/*!\internal + + \a types is a 0-terminated vector of meta types for queued + connections. + + if \a signal_index is -1, then we effectively connect *all* signals + from the sender to the receiver's slot +*/ +bool QMetaObject::connect(const QObject *sender, int signal_index, + const QObject *receiver, int method_index, int type, int *types) +{ + QObject *s = const_cast<QObject *>(sender); + QObject *r = const_cast<QObject *>(receiver); + + QOrderedMutexLocker locker(&s->d_func()->threadData->mutex, + &r->d_func()->threadData->mutex); + +#if defined(Q_CC_HPACC) && defined(QT_ARCH_PARISC) + QObjectPrivate::Connection c; + c.receiver = r; + c.method = method_index; + c.connectionType = type; + c.argumentTypes = types; +#else + QObjectPrivate::Connection c = { r, method_index, type, Q_BASIC_ATOMIC_INITIALIZER(types) }; +#endif + s->d_func()->addConnection(signal_index, &c); + r->d_func()->refSender(s, signal_index); + + if (signal_index < 0) + sender->d_func()->connectedSignals = ~0u; + else if (signal_index < 32) + sender->d_func()->connectedSignals |= (1 << signal_index); + + return true; +} + + +/*!\internal + */ +bool QMetaObject::disconnect(const QObject *sender, int signal_index, + const QObject *receiver, int method_index) +{ + if (!sender) + return false; + + QObject *s = const_cast<QObject *>(sender); + QObject *r = const_cast<QObject *>(receiver); + + QMutex *senderMutex = &s->d_func()->threadData->mutex; + QMutex *receiverMutex = r ? &r->d_func()->threadData->mutex : 0; + QOrderedMutexLocker locker(senderMutex, receiverMutex); + + QObjectConnectionListVector *connectionLists = s->d_func()->connectionLists; + if (!connectionLists) + return false; + + // prevent incoming connections changing the connectionLists while unlocked + ++connectionLists->inUse; + + bool success = false; + if (signal_index < 0) { + // remove from all connection lists + for (signal_index = -1; signal_index < connectionLists->count(); ++signal_index) { + QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal_index]; + for (int i = 0; i < connectionList.count(); ++i) { + QObjectPrivate::Connection *c = &connectionList[i]; + if (c->receiver + && (r == 0 || (c->receiver == r + && (method_index < 0 || c->method == method_index)))) { + QMutex *m = &c->receiver->d_func()->threadData->mutex; + if (!receiverMutex && senderMutex != m) { + // need to relock this receiver and sender in the correct order + bool needToUnlock = QOrderedMutexLocker::relock(senderMutex, m); + c = &connectionList[i]; + if (c->receiver) + c->receiver->d_func()->derefSender(s, signal_index); + if (needToUnlock) + m->unlock(); + } else { + // no need to unlock + c->receiver->d_func()->derefSender(s, signal_index); + } + if (c->argumentTypes && c->argumentTypes != &DIRECT_CONNECTION_ONLY) { + qFree(c->argumentTypes); + c->argumentTypes = 0; + } + c->receiver = 0; + + success = true; + connectionLists->dirty = true; + } + } + } + } else if (signal_index < connectionLists->count()) { + QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal_index]; + for (int i = 0; i < connectionList.count(); ++i) { + QObjectPrivate::Connection *c = &connectionList[i]; + if (c->receiver + && (r == 0 || (c->receiver == r + && (method_index < 0 || c->method == method_index)))) { + QMutex *m = &c->receiver->d_func()->threadData->mutex; + if (!receiverMutex && senderMutex != m) { + // need to relock this receiver and sender in the correct order + bool needToUnlock = QOrderedMutexLocker::relock(senderMutex, m); + c = &connectionList[i]; + if (c->receiver) + c->receiver->d_func()->derefSender(s, signal_index); + if (needToUnlock) + m->unlock(); + } else { + // no need to unlock + c->receiver->d_func()->derefSender(s, signal_index); + } + if (c->argumentTypes && c->argumentTypes != &DIRECT_CONNECTION_ONLY) { + qFree(c->argumentTypes); + c->argumentTypes = 0; + } + c->receiver = 0; + + success = true; + connectionLists->dirty = true; + } + } + } + + --connectionLists->inUse; + Q_ASSERT(connectionLists->inUse >= 0); + if (connectionLists->orphaned && !connectionLists->inUse) + delete connectionLists; + + return success; +} + +/*! + \fn void QMetaObject::connectSlotsByName(QObject *object) + + Searches recursively for all child objects of the given \a object, and connects + matching signals from them to slots of \a object that follow the following form: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 33 + + Let's assume our object has a child object of type QPushButton with + the \l{QObject::objectName}{object name} \c{button1}. The slot to catch the + button's \c{clicked()} signal would be: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 34 + + \sa QObject::setObjectName() + */ +void QMetaObject::connectSlotsByName(QObject *o) +{ + if (!o) + return; + const QMetaObject *mo = o->metaObject(); + Q_ASSERT(mo); + const QObjectList list = qFindChildren<QObject *>(o, QString()); + for (int i = 0; i < mo->methodCount(); ++i) { + const char *slot = mo->method(i).signature(); + Q_ASSERT(slot); + if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_') + continue; + bool foundIt = false; + for(int j = 0; j < list.count(); ++j) { + const QObject *co = list.at(j); + QByteArray objName = co->objectName().toAscii(); + int len = objName.length(); + if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != '_') + continue; + const QMetaObject *smo = co->metaObject(); + int sigIndex = smo->indexOfMethod(slot + len + 4); + if (sigIndex < 0) { // search for compatible signals + int slotlen = qstrlen(slot + len + 4) - 1; + for (int k = 0; k < co->metaObject()->methodCount(); ++k) { + if (smo->method(k).methodType() != QMetaMethod::Signal) + continue; + + if (!qstrncmp(smo->method(k).signature(), slot + len + 4, slotlen)) { + sigIndex = k; + break; + } + } + } + if (sigIndex < 0) + continue; + if (QMetaObject::connect(co, sigIndex, o, i)) { + foundIt = true; + break; + } + } + if (foundIt) { + // we found our slot, now skip all overloads + while (mo->method(i + 1).attributes() & QMetaMethod::Cloned) + ++i; + } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) { + qWarning("QMetaObject::connectSlotsByName: No matching signal for %s", slot); + } + } +} + +static void queued_activate(QObject *sender, int signal, const QObjectPrivate::Connection &c, + void **argv, QSemaphore *semaphore = 0) +{ + if (!c.argumentTypes || c.argumentTypes != &DIRECT_CONNECTION_ONLY) { + QMetaMethod m = sender->metaObject()->method(signal); + QObjectPrivate::Connection &x = const_cast<QObjectPrivate::Connection &>(c); + int *tmp = queuedConnectionTypes(m.parameterTypes()); + if (!tmp) // cannot queue arguments + tmp = &DIRECT_CONNECTION_ONLY; + if (!x.argumentTypes.testAndSetOrdered(0, tmp)) { + if (tmp != &DIRECT_CONNECTION_ONLY) + qFree(tmp); + } + } + if (c.argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate + return; + int nargs = 1; // include return type + while (c.argumentTypes[nargs-1]) + ++nargs; + int *types = (int *) qMalloc(nargs*sizeof(int)); + void **args = (void **) qMalloc(nargs*sizeof(void *)); + types[0] = 0; // return type + args[0] = 0; // return value + for (int n = 1; n < nargs; ++n) + args[n] = QMetaType::construct((types[n] = c.argumentTypes[n-1]), argv[n]); + QCoreApplication::postEvent(c.receiver, new QMetaCallEvent(c.method, + sender, + signal, + nargs, + types, + args, + semaphore)); +} + +static void blocking_activate(QObject *sender, int signal, const QObjectPrivate::Connection &c, void **argv) +{ + if (QThread::currentThread() == c.receiver->thread()) { + qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: " + "Sender is %s(%p), receiver is %s(%p)", + sender->metaObject()->className(), sender, + c.receiver->metaObject()->className(), c.receiver); + } + +#ifdef QT_NO_THREAD + queued_activate(sender, signal, c, argv); +#else + QSemaphore semaphore; + queued_activate(sender, signal, c, argv, &semaphore); + QMutex *mutex = &QThreadData::get2(sender->thread())->mutex; + mutex->unlock(); + semaphore.acquire(); + mutex->lock(); +#endif +} + +/*!\internal + */ +void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv) +{ + if (sender->d_func()->blockSig) + return; + + void *empty_argv[] = { 0 }; + if (qt_signal_spy_callback_set.signal_begin_callback != 0) { + qt_signal_spy_callback_set.signal_begin_callback(sender, from_signal_index, + argv ? argv : empty_argv); + } + + QMutexLocker locker(&sender->d_func()->threadData->mutex); + QThreadData *currentThreadData = QThreadData::current(); + + QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; + if (!connectionLists) { + if (qt_signal_spy_callback_set.signal_end_callback != 0) + qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index); + return; + } + ++connectionLists->inUse; + + // emit signals in the following order: from_signal_index <= signals <= to_signal_index, signal < 0 + for (int signal = from_signal_index; + (signal >= from_signal_index && signal <= to_signal_index) || (signal == -2); + (signal == to_signal_index ? signal = -2 : ++signal)) + { + if (signal >= connectionLists->count()) { + signal = to_signal_index; + continue; + } + int count = connectionLists->at(signal).count(); + for (int i = 0; i < count; ++i) { + const QObjectPrivate::Connection *c = &connectionLists->at(signal)[i]; + if (!c->receiver) + continue; + + QObject * const receiver = c->receiver; + + // determine if this connection should be sent immediately or + // put into the event queue + if ((c->connectionType == Qt::AutoConnection + && (currentThreadData != sender->d_func()->threadData + || receiver->d_func()->threadData != sender->d_func()->threadData)) + || (c->connectionType == Qt::QueuedConnection)) { + queued_activate(sender, signal, *c, argv); + continue; + } else if (c->connectionType == Qt::BlockingQueuedConnection) { + blocking_activate(sender, signal, *c, argv); + continue; + } + + const int method = c->method; + QObjectPrivate::Sender currentSender; + currentSender.sender = sender; + currentSender.signal = signal < 0 ? from_signal_index : signal; + currentSender.ref = 1; + QObjectPrivate::Sender *previousSender = 0; + if (currentThreadData == receiver->d_func()->threadData) + previousSender = QObjectPrivate::setCurrentSender(receiver, ¤tSender); + locker.unlock(); + + if (qt_signal_spy_callback_set.slot_begin_callback != 0) { + qt_signal_spy_callback_set.slot_begin_callback(receiver, + method, + argv ? argv : empty_argv); + } + +#if defined(QT_NO_EXCEPTIONS) + receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); +#else + try { + receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); + } catch (...) { + locker.relock(); + + QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); + + --connectionLists->inUse; + Q_ASSERT(connectionLists->inUse >= 0); + if (connectionLists->orphaned && !connectionLists->inUse) + delete connectionLists; + throw; + } +#endif + + locker.relock(); + + if (qt_signal_spy_callback_set.slot_end_callback != 0) + qt_signal_spy_callback_set.slot_end_callback(receiver, method); + + QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); + + if (connectionLists->orphaned) + break; + } + + if (connectionLists->orphaned) + break; + } + + --connectionLists->inUse; + Q_ASSERT(connectionLists->inUse >= 0); + if (connectionLists->orphaned) { + if (!connectionLists->inUse) + delete connectionLists; + } else { + sender->d_func()->cleanConnectionLists(); + } + + locker.unlock(); + + if (qt_signal_spy_callback_set.signal_end_callback != 0) + qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index); +} + + +/*!\internal + */ +void QMetaObject::activate(QObject *sender, int signal_index, void **argv) +{ + if (signal_index < 32 + && !qt_signal_spy_callback_set.signal_begin_callback + && !qt_signal_spy_callback_set.signal_end_callback) { + uint signal_mask = 1 << signal_index; + if ((sender->d_func()->connectedSignals & signal_mask) == 0) + // nothing connected to these signals, and no spy + return; + } + activate(sender, signal_index, signal_index, argv); +} + +/*!\internal + */ +void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, + void **argv) +{ + int signal_index = m->methodOffset() + local_signal_index; + if (signal_index < 32 + && !qt_signal_spy_callback_set.signal_begin_callback + && !qt_signal_spy_callback_set.signal_end_callback) { + uint signal_mask = 1 << signal_index; + if ((sender->d_func()->connectedSignals & signal_mask) == 0) + // nothing connected to these signals, and no spy + return; + } + activate(sender, signal_index, signal_index, argv); +} + +/*!\internal + */ +void QMetaObject::activate(QObject *sender, const QMetaObject *m, + int from_local_signal_index, int to_local_signal_index, void **argv) +{ + int offset = m->methodOffset(); + int from_signal_index = offset + from_local_signal_index; + int to_signal_index = offset + to_local_signal_index; + if (to_signal_index < 32 + && !qt_signal_spy_callback_set.signal_begin_callback + && !qt_signal_spy_callback_set.signal_end_callback) { + uint signal_mask = (1 << (to_signal_index + 1)) - 1; + signal_mask ^= (1 << from_signal_index) - 1; + if ((sender->d_func()->connectedSignals & signal_mask) == 0) + // nothing connected to these signals, and no spy + return; + } + activate(sender, from_signal_index, to_signal_index, argv); +} + + +/***************************************************************************** + Properties + *****************************************************************************/ + +#ifndef QT_NO_PROPERTIES + +/*! + Sets the value of the object's \a name property to \a value. + + If the property is defined in the class using Q_PROPERTY then + true is returned on success and false otherwise. If the property + is not defined using Q_PROPERTY, and therefore not listed in the + meta-object, it is added as a dynamic property and false is returned. + + Information about all available properties is provided through the + metaObject() and dynamicPropertyNames(). + + Dynamic properties can be queried again using property() and can be + removed by setting the property value to an invalid QVariant. + Changing the value of a dynamic property causes a QDynamicPropertyChangeEvent + to be sent to the object. + + \bold{Note:} Dynamic properties starting with "_q_" are reserved for internal + purposes. + + \sa property(), metaObject(), dynamicPropertyNames() +*/ +bool QObject::setProperty(const char *name, const QVariant &value) +{ + Q_D(QObject); + const QMetaObject* meta = metaObject(); + if (!name || !meta) + return false; + + int id = meta->indexOfProperty(name); + if (id < 0) { + if (!d->extraData) + d->extraData = new QObjectPrivate::ExtraData; + + const int idx = d->extraData->propertyNames.indexOf(name); + + if (!value.isValid()) { + if (idx == -1) + return false; + d->extraData->propertyNames.removeAt(idx); + d->extraData->propertyValues.removeAt(idx); + } else { + if (idx == -1) { + d->extraData->propertyNames.append(name); + d->extraData->propertyValues.append(value); + } else { + d->extraData->propertyValues[idx] = value; + } + } + + QDynamicPropertyChangeEvent ev(name); + QCoreApplication::sendEvent(this, &ev); + + return false; + } + QMetaProperty p = meta->property(id); +#ifndef QT_NO_DEBUG + if (!p.isWritable()) + qWarning("%s::setProperty: Property \"%s\" invalid," + " read-only or does not exist", metaObject()->className(), name); +#endif + return p.write(this, value); +} + +/*! + Returns the value of the object's \a name property. + + If no such property exists, the returned variant is invalid. + + Information about all available properties is provided through the + metaObject() and dynamicPropertyNames(). + + \sa setProperty(), QVariant::isValid(), metaObject(), dynamicPropertyNames() +*/ +QVariant QObject::property(const char *name) const +{ + Q_D(const QObject); + const QMetaObject* meta = metaObject(); + if (!name || !meta) + return QVariant(); + + int id = meta->indexOfProperty(name); + if (id < 0) { + if (!d->extraData) + return QVariant(); + const int i = d->extraData->propertyNames.indexOf(name); + return d->extraData->propertyValues.value(i); + } + QMetaProperty p = meta->property(id); +#ifndef QT_NO_DEBUG + if (!p.isReadable()) + qWarning("%s::property: Property \"%s\" invalid or does not exist", + metaObject()->className(), name); +#endif + return p.read(this); +} + +/*! + \since 4.2 + + Returns the names of all properties that were dynamically added to + the object using setProperty(). +*/ +QList<QByteArray> QObject::dynamicPropertyNames() const +{ + Q_D(const QObject); + if (d->extraData) + return d->extraData->propertyNames; + return QList<QByteArray>(); +} + +#endif // QT_NO_PROPERTIES + + +/***************************************************************************** + QObject debugging output routines. + *****************************************************************************/ + +static void dumpRecursive(int level, QObject *object) +{ +#if defined(QT_DEBUG) + if (object) { + QByteArray buf; + buf.fill(' ', level / 2 * 8); + if (level % 2) + buf += " "; + QString name = object->objectName(); + QString flags = QLatin1String(""); +#if 0 + if (qApp->focusWidget() == object) + flags += 'F'; + if (object->isWidgetType()) { + QWidget * w = (QWidget *)object; + if (w->isVisible()) { + QString t("<%1,%2,%3,%4>"); + flags += t.arg(w->x()).arg(w->y()).arg(w->width()).arg(w->height()); + } else { + flags += 'I'; + } + } +#endif + qDebug("%s%s::%s %s", (const char*)buf, object->metaObject()->className(), name.toLocal8Bit().data(), + flags.toLatin1().data()); + QObjectList children = object->children(); + if (!children.isEmpty()) { + for (int i = 0; i < children.size(); ++i) + dumpRecursive(level+1, children.at(i)); + } + } +#else + Q_UNUSED(level) + Q_UNUSED(object) +#endif +} + +/*! + Dumps a tree of children to the debug output. + + This function is useful for debugging, but does nothing if the + library has been compiled in release mode (i.e. without debugging + information). + + \sa dumpObjectInfo() +*/ + +void QObject::dumpObjectTree() +{ + dumpRecursive(0, this); +} + +/*! + Dumps information about signal connections, etc. for this object + to the debug output. + + This function is useful for debugging, but does nothing if the + library has been compiled in release mode (i.e. without debugging + information). + + \sa dumpObjectTree() +*/ + +void QObject::dumpObjectInfo() +{ +#if defined(QT_DEBUG) + qDebug("OBJECT %s::%s", metaObject()->className(), + objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data()); + + Q_D(QObject); + QMutexLocker locker(&d->threadData->mutex); + + // first, look for connections where this object is the sender + qDebug(" SIGNALS OUT"); + + if (d->connectionLists) { + for (int signal_index = 0; signal_index < d->connectionLists->count(); ++signal_index) { + const QMetaMethod signal = metaObject()->method(signal_index); + qDebug(" signal: %s", signal.signature()); + + // receivers + const QObjectPrivate::ConnectionList &connectionList = d->connectionLists->at(signal_index); + for (int i = 0; i < connectionList.count(); ++i) { + const QObjectPrivate::Connection &c = connectionList.at(i); + if (!c.receiver) { + qDebug(" <Disconnected receiver>"); + continue; + } + const QMetaObject *receiverMetaObject = c.receiver->metaObject(); + const QMetaMethod method = receiverMetaObject->method(c.method); + qDebug(" --> %s::%s %s", + receiverMetaObject->className(), + c.receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c.receiver->objectName()), + method.signature()); + } + } + } else { + qDebug( " <None>" ); + } + + // now look for connections where this object is the receiver + qDebug(" SIGNALS IN"); + + if (!d->senders.isEmpty()) { + for (int i = 0; i < d->senders.count(); ++i) { + const QObjectPrivate::Sender &s = d->senders.at(i); + const QMetaObject *senderMetaObject = s.sender->metaObject(); + const QMetaMethod signal = senderMetaObject->method(s.signal); + qDebug(" <-- %s::%s %s", + senderMetaObject->className(), + s.sender->objectName().isEmpty() ? "unnamed" : qPrintable(s.sender->objectName()), + signal.signature()); + } + } else { + qDebug(" <None>"); + } +#endif +} + +#ifndef QT_NO_USERDATA +/*!\internal + */ +uint QObject::registerUserData() +{ + static int user_data_registration = 0; + return user_data_registration++; +} + +/*!\internal + */ +QObjectUserData::~QObjectUserData() +{ +} + +/*!\internal + */ +void QObject::setUserData(uint id, QObjectUserData* data) +{ + Q_D(QObject); + if (!d->extraData) + d->extraData = new QObjectPrivate::ExtraData; + + if (d->extraData->userData.size() <= (int) id) + d->extraData->userData.resize((int) id + 1); + d->extraData->userData[id] = data; +} + +/*!\internal + */ +QObjectUserData* QObject::userData(uint id) const +{ + Q_D(const QObject); + if (!d->extraData) + return 0; + if ((int)id < d->extraData->userData.size()) + return d->extraData->userData.at(id); + return 0; +} + +#endif // QT_NO_USERDATA + + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QObject *o) { +#ifndef Q_BROKEN_DEBUG_STREAM + if (!o) + return dbg << "QObject(0x0) "; + dbg.nospace() << o->metaObject()->className() << "(" << (void *)o; + if (!o->objectName().isEmpty()) + dbg << ", name = " << o->objectName(); + dbg << ')'; + return dbg.space(); +#else + qWarning("This compiler doesn't support streaming QObject to QDebug"); + return dbg; + Q_UNUSED(o); +#endif +} +#endif + +/*! + \fn void QObject::insertChild(QObject *object) + + Use setParent() instead, i.e., call object->setParent(this). +*/ + +/*! + \fn void QObject::removeChild(QObject *object) + + Use setParent() instead, i.e., call object->setParent(0). +*/ + +/*! + \fn bool QObject::isA(const char *className) const + + Compare \a className with the object's metaObject()->className() instead. +*/ + +/*! + \fn const char *QObject::className() const + + Use metaObject()->className() instead. +*/ + +/*! + \fn const char *QObject::name() const + + Use objectName() instead. +*/ + +/*! + \fn const char *QObject::name(const char *defaultName) const + + Use objectName() instead. +*/ + +/*! + \fn void QObject::setName(const char *name) + + Use setObjectName() instead. +*/ + +/*! + \fn bool QObject::checkConnectArgs(const char *signal, const + QObject *object, const char *method) + + Use QMetaObject::checkConnectArgs() instead. +*/ + +/*! + \fn QByteArray QObject::normalizeSignalSlot(const char *signalSlot) + + Use QMetaObject::normalizedSignature() instead. +*/ + +/*! + \fn const char *QMetaObject::superClassName() const + + \internal +*/ + +/*! + \macro Q_CLASSINFO(Name, Value) + \relates QObject + + This macro associates extra information to the class, which is + available using QObject::metaObject(). Except for the ActiveQt + extension, Qt doesn't use this information. + + The extra information takes the form of a \a Name string and a \a + Value literal string. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 35 + + \sa QMetaObject::classInfo() +*/ + +/*! + \macro Q_INTERFACES(...) + \relates QObject + + This macro tells Qt which interfaces the class implements. This + is used when implementing plugins. + + Example: + + \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.h 1 + \dots + \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.h 3 + + See the \l{tools/plugandpaintplugins/basictools}{Plug & Paint + Basic Tools} example for details. + + \sa Q_DECLARE_INTERFACE(), Q_EXPORT_PLUGIN2(), {How to Create Qt Plugins} +*/ + +/*! + \macro Q_PROPERTY(...) + \relates QObject + + This macro is used for declaring properties in classes that + inherit QObject. Properties behave like class data members, but + they have additional features accessible through the \l + {Meta-Object System}. + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 36 + + The property name and type and the \c READ function are required. + The type can be any type supported by QVariant, or it can be a + user-defined type. The other items are optional, but a \c WRITE + function is common. The attributes default to true except \c USER, + which defaults to false. + + For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 37 + + For more details about how to use this macro, and a more detailed + example of its use, see the discussion on \l {Qt's Property System}. + + \sa {Qt's Property System} +*/ + +/*! + \macro Q_ENUMS(...) + \relates QObject + + This macro registers one or several enum types to the meta-object + system. + + For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 38 + + If you want to register an enum that is declared in another class, + the enum must be fully qualified with the name of the class + defining it. In addition, the class \e defining the enum has to + inherit QObject as well as declare the enum using Q_ENUMS(). + + \sa {Qt's Property System} +*/ + +/*! + \macro Q_FLAGS(...) + \relates QObject + + This macro registers one or several \l{QFlags}{flags types} to the + meta-object system. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 39 + + \note This macro takes care of registering individual flag values + with the meta-object system, so it is unnecessary to use Q_ENUMS() + in addition to this macro. + + \sa {Qt's Property System} +*/ + +/*! + \macro Q_OBJECT + \relates QObject + + The Q_OBJECT macro must appear in the private section of a class + definition that declares its own signals and slots or that uses + other services provided by Qt's meta-object system. + + For example: + + \snippet doc/src/snippets/signalsandslots/signalsandslots.h 1 + \codeline + \snippet doc/src/snippets/signalsandslots/signalsandslots.h 2 + \snippet doc/src/snippets/signalsandslots/signalsandslots.h 3 + + \note This macro requires the class to be a subclass of QObject. Use + Q_GADGET instead of Q_OBJECT to enable the meta object system's support + for enums in a class that is not a QObject subclass. Q_GADGET makes a + class member, \c{staticMetaObject}, available. + \c{staticMetaObject} is of type QMetaObject and provides access to the + enums declared with Q_ENUMS. + Q_GADGET is provided only for C++. + + \sa {Meta-Object System}, {Signals and Slots}, {Qt's Property System} +*/ + +/*! + \macro Q_SIGNALS + \relates QObject + + Use this macro to replace the \c signals keyword in class + declarations, when you want to use Qt Signals and Slots with a + \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}. + + The macro is normally used when \c no_keywords is specified with + the \c CONFIG variable in the \c .pro file, but it can be used + even when \c no_keywords is \e not specified. +*/ + +/*! + \macro Q_SIGNAL + \relates QObject + + This is an additional macro that allows you to mark a single + function as a signal. It can be quite useful, especially when you + use a 3rd-party source code parser which doesn't understand a \c + signals or \c Q_SIGNALS groups. + + Use this macro to replace the \c signals keyword in class + declarations, when you want to use Qt Signals and Slots with a + \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}. + + The macro is normally used when \c no_keywords is specified with + the \c CONFIG variable in the \c .pro file, but it can be used + even when \c no_keywords is \e not specified. +*/ + +/*! + \macro Q_SLOTS + \relates QObject + + Use this macro to replace the \c slots keyword in class + declarations, when you want to use Qt Signals and Slots with a + \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}. + + The macro is normally used when \c no_keywords is specified with + the \c CONFIG variable in the \c .pro file, but it can be used + even when \c no_keywords is \e not specified. +*/ + +/*! + \macro Q_SLOT + \relates QObject + + This is an additional macro that allows you to mark a single + function as a slot. It can be quite useful, especially when you + use a 3rd-party source code parser which doesn't understand a \c + slots or \c Q_SLOTS groups. + + Use this macro to replace the \c slots keyword in class + declarations, when you want to use Qt Signals and Slots with a + \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}. + + The macro is normally used when \c no_keywords is specified with + the \c CONFIG variable in the \c .pro file, but it can be used + even when \c no_keywords is \e not specified. +*/ + +/*! + \macro Q_EMIT + \relates QObject + + Use this macro to replace the \c emit keyword for emitting + signals, when you want to use Qt Signals and Slots with a + \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}. + + The macro is normally used when \c no_keywords is specified with + the \c CONFIG variable in the \c .pro file, but it can be used + even when \c no_keywords is \e not specified. +*/ + +/*! + \macro Q_INVOKABLE + \relates QObject + + Apply this macro to definitions of member functions to allow them to + be invoked via the meta-object system. The macro is written before + the return type, as shown in the following example: + + \snippet snippets/qmetaobject-invokable/window.h Window class with invokable method + + The \c invokableMethod() function is marked up using Q_INVOKABLE, causing + it to be registered with the meta-object system and enabling it to be + invoked using QMetaObject::invokeMethod(). + Since \c normalMethod() function is not registered in this way, it cannot + be invoked using QMetaObject::invokeMethod(). +*/ + +/*! + \typedef QObjectList + \relates QObject + + Synonym for QList<QObject *>. +*/ + +#ifdef QT_JAMBI_BUILD +class QDPtrAccessor : public QObject { +public: + QObjectData *d() const { return d_ptr; } +}; +#endif + +void qDeleteInEventHandler(QObject *o) +{ +#ifdef QT_JAMBI_BUILD + if (!o) + return; + ((QDPtrAccessor *) o)->d()->inEventHandler = false; +#endif + delete o; +} + +QT_END_NAMESPACE + +#include "moc_qobject.cpp" diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h new file mode 100644 index 0000000..dbec0a6 --- /dev/null +++ b/src/corelib/kernel/qobject.h @@ -0,0 +1,480 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOBJECT_H +#define QOBJECT_H + +#ifndef QT_NO_QOBJECT + +#include <QtCore/qobjectdefs.h> +#include <QtCore/qstring.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qlist.h> +#ifdef QT_INCLUDE_COMPAT +#include <QtCore/qcoreevent.h> +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QEvent; +class QTimerEvent; +class QChildEvent; +struct QMetaObject; +class QVariant; +class QObjectPrivate; +class QObject; +class QThread; +class QWidget; +#ifndef QT_NO_REGEXP +class QRegExp; +#endif +#ifndef QT_NO_USERDATA +class QObjectUserData; +#endif + +typedef QList<QObject*> QObjectList; + +#if defined Q_CC_MSVC && _MSC_VER < 1300 +template<typename T> inline T qFindChild(const QObject *o, const QString &name = QString(), T = 0); +template<typename T> inline QList<T> qFindChildren(const QObject *o, const QString &name = QString(), T = 0); +# ifndef QT_NO_REGEXP +template<typename T> inline QList<T> qFindChildren(const QObject *o, const QRegExp &re, T = 0); +# endif +#else +template<typename T> inline T qFindChild(const QObject *, const QString & = QString()); +template<typename T> inline QList<T> qFindChildren(const QObject *, const QString & = QString()); +# ifndef QT_NO_REGEXP +template<typename T> inline QList<T> qFindChildren(const QObject *, const QRegExp &); +# endif +#endif + +class QObjectData { +public: + virtual ~QObjectData() = 0; + QObject *q_ptr; + QObject *parent; + QObjectList children; + + uint isWidget : 1; + uint pendTimer : 1; + uint blockSig : 1; + uint wasDeleted : 1; + uint ownObjectName : 1; + uint sendChildEvents : 1; + uint receiveChildEvents : 1; + uint inEventHandler : 1; + uint inThreadChangeEvent : 1; + uint unused : 23; + int postedEvents; +}; + + +class Q_CORE_EXPORT QObject +{ + Q_OBJECT + Q_PROPERTY(QString objectName READ objectName WRITE setObjectName) + Q_DECLARE_PRIVATE(QObject) + +public: + Q_INVOKABLE explicit QObject(QObject *parent=0); + virtual ~QObject(); + + virtual bool event(QEvent *); + virtual bool eventFilter(QObject *, QEvent *); + +#ifdef qdoc + static QString tr(const char *sourceText, const char *comment = 0, int n = -1); + static QString trUtf8(const char *sourceText, const char *comment = 0, int n = -1); + virtual const QMetaObject *metaObject() const; + static const QMetaObject staticMetaObject; +#endif +#ifdef QT_NO_TRANSLATION + static QString tr(const char *sourceText, const char *, int) + { return QString::fromLatin1(sourceText); } + static QString tr(const char *sourceText, const char * = 0) + { return QString::fromLatin1(sourceText); } +#ifndef QT_NO_TEXTCODEC + static QString trUtf8(const char *sourceText, const char *, int) + { return QString::fromUtf8(sourceText); } + static QString trUtf8(const char *sourceText, const char * = 0) + { return QString::fromUtf8(sourceText); } +#endif +#endif //QT_NO_TRANSLATION + + QString objectName() const; + void setObjectName(const QString &name); + + inline bool isWidgetType() const { return d_ptr->isWidget; } + + inline bool signalsBlocked() const { return d_ptr->blockSig; } + bool blockSignals(bool b); + + QThread *thread() const; + void moveToThread(QThread *thread); + + int startTimer(int interval); + void killTimer(int id); + +#ifndef QT_NO_MEMBER_TEMPLATES + template<typename T> + inline T findChild(const QString &aName = QString()) const + { return qFindChild<T>(this, aName); } + + template<typename T> + inline QList<T> findChildren(const QString &aName = QString()) const + { return qFindChildren<T>(this, aName); } + +#ifndef QT_NO_REGEXP + template<typename T> + inline QList<T> findChildren(const QRegExp &re) const + { return qFindChildren<T>(this, re); } +#endif +#endif + +#ifdef QT3_SUPPORT + QT3_SUPPORT QObject *child(const char *objName, const char *inheritsClass = 0, + bool recursiveSearch = true) const; + QT3_SUPPORT QObjectList queryList(const char *inheritsClass = 0, + const char *objName = 0, + bool regexpMatch = true, + bool recursiveSearch = true) const; +#endif + inline const QObjectList &children() const { return d_ptr->children; } + + void setParent(QObject *); + void installEventFilter(QObject *); + void removeEventFilter(QObject *); + + + static bool connect(const QObject *sender, const char *signal, + const QObject *receiver, const char *member, Qt::ConnectionType = +#ifdef qdoc + Qt::AutoConnection +#else +#ifdef QT3_SUPPORT + Qt::AutoCompatConnection +#else + Qt::AutoConnection +#endif +#endif + ); + inline bool connect(const QObject *sender, const char *signal, + const char *member, Qt::ConnectionType type = +#ifdef qdoc + Qt::AutoConnection +#else +#ifdef QT3_SUPPORT + Qt::AutoCompatConnection +#else + Qt::AutoConnection +#endif +#endif + ) const; + + static bool disconnect(const QObject *sender, const char *signal, + const QObject *receiver, const char *member); + inline bool disconnect(const char *signal = 0, + const QObject *receiver = 0, const char *member = 0) + { return disconnect(this, signal, receiver, member); } + inline bool disconnect(const QObject *receiver, const char *member = 0) + { return disconnect(this, 0, receiver, member); } + + void dumpObjectTree(); + void dumpObjectInfo(); + +#ifndef QT_NO_PROPERTIES + bool setProperty(const char *name, const QVariant &value); + QVariant property(const char *name) const; + QList<QByteArray> dynamicPropertyNames() const; +#endif // QT_NO_PROPERTIES + +#ifndef QT_NO_USERDATA + static uint registerUserData(); + void setUserData(uint id, QObjectUserData* data); + QObjectUserData* userData(uint id) const; +#endif // QT_NO_USERDATA + +Q_SIGNALS: + void destroyed(QObject * = 0); + +public: + inline QObject *parent() const { return d_ptr->parent; } + + inline bool inherits(const char *classname) const + { return const_cast<QObject *>(this)->qt_metacast(classname) != 0; } + +public Q_SLOTS: + void deleteLater(); + +protected: + QObject *sender() const; + int receivers(const char* signal) const; + + virtual void timerEvent(QTimerEvent *); + virtual void childEvent(QChildEvent *); + virtual void customEvent(QEvent *); + + virtual void connectNotify(const char *signal); + virtual void disconnectNotify(const char *signal); + +#ifdef QT3_SUPPORT +public: + QT3_SUPPORT_CONSTRUCTOR QObject(QObject *parent, const char *name); + inline QT3_SUPPORT void insertChild(QObject *o) + { if (o) o->setParent(this); } + inline QT3_SUPPORT void removeChild(QObject *o) + { if (o) o->setParent(0); } + inline QT3_SUPPORT bool isA(const char *classname) const + { return qstrcmp(classname, metaObject()->className()) == 0; } + inline QT3_SUPPORT const char *className() const { return metaObject()->className(); } + inline QT3_SUPPORT const char *name() const { return objectName().latin1_helper(); } + inline QT3_SUPPORT const char *name(const char *defaultName) const + { QString s = objectName(); return s.isEmpty()?defaultName:s.latin1_helper(); } + inline QT3_SUPPORT void setName(const char *aName) { setObjectName(QLatin1String(aName)); } +protected: + inline QT3_SUPPORT bool checkConnectArgs(const char *signal, + const QObject *, + const char *member) + { return QMetaObject::checkConnectArgs(signal, member); } + static inline QT3_SUPPORT QByteArray normalizeSignalSlot(const char *signalSlot) + { return QMetaObject::normalizedSignature(signalSlot); } +#endif + +protected: + QObject(QObjectPrivate &dd, QObject *parent = 0); + +protected: + QObjectData *d_ptr; + + static const QMetaObject staticQtMetaObject; + + friend struct QMetaObject; + friend class QApplication; + friend class QApplicationPrivate; + friend class QCoreApplication; + friend class QCoreApplicationPrivate; + friend class QWidget; + friend class QThreadData; + +private: + Q_DISABLE_COPY(QObject) + Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *)) +}; + +inline bool QObject::connect(const QObject *asender, const char *asignal, + const char *amember, Qt::ConnectionType atype) const +{ return connect(asender, asignal, this, amember, atype); } + +#ifndef QT_NO_USERDATA +class Q_CORE_EXPORT QObjectUserData { +public: + virtual ~QObjectUserData(); +}; +#endif + +Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QRegExp *re, + const QMetaObject &mo, QList<void *> *list); +Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo); + +#if defined Q_CC_MSVC && _MSC_VER < 1300 + +template<typename T> +inline T qFindChild(const QObject *o, const QString &name, T) +{ return static_cast<T>(qt_qFindChild_helper(o, name, ((T)0)->staticMetaObject)); } + +template<typename T> +inline QList<T> qFindChildren(const QObject *o, const QString &name, T) +{ + QList<T> list; + union { + QList<T> *typedList; + QList<void *> *voidList; + } u; + u.typedList = &list; + qt_qFindChildren_helper(o, name, 0, ((T)0)->staticMetaObject, u.voidList); + return list; +} + +template<typename T> +inline T qFindChild(const QObject *o, const QString &name) +{ return qFindChild<T>(o, name, T(0)); } + +template<typename T> +inline T qFindChild(const QObject *o) +{ return qFindChild<T>(o, QString(), T(0)); } + +template<typename T> +inline QList<T> qFindChildren(const QObject *o, const QString &name) +{ return qFindChildren<T>(o, name, T(0)); } + +template<typename T> +inline QList<T> qFindChildren(const QObject *o) +{ return qFindChildren<T>(o, QString(), T(0)); } + +#ifndef QT_NO_REGEXP +template<typename T> +inline QList<T> qFindChildren(const QObject *o, const QRegExp &re, T) +{ + QList<T> list; + union { + QList<T> *typedList; + QList<void *> *voidList; + } u; + u.typedList = &list; + qt_qFindChildren_helper(o, 0, &re, ((T)0)->staticMetaObject, u.voidList); + return list; +} + +template<typename T> +inline QList<T> qFindChildren(const QObject *o, const QRegExp &re) +{ return qFindChildren<T>(o, re, T(0)); } + +#endif + +#ifdef Q_MOC_RUN +# define Q_DECLARE_INTERFACE(IFace, IId) Q_DECLARE_INTERFACE(IFace, IId) +#endif // Q_MOC_RUN + + +template <class T> inline T qobject_cast_helper(QObject *object, T) +{ return static_cast<T>(((T)0)->staticMetaObject.cast(object)); } + +template <class T> inline T qobject_cast_helper(const QObject *object, T) +{ return static_cast<T>(const_cast<const QObject *>(((T)0)->staticMetaObject.cast(const_cast<QObject *>(object)))); } + +template <class T> +inline T qobject_cast(QObject *object) +{ return qobject_cast_helper<T>(object, T(0)); } + +template <class T> +inline T qobject_cast(const QObject *object) +{ return qobject_cast_helper<T>(object, T(0)); } + +#ifndef Q_MOC_RUN +# define Q_DECLARE_INTERFACE(IFace, IId) \ + template <> inline IFace *qobject_cast_helper<IFace *>(QObject *object, IFace *) \ + { return (IFace *)(object ? object->qt_metacast(IId) : 0); } \ + template <> inline IFace *qobject_cast_helper<IFace *>(const QObject *object, IFace *) \ + { return (IFace *)(object ? const_cast<QObject *>(object)->qt_metacast(IId) : 0); } +#endif // Q_MOC_RUN + +#else + +template<typename T> +inline T qFindChild(const QObject *o, const QString &name) +{ return static_cast<T>(qt_qFindChild_helper(o, name, reinterpret_cast<T>(0)->staticMetaObject)); } + +template<typename T> +inline QList<T> qFindChildren(const QObject *o, const QString &name) +{ + QList<T> list; + union { + QList<T> *typedList; + QList<void *> *voidList; + } u; + u.typedList = &list; + qt_qFindChildren_helper(o, name, 0, reinterpret_cast<T>(0)->staticMetaObject, u.voidList); + return list; +} + +#ifndef QT_NO_REGEXP +template<typename T> +inline QList<T> qFindChildren(const QObject *o, const QRegExp &re) +{ + QList<T> list; + union { + QList<T> *typedList; + QList<void *> *voidList; + } u; + u.typedList = &list; + qt_qFindChildren_helper(o, QString(), &re, reinterpret_cast<T>(0)->staticMetaObject, u.voidList); + return list; +} +#endif + +template <class T> +inline T qobject_cast(QObject *object) +{ +#if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) + reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(object)); +#endif + return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast(object)); +} + +template <class T> +inline T qobject_cast(const QObject *object) +{ + // this will cause a compilation error if T is not const + register T ptr = static_cast<T>(object); + Q_UNUSED(ptr); + +#if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK) + reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(const_cast<QObject *>(object))); +#endif + return static_cast<T>(const_cast<QObject *>(reinterpret_cast<T>(0)->staticMetaObject.cast(const_cast<QObject *>(object)))); +} + + +#ifndef Q_MOC_RUN +# define Q_DECLARE_INTERFACE(IFace, IId) \ + template <> inline IFace *qobject_cast<IFace *>(QObject *object) \ + { return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : 0)); } \ + template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \ + { return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : 0)); } +#endif // Q_MOC_RUN + +#endif + +#ifndef QT_NO_DEBUG_STREAM +Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *); +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif + +#endif // QOBJECT_H diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h new file mode 100644 index 0000000..b324334 --- /dev/null +++ b/src/corelib/kernel/qobject_p.h @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOBJECT_P_H +#define QOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qobject.h" +#include "QtCore/qpointer.h" +#include "QtCore/qcoreevent.h" +#include "QtCore/qlist.h" +#include "QtCore/qvector.h" +#include "QtCore/qreadwritelock.h" +#include "QtCore/qvariant.h" + +QT_BEGIN_NAMESPACE + +class QVariant; +class QThreadData; +class QObjectConnectionListVector; + +/* mirrored in QtTestLib, DON'T CHANGE without prior warning */ +struct QSignalSpyCallbackSet +{ + typedef void (*BeginCallback)(QObject *caller, int method_index, void **argv); + typedef void (*EndCallback)(QObject *caller, int method_index); + BeginCallback signal_begin_callback, + slot_begin_callback; + EndCallback signal_end_callback, + slot_end_callback; +}; +void Q_CORE_EXPORT qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet &callback_set); + +extern QSignalSpyCallbackSet Q_CORE_EXPORT qt_signal_spy_callback_set; + +inline QObjectData::~QObjectData() {} + +enum { QObjectPrivateVersion = QT_VERSION }; + +class Q_CORE_EXPORT QObjectPrivate : public QObjectData +{ + Q_DECLARE_PUBLIC(QObject) + +public: + QObjectPrivate(int version = QObjectPrivateVersion); + virtual ~QObjectPrivate(); + +#ifdef QT3_SUPPORT + QList<QObject *> pendingChildInsertedEvents; + void sendPendingChildInsertedEvents(); + void removePendingChildInsertedEvents(QObject *child); +#else + // preserve binary compatibility with code compiled without Qt 3 support + QList<QObject *> unused; +#endif + + // id of the thread that owns the object + QThreadData *threadData; + void moveToThread_helper(); + void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); + void _q_reregisterTimers(void *pointer); + + struct Sender + { + QObject *sender; + int signal; + int ref; + }; + + // object currently activating the object + Sender *currentSender; + + QObject *currentChildBeingDeleted; + + bool isSender(const QObject *receiver, const char *signal) const; + QObjectList receiverList(const char *signal) const; + QObjectList senderList() const; + + QList<QPointer<QObject> > eventFilters; + + void setParent_helper(QObject *); + + void deleteChildren(); + + static void clearGuards(QObject *); + + struct ExtraData + { +#ifndef QT_NO_USERDATA + QVector<QObjectUserData *> userData; +#endif + QList<QByteArray> propertyNames; + QList<QVariant> propertyValues; + }; + ExtraData *extraData; + mutable quint32 connectedSignals; + + QString objectName; + + // Note: you must hold the signalSlotLock() before accessing the lists below or calling the functions + struct Connection + { + QObject *receiver; + int method; + uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking + QBasicAtomicPointer<int> argumentTypes; + }; + typedef QList<Connection> ConnectionList; + + QObjectConnectionListVector *connectionLists; + void addConnection(int signal, Connection *c); + void removeReceiver(int signal, QObject *receiver); + void cleanConnectionLists(); + + QList<Sender> senders; + void refSender(QObject *sender, int signal); + void derefSender(QObject *sender, int signal); + void removeSender(QObject *sender, int signal); + + static Sender *setCurrentSender(QObject *receiver, + Sender *sender); + static void resetCurrentSender(QObject *receiver, + Sender *currentSender, + Sender *previousSender); + static int *setDeleteWatch(QObjectPrivate *d, int *newWatch); + static void resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch); + + int *deleteWatch; + + static QObjectPrivate *get(QObject *o) { + return o->d_func(); + } +}; + +Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE); + +class QSemaphore; +class Q_CORE_EXPORT QMetaCallEvent : public QEvent +{ +public: + QMetaCallEvent(int id, const QObject *sender, int signalId, + int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0); + ~QMetaCallEvent(); + + inline int id() const { return id_; } + inline const QObject *sender() const { return sender_; } + inline int signalId() const { return signalId_; } + inline void **args() const { return args_; } + + virtual int placeMetaCall(QObject *object); + +private: + int id_; + const QObject *sender_; + int signalId_; + int nargs_; + int *types_; + void **args_; + QSemaphore *semaphore_; +}; + +class Q_CORE_EXPORT QBoolBlocker +{ +public: + inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;} + inline ~QBoolBlocker(){block = reset; } +private: + bool █ + bool reset; +}; + +void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o); + +QT_END_NAMESPACE + +#endif // QOBJECT_P_H diff --git a/src/corelib/kernel/qobjectcleanuphandler.cpp b/src/corelib/kernel/qobjectcleanuphandler.cpp new file mode 100644 index 0000000..d2241ad --- /dev/null +++ b/src/corelib/kernel/qobjectcleanuphandler.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qobjectcleanuphandler.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QObjectCleanupHandler + \brief The QObjectCleanupHandler class watches the lifetime of multiple QObjects. + + \ingroup objectmodel + + A QObjectCleanupHandler is useful whenever you need to know when a + number of \l{QObject}s that are owned by someone else have been + deleted. This is important, for example, when referencing memory + in an application that has been allocated in a shared library. + + To keep track of some \l{QObject}s, create a + QObjectCleanupHandler, and add() the objects you are interested + in. If you are no longer interested in tracking a particular + object, use remove() to remove it from the cleanup handler. If an + object being tracked by the cleanup handler gets deleted by + someone else it will automatically be removed from the cleanup + handler. You can delete all the objects in the cleanup handler + with clear(), or by destroying the cleanup handler. isEmpty() + returns true if the QObjectCleanupHandler has no objects to keep + track of. + + \sa QPointer +*/ + +/*! + Constructs an empty QObjectCleanupHandler. +*/ +QObjectCleanupHandler::QObjectCleanupHandler() +{ +} + +/*! + Destroys the cleanup handler. All objects in this cleanup handler + will be deleted. + + \sa clear() +*/ +QObjectCleanupHandler::~QObjectCleanupHandler() +{ + clear(); +} + +/*! + Adds \a object to this cleanup handler and returns the pointer to + the object. + + \sa remove() +*/ +QObject *QObjectCleanupHandler::add(QObject* object) +{ + if (!object) + return 0; + + connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); + cleanupObjects.insert(0, object); + return object; +} + +/*! + Removes the \a object from this cleanup handler. The object will + not be destroyed. + + \sa add() +*/ +void QObjectCleanupHandler::remove(QObject *object) +{ + int index; + if ((index = cleanupObjects.indexOf(object)) != -1) { + cleanupObjects.removeAt(index); + disconnect(object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); + } +} + +/*! + Returns true if this cleanup handler is empty or if all objects in + this cleanup handler have been destroyed; otherwise return false. + + \sa add() remove() clear() +*/ +bool QObjectCleanupHandler::isEmpty() const +{ + return cleanupObjects.isEmpty(); +} + +/*! + Deletes all objects in this cleanup handler. The cleanup handler + becomes empty. + + \sa isEmpty() +*/ +void QObjectCleanupHandler::clear() +{ + while (!cleanupObjects.isEmpty()) + delete cleanupObjects.takeFirst(); +} + +void QObjectCleanupHandler::objectDestroyed(QObject *object) +{ + remove(object); +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qobjectcleanuphandler.h b/src/corelib/kernel/qobjectcleanuphandler.h new file mode 100644 index 0000000..67db5d3 --- /dev/null +++ b/src/corelib/kernel/qobjectcleanuphandler.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOBJECTCLEANUPHANDLER_H +#define QOBJECTCLEANUPHANDLER_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class Q_CORE_EXPORT QObjectCleanupHandler : public QObject +{ + Q_OBJECT + +public: + QObjectCleanupHandler(); + ~QObjectCleanupHandler(); + + QObject* add(QObject* object); + void remove(QObject *object); + bool isEmpty() const; + void clear(); + +private: + // ### move into d pointer + QObjectList cleanupObjects; + +private Q_SLOTS: + void objectDestroyed(QObject *); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QOBJECTCLEANUPHANDLER_H diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h new file mode 100644 index 0000000..3a22323 --- /dev/null +++ b/src/corelib/kernel/qobjectdefs.h @@ -0,0 +1,465 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOBJECTDEFS_H +#define QOBJECTDEFS_H + +#include <QtCore/qnamespace.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QByteArray; + +class QString; + +#ifndef Q_MOC_OUTPUT_REVISION +#define Q_MOC_OUTPUT_REVISION 61 +#endif + +// The following macros are our "extensions" to C++ +// They are used, strictly speaking, only by the moc. + +#ifndef Q_MOC_RUN +# if defined(QT_NO_KEYWORDS) +# define QT_NO_EMIT +# else +# define slots +# define signals protected +# endif +# define Q_SLOTS +# define Q_SIGNALS protected +# define Q_PRIVATE_SLOT(d, signature) +# define Q_EMIT +#ifndef QT_NO_EMIT +# define emit +#endif +#define Q_CLASSINFO(name, value) +#define Q_INTERFACES(x) +#define Q_PROPERTY(text) +#define Q_OVERRIDE(text) +#define Q_ENUMS(x) +#define Q_FLAGS(x) +#ifdef QT3_SUPPORT +# define Q_SETS(x) +#endif +#define Q_SCRIPTABLE +#define Q_INVOKABLE +#define Q_SIGNAL +#define Q_SLOT + +#ifndef QT_NO_TRANSLATION +# ifndef QT_NO_TEXTCODEC +// full set of tr functions +// ### Qt 5: merge overloads +# define QT_TR_FUNCTIONS \ + static inline QString tr(const char *s, const char *c = 0) \ + { return staticMetaObject.tr(s, c); } \ + static inline QString trUtf8(const char *s, const char *c = 0) \ + { return staticMetaObject.trUtf8(s, c); } \ + static inline QString tr(const char *s, const char *c, int n) \ + { return staticMetaObject.tr(s, c, n); } \ + static inline QString trUtf8(const char *s, const char *c, int n) \ + { return staticMetaObject.trUtf8(s, c, n); } +# else +// no QTextCodec, no utf8 +// ### Qt 5: merge overloads +# define QT_TR_FUNCTIONS \ + static inline QString tr(const char *s, const char *c = 0) \ + { return staticMetaObject.tr(s, c); } \ + static inline QString tr(const char *s, const char *c, int n) \ + { return staticMetaObject.tr(s, c, n); } +# endif +#else +// inherit the ones from QObject +# define QT_TR_FUNCTIONS +#endif + +#if defined(QT_NO_MEMBER_TEMPLATES) || defined(QT_NO_QOBJECT_CHECK) +/* tmake ignore Q_OBJECT */ +#define Q_OBJECT_CHECK +#else + +/* This is a compile time check that ensures that any class cast with qobject_cast + actually contains a Q_OBJECT macro. Note: qobject_cast will fail if a QObject + subclass doesn't contain Q_OBJECT. + + In qt_check_for_QOBJECT_macro, we call a dummy templated function with two + parameters, the first being "this" and the other the target of the qobject + cast. If the types are not identical, we know that a Q_OBJECT macro is missing. + + If you get a compiler error here, make sure that the class you are casting + to contains a Q_OBJECT macro. +*/ + +/* tmake ignore Q_OBJECT */ +#define Q_OBJECT_CHECK \ + template <typename T> inline void qt_check_for_QOBJECT_macro(const T &_q_argument) const \ + { int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i; } + +template <typename T> +inline int qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; } + +template <typename T1, typename T2> +inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {} +#endif // QT_NO_MEMBER_TEMPLATES + +/* tmake ignore Q_OBJECT */ +#define Q_OBJECT \ +public: \ + Q_OBJECT_CHECK \ + static const QMetaObject staticMetaObject; \ + virtual const QMetaObject *metaObject() const; \ + virtual void *qt_metacast(const char *); \ + QT_TR_FUNCTIONS \ + virtual int qt_metacall(QMetaObject::Call, int, void **); \ +private: +/* tmake ignore Q_OBJECT */ +#define Q_OBJECT_FAKE Q_OBJECT +/* tmake ignore Q_GADGET */ +#define Q_GADGET \ +public: \ + static const QMetaObject staticMetaObject; \ +private: +#else // Q_MOC_RUN +#define slots slots +#define signals signals +#define Q_SLOTS Q_SLOTS +#define Q_SIGNALS Q_SIGNALS +#define Q_CLASSINFO(name, value) Q_CLASSINFO(name, value) +#define Q_INTERFACES(x) Q_INTERFACES(x) +#define Q_PROPERTY(text) Q_PROPERTY(text) +#define Q_OVERRIDE(text) Q_OVERRIDE(text) +#define Q_ENUMS(x) Q_ENUMS(x) +#define Q_FLAGS(x) Q_FLAGS(x) +#ifdef QT3_SUPPORT +# define Q_SETS(x) Q_SETS(x) +#endif + /* tmake ignore Q_OBJECT */ +#define Q_OBJECT Q_OBJECT + /* tmake ignore Q_OBJECT */ +#define Q_OBJECT_FAKE Q_OBJECT_FAKE + /* tmake ignore Q_GADGET */ +#define Q_GADGET Q_GADGET +#define Q_SCRIPTABLE Q_SCRIPTABLE +#define Q_INVOKABLE Q_INVOKABLE +#define Q_SIGNAL Q_SIGNAL +#define Q_SLOT Q_SLOT +#endif //Q_MOC_RUN + +// macro for onaming members +#ifdef METHOD +#undef METHOD +#endif +#ifdef SLOT +#undef SLOT +#endif +#ifdef SIGNAL +#undef SIGNAL +#endif + +Q_CORE_EXPORT const char *qFlagLocation(const char *method); + +#define QTOSTRING_HELPER(s) #s +#define QTOSTRING(s) QTOSTRING_HELPER(s) +#ifndef QT_NO_DEBUG +# define QLOCATION "\0"__FILE__":"QTOSTRING(__LINE__) +# define METHOD(a) qFlagLocation("0"#a QLOCATION) +# define SLOT(a) qFlagLocation("1"#a QLOCATION) +# define SIGNAL(a) qFlagLocation("2"#a QLOCATION) +#else +# define METHOD(a) "0"#a +# define SLOT(a) "1"#a +# define SIGNAL(a) "2"#a +#endif + +#ifdef QT3_SUPPORT +#define METHOD_CODE 0 // member type codes +#define SLOT_CODE 1 +#define SIGNAL_CODE 2 +#endif + +#define QMETHOD_CODE 0 // member type codes +#define QSLOT_CODE 1 +#define QSIGNAL_CODE 2 + +#define Q_ARG(type, data) QArgument<type >(#type, data) +#define Q_RETURN_ARG(type, data) QReturnArgument<type >(#type, data) + +class QObject; +class QMetaMethod; +class QMetaEnum; +class QMetaProperty; +class QMetaClassInfo; + + +class Q_CORE_EXPORT QGenericArgument +{ +public: + inline QGenericArgument(const char *aName = 0, const void *aData = 0) + : _data(aData), _name(aName) {} + inline void *data() const { return const_cast<void *>(_data); } + inline const char *name() const { return _name; } + +private: + const void *_data; + const char *_name; +}; + +class Q_CORE_EXPORT QGenericReturnArgument: public QGenericArgument +{ +public: + inline QGenericReturnArgument(const char *aName = 0, void *aData = 0) + : QGenericArgument(aName, aData) + {} +}; + +template <class T> +class QArgument: public QGenericArgument +{ +public: + inline QArgument(const char *aName, const T &aData) + : QGenericArgument(aName, static_cast<const void *>(&aData)) + {} +}; + + +template <typename T> +class QReturnArgument: public QGenericReturnArgument +{ +public: + inline QReturnArgument(const char *aName, T &aData) + : QGenericReturnArgument(aName, static_cast<void *>(&aData)) + {} +}; + +struct Q_CORE_EXPORT QMetaObject +{ + const char *className() const; + const QMetaObject *superClass() const; + + QObject *cast(QObject *obj) const; + +#ifndef QT_NO_TRANSLATION + // ### Qt 4: Merge overloads + QString tr(const char *s, const char *c) const; + QString trUtf8(const char *s, const char *c) const; + QString tr(const char *s, const char *c, int n) const; + QString trUtf8(const char *s, const char *c, int n) const; +#endif // QT_NO_TRANSLATION + + int methodOffset() const; + int enumeratorOffset() const; + int propertyOffset() const; + int classInfoOffset() const; + + int constructorCount() const; + int methodCount() const; + int enumeratorCount() const; + int propertyCount() const; + int classInfoCount() const; + + int indexOfConstructor(const char *constructor) const; + int indexOfMethod(const char *method) const; + int indexOfSignal(const char *signal) const; + int indexOfSlot(const char *slot) const; + int indexOfEnumerator(const char *name) const; + int indexOfProperty(const char *name) const; + int indexOfClassInfo(const char *name) const; + + QMetaMethod constructor(int index) const; + QMetaMethod method(int index) const; + QMetaEnum enumerator(int index) const; + QMetaProperty property(int index) const; + QMetaClassInfo classInfo(int index) const; + QMetaProperty userProperty() const; + + static bool checkConnectArgs(const char *signal, const char *method); + static QByteArray normalizedSignature(const char *method); + static QByteArray normalizedType(const char *type); + + // internal index-based connect + static bool connect(const QObject *sender, int signal_index, + const QObject *receiver, int method_index, + int type = 0, int *types = 0); + // internal index-based disconnect + static bool disconnect(const QObject *sender, int signal_index, + const QObject *receiver, int method_index); + // internal slot-name based connect + static void connectSlotsByName(QObject *o); + + // internal index-based signal activation + static void activate(QObject *sender, int signal_index, void **argv); + static void activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv); + static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv); + static void activate(QObject *sender, const QMetaObject *, int from_local_signal_index, int to_local_signal_index, void **argv); + // internal guarded pointers + static void addGuard(QObject **ptr); + static void removeGuard(QObject **ptr); + static void changeGuard(QObject **ptr, QObject *o); + + static bool invokeMethod(QObject *obj, const char *member, + Qt::ConnectionType, + QGenericReturnArgument ret, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()); + + static inline bool invokeMethod(QObject *obj, const char *member, + QGenericReturnArgument ret, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) + { + return invokeMethod(obj, member, Qt::AutoConnection, ret, val0, val1, val2, val3, + val4, val5, val6, val7, val8, val9); + } + + static inline bool invokeMethod(QObject *obj, const char *member, + Qt::ConnectionType type, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) + { + return invokeMethod(obj, member, type, QGenericReturnArgument(), val0, val1, val2, + val3, val4, val5, val6, val7, val8, val9); + } + + static inline bool invokeMethod(QObject *obj, const char *member, + QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) + { + return invokeMethod(obj, member, Qt::AutoConnection, QGenericReturnArgument(), val0, + val1, val2, val3, val4, val5, val6, val7, val8, val9); + } + + QObject *newInstance(QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) const; + + enum Call { + InvokeMetaMethod, + ReadProperty, + WriteProperty, + ResetProperty, + QueryPropertyDesignable, + QueryPropertyScriptable, + QueryPropertyStored, + QueryPropertyEditable, + QueryPropertyUser, + CreateInstance + }; + + int static_metacall(Call, int, void **) const; + +#ifdef QT3_SUPPORT + QT3_SUPPORT const char *superClassName() const; +#endif + + struct { // private data + const QMetaObject *superdata; + const char *stringdata; + const uint *data; + const void *extradata; + } d; +}; + +struct QMetaObjectExtraData +{ + const QMetaObject **objects; + int (*static_metacall)(QMetaObject::Call, int, void **); +}; + +inline const char *QMetaObject::className() const +{ return d.stringdata; } + +inline const QMetaObject *QMetaObject::superClass() const +{ return d.superdata; } + +#ifdef QT3_SUPPORT +inline const char *QMetaObject::superClassName() const +{ return d.superdata ? d.superdata->className() : 0; } +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QOBJECTDEFS_H diff --git a/src/corelib/kernel/qpointer.cpp b/src/corelib/kernel/qpointer.cpp new file mode 100644 index 0000000..99a8e4b --- /dev/null +++ b/src/corelib/kernel/qpointer.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QPointer + \brief The QPointer class is a template class that provides guarded pointers to QObjects. + + \ingroup objectmodel + \mainclass + + A guarded pointer, QPointer<T>, behaves like a normal C++ + pointer \c{T *}, except that it is automatically set to 0 when the + referenced object is destroyed (unlike normal C++ pointers, which + become "dangling pointers" in such cases). \c T must be a + subclass of QObject. + + Guarded pointers are useful whenever you need to store a pointer + to a QObject that is owned by someone else, and therefore might be + destroyed while you still hold a reference to it. You can safely + test the pointer for validity. + + Qt also provides QSharedPointer, an implementation of a reference-counted + shared pointer object, which can be used to maintain a collection of + references to an individual pointer. + + Example: + + \snippet doc/src/snippets/pointer/pointer.cpp 0 + \dots + \snippet doc/src/snippets/pointer/pointer.cpp 1 + \snippet doc/src/snippets/pointer/pointer.cpp 2 + + If the QLabel is deleted in the meantime, the \c label variable + will hold 0 instead of an invalid address, and the last line will + never be executed. + + The functions and operators available with a QPointer are the + same as those available with a normal unguarded pointer, except + the pointer arithmetic operators (\c{+}, \c{-}, \c{++}, and + \c{--}), which are normally used only with arrays of objects. + + Use QPointers like normal pointers and you will not need to read + this class documentation. + + For creating guarded pointers, you can construct or assign to them + from a T* or from another guarded pointer of the same type. You + can compare them with each other using operator==() and + operator!=(), or test for 0 with isNull(). You can dereference + them using either the \c *x or the \c x->member notation. + + A guarded pointer will automatically cast to a \c T *, so you can + freely mix guarded and unguarded pointers. This means that if you + have a QPointer<QWidget>, you can pass it to a function that + requires a QWidget *. For this reason, it is of little value to + declare functions to take a QPointer as a parameter; just use + normal pointers. Use a QPointer when you are storing a pointer + over time. + + Note that class \c T must inherit QObject, or a compilation or + link error will result. + + \sa QSharedPointer, QObject, QObjectCleanupHandler +*/ + +/*! + \fn QPointer::QPointer() + + Constructs a 0 guarded pointer. + + \sa isNull() +*/ + +/*! + \fn QPointer::QPointer(T* p) + + Constructs a guarded pointer that points to same object that \a p + points to. +*/ + +/*! + \fn QPointer::QPointer(const QPointer<T> &p) + + Copies one guarded pointer from another. The constructed guarded + pointer points to the same object that \a p points to (which may + be 0). +*/ + +/*! + \fn QPointer::~QPointer() + + Destroys the guarded pointer. Just like a normal pointer, + destroying a guarded pointer does \e not destroy the object being + pointed to. +*/ + +/*! + \fn QPointer<T>& QPointer::operator=(const QPointer<T> &p) + + Assignment operator. This guarded pointer will now point to the + same object that \a p points to. +*/ + +/*! + \fn QPointer<T> & QPointer::operator=(T* p) + + Assignment operator. This guarded pointer will now point to the + same object that \a p points to. +*/ + +/*! + \fn T* QPointer::data() const + \since 4.4 + + Returns the pointer to the object being guarded. +*/ + +/*! + \fn bool QPointer::isNull() const + + Returns \c true if the referenced object has been destroyed or if + there is no referenced object; otherwise returns false. +*/ + +/*! + \fn T* QPointer::operator->() const + + Overloaded arrow operator; implements pointer semantics. Just use + this operator as you would with a normal C++ pointer. +*/ + +/*! + \fn T& QPointer::operator*() const + + Dereference operator; implements pointer semantics. Just use this + operator as you would with a normal C++ pointer. +*/ + +/*! + \fn QPointer::operator T*() const + + Cast operator; implements pointer semantics. Because of this + function you can pass a QPointer\<T\> to a function where a T* + is required. +*/ + +/*! + \fn bool operator==(const T *o, const QPointer<T> &p) + + Equality operator. Returns true if \a o and the guarded + pointer \a p are pointing to the same object, otherwise + returns false. + +*/ +/*! + \fn bool operator==(const QPointer<T> &p, const T *o) + + Equality operator. Returns true if \a o and the guarded + pointer \a p are pointing to the same object, otherwise + returns false. + +*/ +/*! + \fn bool operator==(T *o, const QPointer<T> &p) + + Equality operator. Returns true if \a o and the guarded + pointer \a p are pointing to the same object, otherwise + returns false. + +*/ +/*! + \fn bool operator==(const QPointer<T> &p, T *o) + + Equality operator. Returns true if \a o and the guarded + pointer \a p are pointing to the same object, otherwise + returns false. + +*/ +/*! + \fn bool operator==(const QPointer<T> &p1, const QPointer<T> &p2) + + Equality operator. Returns true if the guarded pointers \a p1 and \a p2 + are pointing to the same object, otherwise + returns false. + +*/ + + +/*! + \fn bool operator!=(const T *o, const QPointer<T> &p) + + Inequality operator. Returns true if \a o and the guarded + pointer \a p are not pointing to the same object, otherwise + returns false. +*/ +/*! + \fn bool operator!=(const QPointer<T> &p, const T *o) + + Inequality operator. Returns true if \a o and the guarded + pointer \a p are not pointing to the same object, otherwise + returns false. +*/ +/*! + \fn bool operator!=(T *o, const QPointer<T> &p) + + Inequality operator. Returns true if \a o and the guarded + pointer \a p are not pointing to the same object, otherwise + returns false. +*/ +/*! + \fn bool operator!=(const QPointer<T> &p, T *o) + + Inequality operator. Returns true if \a o and the guarded + pointer \a p are not pointing to the same object, otherwise + returns false. +*/ +/*! + \fn bool operator!=(const QPointer<T> &p1, const QPointer<T> &p2) + + Inequality operator. Returns true if the guarded pointers \a p1 and + \a p2 are not pointing to the same object, otherwise + returns false. +*/ diff --git a/src/corelib/kernel/qpointer.h b/src/corelib/kernel/qpointer.h new file mode 100644 index 0000000..ec4a623 --- /dev/null +++ b/src/corelib/kernel/qpointer.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPOINTER_H +#define QPOINTER_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +template <class T> +class QPointer +{ + QObject *o; +public: + inline QPointer() : o(0) {} + inline QPointer(T *p) : o(p) + { QMetaObject::addGuard(&o); } + inline QPointer(const QPointer<T> &p) : o(p.o) + { QMetaObject::addGuard(&o); } + inline ~QPointer() + { QMetaObject::removeGuard(&o); } + inline QPointer<T> &operator=(const QPointer<T> &p) + { if (this != &p) QMetaObject::changeGuard(&o, p.o); return *this; } + inline QPointer<T> &operator=(T* p) + { if (o != p) QMetaObject::changeGuard(&o, p); return *this; } + + inline bool isNull() const + { return !o; } + + inline T* operator->() const + { return static_cast<T*>(const_cast<QObject*>(o)); } + inline T& operator*() const + { return *static_cast<T*>(const_cast<QObject*>(o)); } + inline operator T*() const + { return static_cast<T*>(const_cast<QObject*>(o)); } + inline T* data() const + { return static_cast<T*>(const_cast<QObject*>(o)); } +}; + + +#if (!defined(Q_CC_SUN) || (__SUNPRO_CC >= 0x580)) // ambiguity between const T * and T * + +template <class T> +inline bool operator==(const T *o, const QPointer<T> &p) +{ return o == p.operator->(); } + +template<class T> +inline bool operator==(const QPointer<T> &p, const T *o) +{ return p.operator->() == o; } + +#else + +template<class T> +inline bool operator==(const void *o, const QPointer<T> &p) +{ return o == p.operator->(); } + +template<class T> +inline bool operator==(const QPointer<T> &p, const void *o) +{ return p.operator->() == o; } + +#endif + +template <class T> +inline bool operator==(T *o, const QPointer<T> &p) +{ return o == p.operator->(); } + +template<class T> +inline bool operator==(const QPointer<T> &p, T *o) +{ return p.operator->() == o; } + +template<class T> +inline bool operator==(const QPointer<T> &p1, const QPointer<T> &p2) +{ return p1.operator->() == p2.operator->(); } + + +#if (!defined(Q_CC_SUN) || (__SUNPRO_CC >= 0x580)) // ambiguity between const T * and T * + +template <class T> +inline bool operator!=(const T *o, const QPointer<T> &p) +{ return o != p.operator->(); } + +template<class T> +inline bool operator!= (const QPointer<T> &p, const T *o) +{ return p.operator->() != o; } + +#else + +template<class T> +inline bool operator!= (const void *o, const QPointer<T> &p) +{ return o != p.operator->(); } + +template<class T> +inline bool operator!= (const QPointer<T> &p, const void *o) +{ return p.operator->() != o; } + +#endif + +template <class T> +inline bool operator!=(T *o, const QPointer<T> &p) +{ return o != p.operator->(); } + +template<class T> +inline bool operator!= (const QPointer<T> &p, T *o) +{ return p.operator->() != o; } + +template<class T> +inline bool operator!= (const QPointer<T> &p1, const QPointer<T> &p2) +{ return p1.operator->() != p2.operator->() ; } + +// Make MSVC < 1400 (2005) handle "if (NULL == p)" syntax +#if defined(Q_CC_MSVC) && (_MSC_VER < 1400) +template<class T> +inline bool operator== (int i, const QPointer<T> &p) +{ Q_ASSERT(i == 0); return !i && p.isNull(); } + +template<class T> +inline bool operator!= (int i, const QPointer<T> &p) +{ Q_ASSERT(i == 0); return !i && !p.isNull(); } +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPOINTER_H diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp new file mode 100644 index 0000000..9853079 --- /dev/null +++ b/src/corelib/kernel/qsharedmemory.cpp @@ -0,0 +1,541 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsharedmemory.h" +#include "qsharedmemory_p.h" +#include "qsystemsemaphore.h" +#include <qdir.h> +#include <qcryptographichash.h> + +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +#if !(defined(QT_NO_SHAREDMEMORY) && defined(QT_NO_SYSTEMSEMAPHORE)) +/*! + \internal + + Generate a string from the key which can be any unicode string into + the subset that the win/unix kernel allows. + + On Unix this will be a file name + */ +QString +QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, + const QString &prefix) +{ + if (key.isEmpty()) + return QString(); + + QString result = prefix; + + QString part1 = key; + part1.replace(QRegExp(QLatin1String("[^A-Za-z]")), QString()); + result.append(part1); + + QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex(); + result.append(QLatin1String(hex)); + +#ifdef Q_OS_WIN + return result; +#else + return QDir::tempPath() + QLatin1Char('/') + result; +#endif +} +#endif // QT_NO_SHAREDMEMORY && QT_NO_SHAREDMEMORY + +#ifndef QT_NO_SHAREDMEMORY + +/*! + \class QSharedMemory + \ingroup ipc + \since 4.4 + + \brief The QSharedMemory class provides access to a shared memory segment. + + QSharedMemory provides access to a shared memory segment by multiple + threads and processes. It also provides a way for a single thread or + process to lock the memory for exclusive access. + + When using this class, be aware of the following platform + differences: + + \list + + \o Windows: QSharedMemory does not "own" the shared memory segment. + When all threads or processes that have an instance of QSharedMemory + attached to a particular shared memory segment have either destroyed + their instance of QSharedMemory or exited, the Windows kernel + releases the shared memory segment automatically. + + \o Unix: QSharedMemory "owns" the shared memory segment. When the + last thread or process that has an instance of QSharedMemory + attached to a particular shared memory segment detaches from the + segment by destroying its instance of QSharedMemory, the Unix kernel + release the shared memory segment. But if that last thread or + process crashes without running the QSharedMemory destructor, the + shared memory segment survives the crash. + + \o HP-UX: Only one attach to a shared memory segment is allowed per + process. This means that QSharedMemory should not be used across + multiple threads in the same process in HP-UX. + + \endlist + + Remember to lock the shared memory with lock() before reading from + or writing to the shared memory, and remember to release the lock + with unlock() after you are done. + + Unlike QtSharedMemory, QSharedMemory automatically destroys the + shared memory segment when the last instance of QSharedMemory is + detached from the segment, and no references to the segment + remain. Do not mix using QtSharedMemory and QSharedMemory. Port + everything to QSharedMemory. + */ + +/*! + \overload QSharedMemory() + + Constructs a shared memory object with the given \a parent. The + shared memory object's key is not set by the constructor, so the + shared memory object does not have an underlying shared memory + segment attached. The key must be set with setKey() before create() + or attach() can be used. + + \sa setKey() + */ +QSharedMemory::QSharedMemory(QObject *parent) + : QObject(*new QSharedMemoryPrivate, parent) +{ +} + +/*! + Constructs a shared memory object with the given \a parent and with + its key set to \a key. Because its key is set, its create() and + attach() functions can be called. + + \sa setKey(), create(), attach() + */ +QSharedMemory::QSharedMemory(const QString &key, QObject *parent) + : QObject(*new QSharedMemoryPrivate, parent) +{ + setKey(key); +} + +/*! + The destructor clears the key, which forces the shared memory object + to \l {detach()} {detach} from its underlying shared memory + segment. If this shared memory object is the last one connected to + the shared memory segment, the detach() operation destroys the + shared memory segment. + + \sa detach() isAttached() + */ +QSharedMemory::~QSharedMemory() +{ + setKey(QString()); +} + +/*! + Sets a new \a key for this shared memory object. If \a key and the + current key are the same, the function returns without doing + anything. If the shared memory object is attached to an underlying + shared memory segment, it will \l {detach()} {detach} from it before + setting the new key. This function does not do an attach(). + + \sa key() isAttached() + */ +void QSharedMemory::setKey(const QString &key) +{ + Q_D(QSharedMemory); + if (key == d->key) + return; + + if (isAttached()) + detach(); + d->cleanHandle(); + d->key = key; +} + +bool QSharedMemoryPrivate::initKey() +{ + if (!cleanHandle()) + return false; +#ifndef QT_NO_SYSTEMSEMAPHORE + systemSemaphore.setKey(QString(), 1); + systemSemaphore.setKey(key, 1); + if (systemSemaphore.error() != QSystemSemaphore::NoError) { + QString function = QLatin1String("QSharedMemoryPrivate::initKey"); + errorString = QSharedMemory::tr("%1: unable to set key on lock").arg(function); + switch(systemSemaphore.error()) { + case QSystemSemaphore::PermissionDenied: + error = QSharedMemory::PermissionDenied; + break; + case QSystemSemaphore::KeyError: + error = QSharedMemory::KeyError; + break; + case QSystemSemaphore::AlreadyExists: + error = QSharedMemory::AlreadyExists; + break; + case QSystemSemaphore::NotFound: + error = QSharedMemory::NotFound; + break; + case QSystemSemaphore::OutOfResources: + error = QSharedMemory::OutOfResources; + break; + case QSystemSemaphore::UnknownError: + default: + error = QSharedMemory::UnknownError; + break; + } + return false; + } +#endif + errorString = QString(); + error = QSharedMemory::NoError; + return true; +} + +/*! + Returns the key assigned to this shared memory. The key is the + identifier used by the operating system to identify the shared + memory segment. When QSharedMemory is used for interprocess + communication, the key is how each process attaches to the shared + memory segment through which the IPC occurs. + + \sa setKey() + */ +QString QSharedMemory::key() const +{ + Q_D(const QSharedMemory); + return d->key; +} + +/*! + Creates a shared memory segment of \a size bytes with the key passed + to the constructor or set with setKey(), attaches to the new shared + memory segment with the given access \a mode, and returns \tt true. + If a shared memory segment identified by the key already exists, the + attach operation is not performed, and \tt false is returned. When + the return value is \tt false, call error() to determine which error + occurred. + + \sa error() + */ +bool QSharedMemory::create(int size, AccessMode mode) +{ + Q_D(QSharedMemory); + + if (!d->initKey()) + return false; + +#ifndef QT_NO_SYSTEMSEMAPHORE +#ifndef Q_OS_WIN + // Take ownership and force set initialValue because the semaphore + // might have already existed from a previous crash. + d->systemSemaphore.setKey(d->key, 1, QSystemSemaphore::Create); +#endif +#endif + + QString function = QLatin1String("QSharedMemory::create"); +#ifndef QT_NO_SYSTEMSEMAPHORE + QSharedMemoryLocker lock(this); + if (!d->tryLocker(&lock, function)) + return false; +#endif + + if (size <= 0) { + d->error = QSharedMemory::InvalidSize; + d->errorString = + QSharedMemory::tr("%1: create size is less then 0").arg(function); + return false; + } + + if (!d->create(size)) + return false; + + return d->attach(mode); +} + +/*! + Returns the size of the attached shared memory segment. If no shared + memory segment is attached, 0 is returned. + + \sa create() attach() + */ +int QSharedMemory::size() const +{ + Q_D(const QSharedMemory); + return d->size; +} + +/*! + \enum QSharedMemory::AccessMode + + \value ReadOnly The shared memory segment is read-only. Writing to + the shared memory segment is not allowed. An attempt to write to a + shared memory segment created with ReadOnly causes the program to + abort. + + \value ReadWrite Reading and writing the shared memory segment are + both allowed. +*/ + +/*! + Attempts to attach the process to the shared memory segment + identified by the key that was passed to the constructor or to a + call to setKey(). The access \a mode is \l {QSharedMemory::} + {ReadWrite} by default. It can also be \l {QSharedMemory::} + {ReadOnly}. Returns true if the attach operation is successful. If + false is returned, call error() to determine which error occurred. + After attaching the shared memory segment, a pointer to the shared + memory can be obtained by calling data(). + + \sa isAttached(), detach(), create() + */ +bool QSharedMemory::attach(AccessMode mode) +{ + Q_D(QSharedMemory); + + if (isAttached() || !d->initKey()) + return false; +#ifndef QT_NO_SYSTEMSEMAPHORE + QSharedMemoryLocker lock(this); + if (!d->tryLocker(&lock, QLatin1String("QSharedMemory::attach"))) + return false; +#endif + + if (isAttached() || !d->handle()) + return false; + + return d->attach(mode); +} + +/*! + Returns true if this process is attached to the shared memory + segment. + + \sa attach(), detach() + */ +bool QSharedMemory::isAttached() const +{ + Q_D(const QSharedMemory); + return (0 != d->memory); +} + +/*! + Detaches the process from the shared memory segment. If this was the + last process attached to the shared memory segment, then the shared + memory segment is released by the system, i.e., the contents are + destroyed. The function returns true if it detaches the shared + memory segment. If it returns false, it usually means the segment + either isn't attached, or it is locked by another process. + + \sa attach(), isAttached() + */ +bool QSharedMemory::detach() +{ + Q_D(QSharedMemory); + if (!isAttached()) + return false; + +#ifndef QT_NO_SYSTEMSEMAPHORE + QSharedMemoryLocker lock(this); + if (!d->tryLocker(&lock, QLatin1String("QSharedMemory::detach"))) + return false; +#endif + + if (d->detach()) { + d->size = 0; + return true; + } + return false; +} + +/*! + Returns a pointer to the contents of the shared memory segment, if + one is attached. Otherwise it returns null. Remember to lock the + shared memory with lock() before reading from or writing to the + shared memory, and remember to release the lock with unlock() after + you are done. + + \sa attach() + */ +void *QSharedMemory::data() +{ + Q_D(QSharedMemory); + return d->memory; +} + +/*! + Returns a const pointer to the contents of the shared memory + segment, if one is attached. Otherwise it returns null. Remember to + lock the shared memory with lock() before reading from or writing to + the shared memory, and remember to release the lock with unlock() + after you are done. + + \sa attach() create() + */ +const void* QSharedMemory::constData() const +{ + Q_D(const QSharedMemory); + return d->memory; +} + +/*! + \overload data() + */ +const void *QSharedMemory::data() const +{ + Q_D(const QSharedMemory); + return d->memory; +} + +#ifndef QT_NO_SYSTEMSEMAPHORE +/*! + This is a semaphore that locks the shared memory segment for access + by this process and returns true. If another process has locked the + segment, this function blocks until the lock is released. Then it + acquires the lock and returns true. If this function returns false, + it means either that you have ignored a false return from create() + or attach(), or that QSystemSemaphore::acquire() failed due to an + unknown system error. + + \sa unlock(), data(), QSystemSemaphore::acquire() + */ +bool QSharedMemory::lock() +{ + Q_D(QSharedMemory); + if (d->lockedByMe) { + qWarning("QSharedMemory::lock: already locked"); + return true; + } + if (d->systemSemaphore.acquire()) { + d->lockedByMe = true; + return true; + } + QString function = QLatin1String("QSharedMemory::lock"); + d->errorString = QSharedMemory::tr("%1: unable to lock").arg(function); + d->error = QSharedMemory::LockError; + return false; +} + +/*! + Releases the lock on the shared memory segment and returns true, if + the lock is currently held by this process. If the segment is not + locked, or if the lock is held by another process, nothing happens + and false is returned. + + \sa lock() + */ +bool QSharedMemory::unlock() +{ + Q_D(QSharedMemory); + if (!d->lockedByMe) + return false; + d->lockedByMe = false; + if (d->systemSemaphore.release()) + return true; + QString function = QLatin1String("QSharedMemory::unlock"); + d->errorString = QSharedMemory::tr("%1: unable to unlock").arg(function); + d->error = QSharedMemory::LockError; + return false; +} +#endif // QT_NO_SYSTEMSEMAPHORE + +/*! + \enum QSharedMemory::SharedMemoryError + + \value NoError No error occurred. + + \value PermissionDenied The operation failed because the caller + didn't have the required permissions. + + \value InvalidSize A create operation failed because the requested + size was invalid. + + \value KeyError The operation failed because of an invalid key. + + \value AlreadyExists A create() operation failed because a shared + memory segment with the specified key already existed. + + \value NotFound An attach() failed because a shared memory segment + with the specified key could not be found. + + \value LockError The attempt to lock() the shared memory segment + failed because create() or attach() failed and returned false, or + because a system error occurred in QSystemSemaphore::acquire(). + + \value OutOfResources A create() operation failed because there was + not enough memory available to fill the request. + + \value UnknownError Something else happened and it was bad. +*/ + +/*! + Returns a value indicating whether an error occurred, and, if so, + which error it was. + + \sa errorString() + */ +QSharedMemory::SharedMemoryError QSharedMemory::error() const +{ + Q_D(const QSharedMemory); + return d->error; +} + +/*! + Returns a text description of the last error that occurred. If + error() returns an \l {QSharedMemory::SharedMemoryError} {error + value}, call this function to get a text string that describes the + error. + + \sa error() + */ +QString QSharedMemory::errorString() const +{ + Q_D(const QSharedMemory); + return d->errorString; +} + +#endif // QT_NO_SHAREDMEMORY + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qsharedmemory.h b/src/corelib/kernel/qsharedmemory.h new file mode 100644 index 0000000..481a815 --- /dev/null +++ b/src/corelib/kernel/qsharedmemory.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSHAREDMEMORY_H +#define QSHAREDMEMORY_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_SHAREDMEMORY + +class QSharedMemoryPrivate; + +class Q_CORE_EXPORT QSharedMemory : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSharedMemory) + +public: + enum AccessMode + { + ReadOnly, + ReadWrite + }; + + enum SharedMemoryError + { + NoError, + PermissionDenied, + InvalidSize, + KeyError, + AlreadyExists, + NotFound, + LockError, + OutOfResources, + UnknownError + }; + + QSharedMemory(QObject *parent = 0); + QSharedMemory(const QString &key, QObject *parent = 0); + ~QSharedMemory(); + + void setKey(const QString &key); + QString key() const; + + bool create(int size, AccessMode mode = ReadWrite); + int size() const; + + bool attach(AccessMode mode = ReadWrite); + bool isAttached() const; + bool detach(); + + void *data(); + const void* constData() const; + const void *data() const; + +#ifndef QT_NO_SYSTEMSEMAPHORE + bool lock(); + bool unlock(); +#endif + + SharedMemoryError error() const; + QString errorString() const; + +private: + Q_DISABLE_COPY(QSharedMemory) +}; + +#endif // QT_NO_SHAREDMEMORY + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSHAREDMEMORY_H + diff --git a/src/corelib/kernel/qsharedmemory_p.h b/src/corelib/kernel/qsharedmemory_p.h new file mode 100644 index 0000000..08f0321 --- /dev/null +++ b/src/corelib/kernel/qsharedmemory_p.h @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSHAREDMEMORY_P_H +#define QSHAREDMEMORY_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. +// + +#include "qsharedmemory.h" + +#ifdef QT_NO_SHAREDMEMORY +# ifndef QT_NO_SYSTEMSEMAPHORE +namespace QSharedMemoryPrivate +{ + int createUnixKeyFile(const QString &fileName); + QString makePlatformSafeKey(const QString &key, + const QString &prefix = QLatin1String("qipc_sharedmemory_")); +} +#endif +#else + +#include "qsystemsemaphore.h" +#include "private/qobject_p.h" + +#ifdef Q_OS_WIN +#include <qt_windows.h> +#else +#include <sys/sem.h> +#endif + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SYSTEMSEMAPHORE +/*! + Helper class + */ +class QSharedMemoryLocker +{ + +public: + inline QSharedMemoryLocker(QSharedMemory *sharedMemory) : q_sm(sharedMemory) + { + Q_ASSERT(q_sm); + } + + inline ~QSharedMemoryLocker() + { + if (q_sm) + q_sm->unlock(); + } + + inline bool lock() + { + if (q_sm && q_sm->lock()) + return true; + q_sm = 0; + return false; + } + +private: + QSharedMemory *q_sm; +}; +#endif // QT_NO_SYSTEMSEMAPHORE + +class Q_AUTOTEST_EXPORT QSharedMemoryPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QSharedMemory) + +public: + QSharedMemoryPrivate(); + + void *memory; + int size; + QString key; + QSharedMemory::SharedMemoryError error; + QString errorString; +#ifndef QT_NO_SYSTEMSEMAPHORE + QSystemSemaphore systemSemaphore; + bool lockedByMe; +#endif + + static int createUnixKeyFile(const QString &fileName); + static QString makePlatformSafeKey(const QString &key, + const QString &prefix = QLatin1String("qipc_sharedmemory_")); +#ifdef Q_OS_WIN + HANDLE handle(); +#else + key_t handle(); +#endif + bool initKey(); + bool cleanHandle(); + bool create(int size); + bool attach(QSharedMemory::AccessMode mode); + bool detach(); + + void setErrorString(const QString &function); + +#ifndef QT_NO_SYSTEMSEMAPHORE + bool tryLocker(QSharedMemoryLocker *locker, const QString function) { + if (!locker->lock()) { + errorString = QSharedMemory::tr("%1: unable to lock").arg(function); + error = QSharedMemory::LockError; + return false; + } + return true; + } +#endif // QT_NO_SYSTEMSEMAPHORE + +private: +#ifdef Q_OS_WIN + HANDLE hand; +#else + key_t unix_key; +#endif +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SHAREDMEMORY + +#endif // QSHAREDMEMORY_P_H + diff --git a/src/corelib/kernel/qsharedmemory_unix.cpp b/src/corelib/kernel/qsharedmemory_unix.cpp new file mode 100644 index 0000000..487c653 --- /dev/null +++ b/src/corelib/kernel/qsharedmemory_unix.cpp @@ -0,0 +1,305 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" + +#include "qsharedmemory.h" +#include "qsharedmemory_p.h" +#include "qsystemsemaphore.h" +#include <qdir.h> +#include <qdebug.h> + +#include <errno.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SHAREDMEMORY + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +QSharedMemoryPrivate::QSharedMemoryPrivate() + : QObjectPrivate(), memory(0), size(0), error(QSharedMemory::NoError), +#ifndef QT_NO_SYSTEMSEMAPHORE + systemSemaphore(QString()), lockedByMe(false), +#endif + unix_key(0) +{ +} + +void QSharedMemoryPrivate::setErrorString(const QString &function) +{ + // EINVAL is handled in functions so they can give better error strings + switch (errno) { + case EACCES: + errorString = QSharedMemory::tr("%1: permission denied").arg(function); + error = QSharedMemory::PermissionDenied; + break; + case EEXIST: + errorString = QSharedMemory::tr("%1: already exists").arg(function); + error = QSharedMemory::AlreadyExists; + break; + case ENOENT: + errorString = QSharedMemory::tr("%1: doesn't exists").arg(function); + error = QSharedMemory::NotFound; + break; + case EMFILE: + case ENOMEM: + case ENOSPC: + errorString = QSharedMemory::tr("%1: out of resources").arg(function); + error = QSharedMemory::OutOfResources; + break; + default: + errorString = QSharedMemory::tr("%1: unknown error %2").arg(function).arg(errno); + error = QSharedMemory::UnknownError; +#if defined QSHAREDMEMORY_DEBUG + qDebug() << errorString << "key" << key << "errno" << errno << EINVAL; +#endif + } +} + +/*! + \internal + + If not already made create the handle used for accessing the shared memory. +*/ +key_t QSharedMemoryPrivate::handle() +{ + // already made + if (unix_key) + return unix_key; + + // don't allow making handles on empty keys + if (key.isEmpty()) { + errorString = QSharedMemory::tr("%1: key is empty").arg(QLatin1String("QSharedMemory::handle:")); + error = QSharedMemory::KeyError; + return 0; + } + + // ftok requires that an actual file exists somewhere + QString fileName = makePlatformSafeKey(key); + if (!QFile::exists(fileName)) { + errorString = QSharedMemory::tr("%1: unix key file doesn't exists").arg(QLatin1String("QSharedMemory::handle:")); + error = QSharedMemory::NotFound; + return 0; + } + + unix_key = ftok(QFile::encodeName(fileName).constData(), 'Q'); + if (-1 == unix_key) { + errorString = QSharedMemory::tr("%1: ftok failed").arg(QLatin1String("QSharedMemory::handle:")); + error = QSharedMemory::KeyError; + unix_key = 0; + } + return unix_key; +} + +#endif // QT_NO_SHAREDMEMORY + +#if !(defined(QT_NO_SHAREDMEMORY) && defined(QT_NO_SYSTEMSEMAPHORE)) +/*! + \internal + Creates the unix file if needed. + returns true if the unix file was created. + + -1 error + 0 already existed + 1 created + */ +int QSharedMemoryPrivate::createUnixKeyFile(const QString &fileName) +{ + if (QFile::exists(fileName)) + return 0; + + int fd = open(QFile::encodeName(fileName).constData(), + O_EXCL | O_CREAT | O_RDWR, 0640); + if (-1 == fd) { + if (errno == EEXIST) + return 0; + return -1; + } else { + close(fd); + } + return 1; +} +#endif // QT_NO_SHAREDMEMORY && QT_NO_SYSTEMSEMAPHORE + +#ifndef QT_NO_SHAREDMEMORY + +bool QSharedMemoryPrivate::cleanHandle() +{ + unix_key = 0; + return true; +} + +bool QSharedMemoryPrivate::create(int size) +{ + // build file if needed + bool createdFile = false; + int built = createUnixKeyFile(makePlatformSafeKey(key)); + if (built == -1) { + errorString = QSharedMemory::tr("%1: unable to make key").arg(QLatin1String("QSharedMemory::handle:")); + error = QSharedMemory::KeyError; + return false; + } + if (built == 1) { + createdFile = true; + } + + // get handle + if (!handle()) { + if (createdFile) + QFile::remove(makePlatformSafeKey(key)); + return false; + } + + // create + if (-1 == shmget(handle(), size, 0666 | IPC_CREAT | IPC_EXCL)) { + QString function = QLatin1String("QSharedMemory::create"); + switch (errno) { + case EINVAL: + errorString = QSharedMemory::tr("%1: system-imposed size restrictions").arg(QLatin1String("QSharedMemory::handle")); + error = QSharedMemory::InvalidSize; + break; + default: + setErrorString(function); + } + if (createdFile && error != QSharedMemory::AlreadyExists) + QFile::remove(makePlatformSafeKey(key)); + return false; + } + + return true; +} + +bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) +{ + // grab the shared memory segment id + if (!handle()) + return false; + + int id = shmget(handle(), 0, (mode == QSharedMemory::ReadOnly ? 0444 : 0660)); + if (-1 == id) { + setErrorString(QLatin1String("QSharedMemory::attach (shmget)")); + return false; + } + + // grab the memory + memory = shmat(id, 0, (mode == QSharedMemory::ReadOnly ? SHM_RDONLY : 0)); + if ((void*) - 1 == memory) { + memory = 0; + setErrorString(QLatin1String("QSharedMemory::attach (shmat)")); + return false; + } + + // grab the size + shmid_ds shmid_ds; + if (!shmctl(id, IPC_STAT, &shmid_ds)) { + size = (int)shmid_ds.shm_segsz; + } else { + setErrorString(QLatin1String("QSharedMemory::attach (shmctl)")); + return false; + } + + return true; +} + +bool QSharedMemoryPrivate::detach() +{ + // detach from the memory segment + if (-1 == shmdt(memory)) { + QString function = QLatin1String("QSharedMemory::detach"); + switch (errno) { + case EINVAL: + errorString = QSharedMemory::tr("%1: not attached").arg(function); + error = QSharedMemory::NotFound; + break; + default: + setErrorString(function); + } + return false; + } + memory = 0; + + // Get the number of current attachments + if (!handle()) + return false; + int id = shmget(handle(), 0, 0444); + unix_key = 0; + + struct shmid_ds shmid_ds; + if (0 != shmctl(id, IPC_STAT, &shmid_ds)) { + switch (errno) { + case EINVAL: + return true; + default: + return false; + } + } + // If there are no attachments then remove it. + if (shmid_ds.shm_nattch == 0) { + // mark for removal + struct shmid_ds shmid_ds; + if (-1 == shmctl(id, IPC_RMID, &shmid_ds)) { + setErrorString(QLatin1String("QSharedMemory::remove")); + switch (errno) { + case EINVAL: + return true; + default: + return false; + } + } + + // remove file + if (!QFile::remove(makePlatformSafeKey(key))) + return false; + } + return true; +} + + +QT_END_NAMESPACE + +#endif // QT_NO_SHAREDMEMORY diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp new file mode 100644 index 0000000..b71fbd0 --- /dev/null +++ b/src/corelib/kernel/qsharedmemory_win.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsharedmemory.h" +#include "qsharedmemory_p.h" +#include "qsystemsemaphore.h" +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SHAREDMEMORY + +QSharedMemoryPrivate::QSharedMemoryPrivate() : QObjectPrivate(), + memory(0), size(0), error(QSharedMemory::NoError), + systemSemaphore(QString()), lockedByMe(false), hand(0) +{ +} + +void QSharedMemoryPrivate::setErrorString(const QString &function) +{ + BOOL windowsError = GetLastError(); + if (windowsError == 0) + return; + switch (windowsError) { + case ERROR_ALREADY_EXISTS: + error = QSharedMemory::AlreadyExists; + errorString = QSharedMemory::tr("%1: already exists").arg(function); + break; + case ERROR_FILE_NOT_FOUND: +#ifdef Q_OS_WINCE + // This happens on CE only if no file is present as CreateFileMappingW + // bails out with this error code + case ERROR_INVALID_PARAMETER: +#endif + error = QSharedMemory::NotFound; + errorString = QSharedMemory::tr("%1: doesn't exists").arg(function); + break; + case ERROR_COMMITMENT_LIMIT: + error = QSharedMemory::InvalidSize; + errorString = QSharedMemory::tr("%1: invalid size").arg(function); + break; + case ERROR_NO_SYSTEM_RESOURCES: + case ERROR_NOT_ENOUGH_MEMORY: + error = QSharedMemory::OutOfResources; + errorString = QSharedMemory::tr("%1: out of resources").arg(function); + break; + case ERROR_ACCESS_DENIED: + error = QSharedMemory::PermissionDenied; + errorString = QSharedMemory::tr("%1: permission denied").arg(function); + break; + default: + errorString = QSharedMemory::tr("%1: unknown error %2").arg(function).arg(windowsError); + error = QSharedMemory::UnknownError; +#if defined QSHAREDMEMORY_DEBUG + qDebug() << errorString << "key" << key; +#endif + } +} + +HANDLE QSharedMemoryPrivate::handle() +{ + if (!hand) { + QString function = QLatin1String("QSharedMemory::handle"); + QString safeKey = makePlatformSafeKey(key); + if (safeKey.isEmpty()) { + error = QSharedMemory::KeyError; + errorString = QSharedMemory::tr("%1: unable to make key").arg(function); + return false; + } +#ifndef Q_OS_WINCE + QT_WA({ + hand = OpenFileMappingW(FILE_MAP_ALL_ACCESS, false, (TCHAR*)safeKey.utf16()); + }, { + hand = OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, safeKey.toLocal8Bit().constData()); + }); +#else + // This works for opening a mapping too, but always opens it with read/write access in + // attach as it seems. + hand = CreateFileMappingW(INVALID_HANDLE_VALUE, + 0, PAGE_READWRITE, 0, 0, (TCHAR*)safeKey.utf16()); +#endif + if (!hand) { + setErrorString(function); + return false; + } + } + return hand; +} + +bool QSharedMemoryPrivate::cleanHandle() +{ + if (hand != 0 && !CloseHandle(hand)) { + hand = 0; + return false; + setErrorString(QLatin1String("QSharedMemory::cleanHandle")); + } + hand = 0; + return true; +} + +bool QSharedMemoryPrivate::create(int size) +{ + // Get a windows acceptable key + QString safeKey = makePlatformSafeKey(key); + QString function = QLatin1String("QSharedMemory::create"); + if (safeKey.isEmpty()) { + error = QSharedMemory::KeyError; + errorString = QSharedMemory::tr("%1: key error").arg(function); + return false; + } + + // Create the file mapping. + QT_WA( { + hand = CreateFileMappingW(INVALID_HANDLE_VALUE, + 0, PAGE_READWRITE, 0, size, (TCHAR*)safeKey.utf16()); + }, { + hand = CreateFileMappingA(INVALID_HANDLE_VALUE, + 0, PAGE_READWRITE, 0, size, safeKey.toLocal8Bit().constData()); + } ); + setErrorString(function); + + // hand is valid when it already exists unlike unix so explicitly check + if (error == QSharedMemory::AlreadyExists || !hand) + return false; + + return true; +} + +bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) +{ + // Grab a pointer to the memory block + int permissions = (mode == QSharedMemory::ReadOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS); + memory = (void *)MapViewOfFile(handle(), permissions, 0, 0, 0); + if (0 == memory) { + setErrorString(QLatin1String("QSharedMemory::attach")); + cleanHandle(); + return false; + } + + // Grab the size of the memory we have been given (a multiple of 4K on windows) + MEMORY_BASIC_INFORMATION info; + if (!VirtualQuery(memory, &info, sizeof(info))) { + // Windows doesn't set an error code on this one, + // it should only be a kernel memory error. + error = QSharedMemory::UnknownError; + errorString = QSharedMemory::tr("%1: size query failed").arg(QLatin1String("QSharedMemory::attach: ")); + return false; + } + size = info.RegionSize; + + return true; +} + +bool QSharedMemoryPrivate::detach() +{ + // umap memory + if (!UnmapViewOfFile(memory)) { + setErrorString(QLatin1String("QSharedMemory::detach")); + return false; + } + memory = 0; + + // close handle + return cleanHandle(); +} + +#endif //QT_NO_SHAREDMEMORY + + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qsignalmapper.cpp b/src/corelib/kernel/qsignalmapper.cpp new file mode 100644 index 0000000..23c6ba7 --- /dev/null +++ b/src/corelib/kernel/qsignalmapper.cpp @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsignalmapper.h" +#ifndef QT_NO_SIGNALMAPPER +#include "qhash.h" +#include "qobject_p.h" + +QT_BEGIN_NAMESPACE + +class QSignalMapperPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QSignalMapper) +public: + void _q_senderDestroyed() { + Q_Q(QSignalMapper); + q->removeMappings(q->sender()); + } + QHash<QObject *, int> intHash; + QHash<QObject *, QString> stringHash; + QHash<QObject *, QWidget*> widgetHash; + QHash<QObject *, QObject*> objectHash; + +}; + + +/*! + \class QSignalMapper + \brief The QSignalMapper class bundles signals from identifiable senders. + + \ingroup io + \mainclass + + This class collects a set of parameterless signals, and re-emits + them with integer, string or widget parameters corresponding to + the object that sent the signal. + + The class supports the mapping of particular strings or integers + with particular objects using setMapping(). The objects' signals + can then be connected to the map() slot which will emit the + mapped() signal with the string or integer associated with the + original signalling object. Mappings can be removed later using + removeMappings(). + + Example: Suppose we want to create a custom widget that contains + a group of buttons (like a tool palette). One approach is to + connect each button's \c clicked() signal to its own custom slot; + but in this example we want to connect all the buttons to a + single slot and parameterize the slot by the button that was + clicked. + + Here's the definition of a simple custom widget that has a single + signal, \c clicked(), which is emitted with the text of the button + that was clicked: + + \snippet doc/src/snippets/qsignalmapper/buttonwidget.h 0 + \snippet doc/src/snippets/qsignalmapper/buttonwidget.h 1 + + The only function that we need to implement is the constructor: + + \snippet doc/src/snippets/qsignalmapper/buttonwidget.cpp 0 + \snippet doc/src/snippets/qsignalmapper/buttonwidget.cpp 1 + \snippet doc/src/snippets/qsignalmapper/buttonwidget.cpp 2 + + A list of texts is passed to the constructor. A signal mapper is + constructed and for each text in the list a QPushButton is + created. We connect each button's \c clicked() signal to the + signal mapper's map() slot, and create a mapping in the signal + mapper from each button to the button's text. Finally we connect + the signal mapper's mapped() signal to the custom widget's \c + clicked() signal. When the user clicks a button, the custom + widget will emit a single \c clicked() signal whose argument is + the text of the button the user clicked. + + \sa QObject, QButtonGroup, QActionGroup +*/ + +/*! + Constructs a QSignalMapper with parent \a parent. +*/ +QSignalMapper::QSignalMapper(QObject* parent) + : QObject(*new QSignalMapperPrivate, parent) +{ +} + +#ifdef QT3_SUPPORT +/*! + \overload QSignalMapper() + \obsolete + */ +QSignalMapper::QSignalMapper(QObject *parent, const char *name) + : QObject(*new QSignalMapperPrivate, parent) +{ + setObjectName(QString::fromAscii(name)); +} +#endif + +/*! + Destroys the QSignalMapper. +*/ +QSignalMapper::~QSignalMapper() +{ +} + +/*! + Adds a mapping so that when map() is signalled from the given \a + sender, the signal mapped(\a id) is emitted. + + There may be at most one integer ID for each sender. + + \sa mapping() +*/ +void QSignalMapper::setMapping(QObject *sender, int id) +{ + Q_D(QSignalMapper); + d->intHash.insert(sender, id); + connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed())); +} + +/*! + Adds a mapping so that when map() is signalled from the \a sender, + the signal mapped(\a text ) is emitted. + + There may be at most one text for each sender. +*/ +void QSignalMapper::setMapping(QObject *sender, const QString &text) +{ + Q_D(QSignalMapper); + d->stringHash.insert(sender, text); + connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed())); +} + +/*! + Adds a mapping so that when map() is signalled from the \a sender, + the signal mapped(\a widget ) is emitted. + + There may be at most one widget for each sender. +*/ +void QSignalMapper::setMapping(QObject *sender, QWidget *widget) +{ + Q_D(QSignalMapper); + d->widgetHash.insert(sender, widget); + connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed())); +} + +/*! + Adds a mapping so that when map() is signalled from the \a sender, + the signal mapped(\a object ) is emitted. + + There may be at most one object for each sender. +*/ +void QSignalMapper::setMapping(QObject *sender, QObject *object) +{ + Q_D(QSignalMapper); + d->objectHash.insert(sender, object); + connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed())); +} + +/*! + Returns the sender QObject that is associated with the \a id. + + \sa setMapping() +*/ +QObject *QSignalMapper::mapping(int id) const +{ + Q_D(const QSignalMapper); + return d->intHash.key(id); +} + +/*! + \overload mapping() +*/ +QObject *QSignalMapper::mapping(const QString &id) const +{ + Q_D(const QSignalMapper); + return d->stringHash.key(id); +} + +/*! + \overload mapping() + + Returns the sender QObject that is associated with the \a widget. +*/ +QObject *QSignalMapper::mapping(QWidget *widget) const +{ + Q_D(const QSignalMapper); + return d->widgetHash.key(widget); +} + +/*! + \overload mapping() + + Returns the sender QObject that is associated with the \a object. +*/ +QObject *QSignalMapper::mapping(QObject *object) const +{ + Q_D(const QSignalMapper); + return d->objectHash.key(object); +} + +/*! + Removes all mappings for \a sender. + + This is done automatically when mapped objects are destroyed. +*/ +void QSignalMapper::removeMappings(QObject *sender) +{ + Q_D(QSignalMapper); + + d->intHash.remove(sender); + d->stringHash.remove(sender); + d->widgetHash.remove(sender); + d->objectHash.remove(sender); +} + +/*! + This slot emits signals based on which object sends signals to it. +*/ +void QSignalMapper::map() { map(sender()); } + +/*! + This slot emits signals based on the \a sender object. +*/ +void QSignalMapper::map(QObject *sender) +{ + Q_D(QSignalMapper); + if (d->intHash.contains(sender)) + emit mapped(d->intHash.value(sender)); + if (d->stringHash.contains(sender)) + emit mapped(d->stringHash.value(sender)); + if (d->widgetHash.contains(sender)) + emit mapped(d->widgetHash.value(sender)); + if (d->objectHash.contains(sender)) + emit mapped(d->objectHash.value(sender)); +} + + +/*! + \fn void QSignalMapper::mapped(int i) + + This signal is emitted when map() is signalled from an object that + has an integer mapping set. The object's mapped integer is passed + in \a i. + + \sa setMapping() +*/ + +/*! + \fn void QSignalMapper::mapped(const QString &text) + + This signal is emitted when map() is signalled from an object that + has a string mapping set. The object's mapped string is passed in + \a text. + + \sa setMapping() +*/ + +/*! + \fn void QSignalMapper::mapped(QWidget *widget) + + This signal is emitted when map() is signalled from an object that + has a widget mapping set. The object's mapped widget is passed in + \a widget. + + \sa setMapping() +*/ + +/*! + \fn void QSignalMapper::mapped(QObject *object) + + This signal is emitted when map() is signalled from an object that + has an object mapping set. The object provided by the map is passed in + \a object. + + \sa setMapping() +*/ + +QT_END_NAMESPACE + +#include "moc_qsignalmapper.cpp" + +#endif // QT_NO_SIGNALMAPPER + diff --git a/src/corelib/kernel/qsignalmapper.h b/src/corelib/kernel/qsignalmapper.h new file mode 100644 index 0000000..ab84b56 --- /dev/null +++ b/src/corelib/kernel/qsignalmapper.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIGNALMAPPER_H +#define QSIGNALMAPPER_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_SIGNALMAPPER +class QSignalMapperPrivate; + +class Q_CORE_EXPORT QSignalMapper : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSignalMapper) +public: + explicit QSignalMapper(QObject *parent = 0); + ~QSignalMapper(); + + void setMapping(QObject *sender, int id); + void setMapping(QObject *sender, const QString &text); + void setMapping(QObject *sender, QWidget *widget); + void setMapping(QObject *sender, QObject *object); + void removeMappings(QObject *sender); + + QObject *mapping(int id) const; + QObject *mapping(const QString &text) const; + QObject *mapping(QWidget *widget) const; + QObject *mapping(QObject *object) const; + +Q_SIGNALS: + void mapped(int); + void mapped(const QString &); + void mapped(QWidget *); + void mapped(QObject *); + +public Q_SLOTS: + void map(); + void map(QObject *sender); + +private: + Q_DISABLE_COPY(QSignalMapper) + Q_PRIVATE_SLOT(d_func(), void _q_senderDestroyed()) + +#ifdef QT3_SUPPORT +public: + QT3_SUPPORT_CONSTRUCTOR QSignalMapper(QObject *parent, const char *name); +#endif +}; +#endif // QT_NO_SIGNALMAPPER + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSIGNALMAPPER_H diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp new file mode 100644 index 0000000..0ff9c8e --- /dev/null +++ b/src/corelib/kernel/qsocketnotifier.cpp @@ -0,0 +1,322 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsocketnotifier.h" + +#include "qplatformdefs.h" + +#include "qabstracteventdispatcher.h" +#include "qcoreapplication.h" + +#include "qobject_p.h" +#include <private/qthread_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QSocketNotifier + \brief The QSocketNotifier class provides support for monitoring + activity on a file descriptor. + + \ingroup io + + The QSocketNotifier makes it possible to integrate Qt's event + loop with other event loops based on file descriptors. For + example, the \l{CORBA Framework} uses it to process CORBA + events. File descriptor action is detected in Qt's main event + loop (QCoreApplication::exec()). + + \target write notifiers + + Once you have opened a device using a low-level (usually + platform-specific) API, you can create a socket notifier to + monitor the file descriptor. The socket notifier is enabled by + default, i.e. it emits the activated() signal whenever a socket + event corresponding to its type occurs. Connect the activated() + signal to the slot you want to be called when an event + corresponding to your socket notifier's type occurs. + + There are three types of socket notifiers: read, write, and + exception. The type is described by the \l Type enum, and must be + specified when constructing the socket notifier. After + construction it can be determined using the type() function. Note + that if you need to monitor both reads and writes for the same + file descriptor, you must create two socket notifiers. Note also + that it is not possible to install two socket notifiers of the + same type (\l Read, \l Write, \l Exception) on the same socket. + + The setEnabled() function allows you to disable as well as enable + the socket notifier. It is generally advisable to explicitly + enable or disable the socket notifier, especially for write + notifiers. A disabled notifier ignores socket events (the same + effect as not creating the socket notifier). Use the isEnabled() + function to determine the notifier's current status. + + Finally, you can use the socket() function to retrieve the + socket identifier. Although the class is called QSocketNotifier, + it is normally used for other types of devices than sockets. + QTcpSocket and QUdpSocket provide notification through signals, so + there is normally no need to use a QSocketNotifier on them. + + \section1 Notes for Windows Users + + The socket passed to QSocketNotifier will become non-blocking, even if + it was created as a blocking socket. + The activated() signal is sometimes triggered by high general activity + on the host, even if there is nothing to read. A subsequent read from + the socket can then fail, the error indicating that there is no data + available (e.g., \c{WSAEWOULDBLOCK}). This is an operating system + limitation, and not a bug in QSocketNotifier. + + To ensure that the socket notifier handles read notifications correctly, + follow these steps when you receive a notification: + + \list 1 + \o Disable the notifier. + \o Read data from the socket. + \o Re-enable the notifier if you are interested in more data (such as after + having written a new command to a remote server). + \endlist + + To ensure that the socket notifier handles write notifications correctly, + follow these steps when you receive a notification: + + \list 1 + \o Disable the notifier. + \o Write as much data as you can (before \c EWOULDBLOCK is returned). + \o Re-enable notifier if you have more data to write. + \endlist + + \bold{Further information:} + On Windows, Qt always disables the notifier after getting a notification, + and only re-enables it if more data is expected. For example, if data is + read from the socket and it can be used to read more, or if reading or + writing is not possible because the socket would block, in which case + it is necessary to wait before attempting to read or write again. + + \sa QFile, QProcess, QTcpSocket, QUdpSocket +*/ + +/*! + \enum QSocketNotifier::Type + + This enum describes the various types of events that a socket + notifier can recognize. The type must be specified when + constructing the socket notifier. + + Note that if you need to monitor both reads and writes for the + same file descriptor, you must create two socket notifiers. Note + also that it is not possible to install two socket notifiers of + the same type (Read, Write, Exception) on the same socket. + + \value Read There is data to be read. + \value Write Data can be written. + \value Exception An exception has occurred. We recommend against using this. + + \sa QSocketNotifier(), type() +*/ + +/*! + Constructs a socket notifier with the given \a parent. It enables + the \a socket, and watches for events of the given \a type. + + It is generally advisable to explicitly enable or disable the + socket notifier, especially for write notifiers. + + \bold{Note for Windows users:} The socket passed to QSocketNotifier + will become non-blocking, even if it was created as a blocking socket. + + \sa setEnabled(), isEnabled() +*/ + +QSocketNotifier::QSocketNotifier(int socket, Type type, QObject *parent) + : QObject(parent) +{ + if (socket < 0) + qWarning("QSocketNotifier: Invalid socket specified"); + sockfd = socket; + sntype = type; + snenabled = true; + + Q_D(QObject); + if (!d->threadData->eventDispatcher) { + qWarning("QSocketNotifier: Can only be used with threads started with QThread"); + } else { + d->threadData->eventDispatcher->registerSocketNotifier(this); + } +} + +#ifdef QT3_SUPPORT +/*! + \obsolete + + Use the QSocketNotifier() constructor combined with the + QObject::setObjectName() function instead. + + \oldcode + QSocketNotifier *notifier = new QSocketNotifier(socket, type, parent, name); + \newcode + QSocketNotifier *notifier = new QSocketNotifier(socket, type, parent); + notifier->setObjectName(name); + \endcode +*/ + +QSocketNotifier::QSocketNotifier(int socket, Type type, QObject *parent, + const char *name) + : QObject(parent) +{ + setObjectName(QString::fromAscii(name)); + if (socket < 0) + qWarning("QSocketNotifier: Invalid socket specified"); + sockfd = socket; + sntype = type; + snenabled = true; + + Q_D(QObject); + if (!d->threadData->eventDispatcher) { + qWarning("QSocketNotifier: Can only be used with threads started with QThread"); + } else { + d->threadData->eventDispatcher->registerSocketNotifier(this); + } +} +#endif +/*! + Destroys this socket notifier. +*/ + +QSocketNotifier::~QSocketNotifier() +{ + setEnabled(false); +} + + +/*! + \fn void QSocketNotifier::activated(int socket) + + This signal is emitted whenever the socket notifier is enabled and + a socket event corresponding to its \l {Type}{type} occurs. + + The socket identifier is passed in the \a socket parameter. + + \sa type(), socket() +*/ + + +/*! + \fn int QSocketNotifier::socket() const + + Returns the socket identifier specified to the constructor. + + \sa type() +*/ + +/*! + \fn Type QSocketNotifier::type() const + + Returns the socket event type specified to the constructor. + + \sa socket() +*/ + + +/*! + \fn bool QSocketNotifier::isEnabled() const + + Returns true if the notifier is enabled; otherwise returns false. + + \sa setEnabled() +*/ + +/*! + If \a enable is true, the notifier is enabled; otherwise the notifier + is disabled. + + The notifier is enabled by default, i.e. it emits the activated() + signal whenever a socket event corresponding to its + \l{type()}{type} occurs. If it is disabled, it ignores socket + events (the same effect as not creating the socket notifier). + + Write notifiers should normally be disabled immediately after the + activated() signal has been emitted + + \sa isEnabled(), activated() +*/ + +void QSocketNotifier::setEnabled(bool enable) +{ + if (sockfd < 0) + return; + if (snenabled == enable) // no change + return; + snenabled = enable; + + Q_D(QObject); + if (!d->threadData->eventDispatcher) // perhaps application/thread is shutting down + return; + if (snenabled) + d->threadData->eventDispatcher->registerSocketNotifier(this); + else + d->threadData->eventDispatcher->unregisterSocketNotifier(this); +} + + +/*!\reimp +*/ +bool QSocketNotifier::event(QEvent *e) +{ + // Emits the activated() signal when a QEvent::SockAct is + // received. + if (e->type() == QEvent::ThreadChange) { + if (snenabled) { + QMetaObject::invokeMethod(this, "setEnabled", Qt::QueuedConnection, + Q_ARG(bool, snenabled)); + setEnabled(false); + } + } + QObject::event(e); // will activate filters + if (e->type() == QEvent::SockAct) { + emit activated(sockfd); + return true; + } + return false; +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qsocketnotifier.h b/src/corelib/kernel/qsocketnotifier.h new file mode 100644 index 0000000..b1fa290 --- /dev/null +++ b/src/corelib/kernel/qsocketnotifier.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOCKETNOTIFIER_H +#define QSOCKETNOTIFIER_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class Q_CORE_EXPORT QSocketNotifier : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QObject) + +public: + enum Type { Read, Write, Exception }; + + QSocketNotifier(int socket, Type, QObject *parent = 0); +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QSocketNotifier(int socket, Type, QObject *parent, const char *name); +#endif + ~QSocketNotifier(); + + inline int socket() const { return sockfd; } + inline Type type() const { return sntype; } + + inline bool isEnabled() const { return snenabled; } + +public Q_SLOTS: + void setEnabled(bool); + +Q_SIGNALS: + void activated(int socket); + +protected: + bool event(QEvent *); + +private: + Q_DISABLE_COPY(QSocketNotifier) + + int sockfd; + Type sntype; + bool snenabled; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSOCKETNOTIFIER_H diff --git a/src/corelib/kernel/qsystemsemaphore.cpp b/src/corelib/kernel/qsystemsemaphore.cpp new file mode 100644 index 0000000..e8426b3 --- /dev/null +++ b/src/corelib/kernel/qsystemsemaphore.cpp @@ -0,0 +1,360 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsystemsemaphore.h" +#include "qsystemsemaphore_p.h" +#include <qglobal.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SYSTEMSEMAPHORE + +/*! + \class QSystemSemaphore + \ingroup ipc + \since 4.4 + + \brief The QSystemSemaphore class provides a general counting system semaphore. + + A semaphore is a generalization of a mutex. While a mutex can be + locked only once, a semaphore can be acquired multiple times. + Typically, a semaphore is used to protect a certain number of + identical resources. + + Like its lighter counterpart QSemaphore, a QSystemSemaphore can be + accessed from multiple \l {QThread} {threads}. Unlike QSemaphore, a + QSystemSemaphore can also be accessed from multiple \l {QProcess} + {processes}. This means QSystemSemaphore is a much heavier class, so + if your application doesn't need to access your semaphores across + multiple processes, you will probably want to use QSemaphore. + + Semaphores support two fundamental operations, acquire() and release(): + + acquire() tries to acquire one resource. If there isn't a resource + available, the call blocks until a resource becomes available. Then + the resource is acquired and the call returns. + + release() releases one resource so it can be acquired by another + process. The function can also be called with a parameter n > 1, + which releases n resources. + + A system semaphore is created with a string key that other processes + can use to use the same semaphore. + + Example: Create a system semaphore + \snippet doc/src/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp 0 + + A typical application of system semaphores is for controlling access + to a circular buffer shared by a producer process and a consumer + processes. + + \section1 Platform-Specific Behavior + + When using this class, be aware of the following platform + differences: + + \bold{Windows:} QSystemSemaphore does not own its underlying system + semaphore. Windows owns it. This means that when all instances of + QSystemSemaphore for a particular key have been destroyed, either by + having their destructors called, or because one or more processes + crash, Windows removes the underlying system semaphore. + + \bold{Unix:} + + \list + \o QSystemSemaphore owns the underlying system semaphore + in Unix systems. This means that the last process having an instance of + QSystemSemaphore for a particular key must remove the underlying + system semaphore in its destructor. If the last process crashes + without running the QSystemSemaphore destructor, Unix does not + automatically remove the underlying system semaphore, and the + semaphore survives the crash. A subsequent process that constructs a + QSystemSemaphore with the same key will then be given the existing + system semaphore. In that case, if the QSystemSemaphore constructor + has specified its \l {QSystemSemaphore::AccessMode} {access mode} as + \l {QSystemSemaphore::} {Open}, its initial resource count will not + be reset to the one provided but remain set to the value it received + in the crashed process. To protect against this, the first process + to create a semaphore for a particular key (usually a server), must + pass its \l {QSystemSemaphore::AccessMode} {access mode} as \l + {QSystemSemaphore::} {Create}, which will force Unix to reset the + resource count in the underlying system semaphore. + + \o When a process using QSystemSemaphore terminates for + any reason, Unix automatically reverses the effect of all acquire + operations that were not released. Thus if the process acquires a + resource and then exits without releasing it, Unix will release that + resource. + \endlist + + \sa QSharedMemory, QSemaphore + */ + +/*! + Requests a system semaphore for the specified \a key. The parameters + \a initialValue and \a mode are used according to the following + rules, which are system dependent. + + In Unix, if the \a mode is \l {QSystemSemaphore::} {Open} and the + system already has a semaphore identified by \a key, that semaphore + is used, and the semaphore's resource count is not changed, i.e., \a + initialValue is ignored. But if the system does not already have a + semaphore identified by \a key, it creates a new semaphore for that + key and sets its resource count to \a initialValue. + + In Unix, if the \a mode is \l {QSystemSemaphore::} {Create} and the + system already has a semaphore identified by \a key, that semaphore + is used, and its resource count is set to \a initialValue. If the + system does not already have a semaphore identified by \a key, it + creates a new semaphore for that key and sets its resource count to + \a initialValue. + + In Windows, \a mode is ignored, and the system always tries to + create a semaphore for the specified \a key. If the system does not + already have a semaphore identified as \a key, it creates the + semaphore and sets its resource count to \a initialValue. But if the + system already has a semaphore identified as \a key it uses that + semaphore and ignores \a initialValue. + + The \l {QSystemSemaphore::AccessMode} {mode} parameter is only used + in Unix systems to handle the case where a semaphore survives a + process crash. In that case, the next process to allocate a + semaphore with the same \a key will get the semaphore that survived + the crash, and unless \a mode is \l {QSystemSemaphore::} {Create}, + the resource count will not be reset to \a initialValue but will + retain the initial value it had been given by the crashed process. + + \sa acquire(), key() + */ +QSystemSemaphore::QSystemSemaphore(const QString &key, int initialValue, AccessMode mode) +{ + d = new QSystemSemaphorePrivate; + setKey(key, initialValue, mode); +} + +/*! + The destructor destroys the QSystemSemaphore object, but the + underlying system semaphore is not removed from the system unless + this instance of QSystemSemaphore is the last one existing for that + system semaphore. + + Two important side effects of the destructor depend on the system. + In Windows, if acquire() has been called for this semaphore but not + release(), release() will not be called by the destructor, nor will + the resource be released when the process exits normally. This would + be a program bug which could be the cause of a deadlock in another + process trying to acquire the same resource. In Unix, acquired + resources that are not released before the destructor is called are + automatically released when the process exits. +*/ +QSystemSemaphore::~QSystemSemaphore() +{ + d->cleanHandle(); + delete d; +} + +/*! + \enum QSystemSemaphore::AccessMode + + This enum is used by the constructor and setKey(). Its purpose is to + enable handling the problem in Unix implementations of semaphores + that survive a crash. In Unix, when a semaphore survives a crash, we + need a way to force it to reset its resource count, when the system + reuses the semaphore. In Windows, where semaphores can't survive a + crash, this enum has no effect. + + \value Open If the semaphore already exists, its initial resource + count is not reset. If the semaphore does not already exist, it is + created and its initial resource count set. + + \value Create QSystemSemaphore takes ownership of the semaphore and + sets its resource count to the requested value, regardless of + whether the semaphore already exists by having survived a crash. + This value should be passed to the constructor, when the first + semaphore for a particular key is constructed and you know that if + the semaphore already exists it could only be because of a crash. In + Windows, where a semaphore can't survive a crash, Create and Open + have the same behavior. +*/ + +/*! + This function works the same as the constructor. It reconstructs + this QSystemSemaphore object. If the new \a key is different from + the old key, calling this function is like calling the destructor of + the semaphore with the old key, then calling the constructor to + create a new semaphore with the new \a key. The \a initialValue and + \a mode parameters are as defined for the constructor. + + \sa QSystemSemaphore(), key() + */ +void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode mode) +{ + if (key == d->key && mode == Open) + return; + d->error = NoError; + d->errorString = QString(); +#ifndef Q_OS_WIN + // optimization to not destroy/create the file & semaphore + if (key == d->key && mode == Create && d->createdSemaphore && d->createdFile) { + d->initialValue = initialValue; + d->unix_key = -1; + d->handle(mode); + return; + } +#endif + d->cleanHandle(); + d->key = key; + d->initialValue = initialValue; + // cache the file name so it doesn't have to be generated all the time. + d->fileName = d->makeKeyFileName(); + d->handle(mode); +} + +/*! + Returns the key assigned to this system semaphore. The key is the + name by which the semaphore can be accessed from other processes. + + \sa setKey() + */ +QString QSystemSemaphore::key() const +{ + return d->key; +} + +/*! + Acquires one of the resources guarded by this semaphore, if there is + one available, and returns true. If all the resources guarded by this + semaphore have already been acquired, the call blocks until one of + them is released by another process or thread having a semaphore + with the same key. + + If false is returned, a system error has occurred. Call error() + to get a value of QSystemSemaphore::SystemSemaphoreError that + indicates which error occurred. + + \sa release() + */ +bool QSystemSemaphore::acquire() +{ + return d->modifySemaphore(-1); +} + +/*! + Releases \a n resources guarded by the semaphore. Returns true + unless there is a system error. + + Example: Create a system semaphore having five resources; acquire + them all and then release them all. + + \snippet doc/src/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp 1 + + This function can also "create" resources. For example, immediately + following the sequence of statements above, suppose we add the + statement: + + \snippet doc/src/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp 2 + + Ten new resources are now guarded by the semaphore, in addition to + the five that already existed. You would not normally use this + function to create more resources. + + \sa acquire() + */ +bool QSystemSemaphore::release(int n) +{ + if (n == 0) + return true; + if (n < 0) { + qWarning("QSystemSemaphore::release: n is negative."); + return false; + } + return d->modifySemaphore(n); +} + +/*! + Returns a value indicating whether an error occurred, and, if so, + which error it was. + + \sa errorString() + */ +QSystemSemaphore::SystemSemaphoreError QSystemSemaphore::error() const +{ + return d->error; +} + +/*! + \enum QSystemSemaphore::SystemSemaphoreError + + \value NoError No error occurred. + + \value PermissionDenied The operation failed because the caller + didn't have the required permissions. + + \value KeyError The operation failed because of an invalid key. + + \value AlreadyExists The operation failed because a system + semaphore with the specified key already existed. + + \value NotFound The operation failed because a system semaphore + with the specified key could not be found. + + \value OutOfResources The operation failed because there was + not enough memory available to fill the request. + + \value UnknownError Something else happened and it was bad. +*/ + +/*! + Returns a text description of the last error that occurred. If + error() returns an \l {QSystemSemaphore::SystemSemaphoreError} {error + value}, call this function to get a text string that describes the + error. + + \sa error() + */ +QString QSystemSemaphore::errorString() const +{ + return d->errorString; +} + +#endif // QT_NO_SYSTEMSEMAPHORE + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qsystemsemaphore.h b/src/corelib/kernel/qsystemsemaphore.h new file mode 100644 index 0000000..5a02072 --- /dev/null +++ b/src/corelib/kernel/qsystemsemaphore.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSYSTEMSEMAPHORE_H +#define QSYSTEMSEMAPHORE_H + +#include <QtCore/qstring.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_SYSTEMSEMAPHORE + +class QSystemSemaphorePrivate; + +class Q_CORE_EXPORT QSystemSemaphore +{ + +public: + enum AccessMode + { + Open, + Create + }; + + enum SystemSemaphoreError + { + NoError, + PermissionDenied, + KeyError, + AlreadyExists, + NotFound, + OutOfResources, + UnknownError + }; + + QSystemSemaphore(const QString &key, int initialValue = 0, AccessMode mode = Open); + ~QSystemSemaphore(); + + void setKey(const QString &key, int initialValue = 0, AccessMode mode = Open); + QString key() const; + + bool acquire(); + bool release(int n = 1); + + SystemSemaphoreError error() const; + QString errorString() const; + +private: + Q_DISABLE_COPY(QSystemSemaphore) + QSystemSemaphorePrivate *d; +}; + +#endif // QT_NO_SYSTEMSEMAPHORE + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSYSTEMSEMAPHORE_H + diff --git a/src/corelib/kernel/qsystemsemaphore_p.h b/src/corelib/kernel/qsystemsemaphore_p.h new file mode 100644 index 0000000..81d4f10 --- /dev/null +++ b/src/corelib/kernel/qsystemsemaphore_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSYSTEMSEMAPHORE_P_H +#define QSYSTEMSEMAPHORE_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. +// + +#include "qsystemsemaphore.h" + +#ifndef QT_NO_SYSTEMSEMAPHORE + +#include "qsharedmemory_p.h" +#ifndef Q_OS_WINCE +# include <sys/types.h> +#endif + +QT_BEGIN_NAMESPACE + +class QSystemSemaphorePrivate +{ + +public: + QSystemSemaphorePrivate(); + + QString makeKeyFileName() + { + return QSharedMemoryPrivate::makePlatformSafeKey(key, QLatin1String("qipc_systemsem_")); + } + +#ifdef Q_OS_WIN + HANDLE handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open); +#else + key_t handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open); +#endif + void setErrorString(const QString &function); + void cleanHandle(); + bool modifySemaphore(int count); + + QString key; + QString fileName; + int initialValue; +#ifdef Q_OS_WIN + HANDLE semaphore; + HANDLE semaphoreLock; +#else + int semaphore; + bool createdFile; + bool createdSemaphore; + key_t unix_key; +#endif + + QString errorString; + QSystemSemaphore::SystemSemaphoreError error; +}; + +#endif // QT_NO_SYSTEMSEMAPHORE + + +QT_END_NAMESPACE +#endif // QSYSTEMSEMAPHORE_P_H + diff --git a/src/corelib/kernel/qsystemsemaphore_unix.cpp b/src/corelib/kernel/qsystemsemaphore_unix.cpp new file mode 100644 index 0000000..a7802ee --- /dev/null +++ b/src/corelib/kernel/qsystemsemaphore_unix.cpp @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsystemsemaphore.h" +#include "qsystemsemaphore_p.h" + +#include <qdebug.h> +#include <qfile.h> +#include <qcoreapplication.h> + +#ifndef QT_NO_SYSTEMSEMAPHORE + +#include <sys/types.h> +#include <sys/ipc.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/shm.h> + +#include <sys/sem.h> + +// OpenBSD 4.2 doesn't define EIDRM, see BUGS section: +// http://www.openbsd.org/cgi-bin/man.cgi?query=semop&manpath=OpenBSD+4.2 +#if defined(Q_OS_OPENBSD) && !defined(EIDRM) +#define EIDRM EINVAL +#endif + +QT_BEGIN_NAMESPACE + +// We have to define this as on some sem.h will have it +union qt_semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ + unsigned short *array; /* array for GETALL, SETALL */ +}; + +QSystemSemaphorePrivate::QSystemSemaphorePrivate() : + semaphore(-1), createdFile(false), + createdSemaphore(false), unix_key(-1), error(QSystemSemaphore::NoError) +{ +} + +void QSystemSemaphorePrivate::setErrorString(const QString &function) +{ + // EINVAL is handled in functions so they can give better error strings + switch (errno) { + case EPERM: + case EACCES: + errorString = QCoreApplication::translate("QSystemSemaphore", "%1: permission denied").arg(function); + error = QSystemSemaphore::PermissionDenied; + break; + case EEXIST: + errorString = QCoreApplication::translate("QSystemSemaphore", "%1: already exists").arg(function); + error = QSystemSemaphore::AlreadyExists; + break; + case ENOENT: + errorString = QCoreApplication::translate("QSystemSemaphore", "%1: does not exist").arg(function); + error = QSystemSemaphore::NotFound; + break; + case ERANGE: + case ENOSPC: + errorString = QCoreApplication::translate("QSystemSemaphore", "%1: out of resources").arg(function); + error = QSystemSemaphore::OutOfResources; + break; + default: + errorString = QCoreApplication::translate("QSystemSemaphore", "%1: unknown error %2").arg(function).arg(errno); + error = QSystemSemaphore::UnknownError; +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << errorString << "key" << key << "errno" << errno << EINVAL; +#endif + } +} + +/*! + \internal + + Setup unix_key + */ +key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode) +{ + if (key.isEmpty()){ + errorString = QCoreApplication::tr("%1: key is empty", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:")); + error = QSystemSemaphore::KeyError; + return -1; + } + + // ftok requires that an actual file exists somewhere + if (-1 != unix_key) + return unix_key; + + // Create the file needed for ftok + int built = QSharedMemoryPrivate::createUnixKeyFile(fileName); + if (-1 == built) { + errorString = QCoreApplication::tr("%1: unable to make key", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:")); + error = QSystemSemaphore::KeyError; + return -1; + } + createdFile = (1 == built); + + // Get the unix key for the created file + unix_key = ftok(QFile::encodeName(fileName).constData(), 'Q'); + if (-1 == unix_key) { + errorString = QCoreApplication::tr("%1: ftok failed", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:")); + error = QSystemSemaphore::KeyError; + return -1; + } + + // Get semaphore + semaphore = semget(unix_key, 1, 0666 | IPC_CREAT | IPC_EXCL); + if (-1 == semaphore) { + if (errno == EEXIST) + semaphore = semget(unix_key, 1, 0666 | IPC_CREAT); + if (-1 == semaphore) { + setErrorString(QLatin1String("QSystemSemaphore::handle")); + cleanHandle(); + return -1; + } + } else { + createdSemaphore = true; + // Force cleanup of file, it is possible that it can be left over from a crash + createdFile = true; + } + + if (mode == QSystemSemaphore::Create) { + createdSemaphore = true; + createdFile = true; + } + + // Created semaphore so initialize its value. + if (createdSemaphore && initialValue >= 0) { + qt_semun init_op; + init_op.val = initialValue; + if (-1 == semctl(semaphore, 0, SETVAL, init_op)) { + setErrorString(QLatin1String("QSystemSemaphore::handle")); + cleanHandle(); + return -1; + } + } + + return unix_key; +} + +/*! + \internal + + Cleanup the unix_key + */ +void QSystemSemaphorePrivate::cleanHandle() +{ + unix_key = -1; + + // remove the file if we made it + if (createdFile) { + QFile::remove(fileName); + createdFile = false; + } + + if (createdSemaphore) { + if (-1 != semaphore) { + if (-1 == semctl(semaphore, 0, IPC_RMID, 0)) { + setErrorString(QLatin1String("QSystemSemaphore::cleanHandle")); +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::cleanHandle semctl failed."); +#endif + } + semaphore = -1; + } + createdSemaphore = false; + } +} + +/*! + \internal + */ +bool QSystemSemaphorePrivate::modifySemaphore(int count) +{ + if (-1 == handle()) + return false; + + struct sembuf operation; + operation.sem_num = 0; + operation.sem_op = count; + operation.sem_flg = SEM_UNDO; + if (-1 == semop(semaphore, &operation, 1)) { + // If the semaphore was removed be nice and create it and then modifySemaphore again + if (errno == EINVAL || errno == EIDRM) { + semaphore = -1; + cleanHandle(); + handle(); + return modifySemaphore(count); + } + setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore")); +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::modify failed") << count << semctl(semaphore, 0, GETVAL) << errno << EIDRM << EINVAL; +#endif + return false; + } + + return true; +} + + +QT_END_NAMESPACE + +#endif // QT_NO_SYSTEMSEMAPHORE diff --git a/src/corelib/kernel/qsystemsemaphore_win.cpp b/src/corelib/kernel/qsystemsemaphore_win.cpp new file mode 100644 index 0000000..5912344 --- /dev/null +++ b/src/corelib/kernel/qsystemsemaphore_win.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsystemsemaphore.h" +#include "qsystemsemaphore_p.h" +#include "qcoreapplication.h" +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SYSTEMSEMAPHORE + +QSystemSemaphorePrivate::QSystemSemaphorePrivate() : + semaphore(0), error(QSystemSemaphore::NoError) +{ +} + +void QSystemSemaphorePrivate::setErrorString(const QString &function) +{ + BOOL windowsError = GetLastError(); + if (windowsError == 0) + return; + + switch (windowsError) { + case ERROR_NO_SYSTEM_RESOURCES: + case ERROR_NOT_ENOUGH_MEMORY: + error = QSystemSemaphore::OutOfResources; + errorString = QCoreApplication::translate("QSystemSemaphore", "%1: out of resources").arg(function); + break; + case ERROR_ACCESS_DENIED: + error = QSystemSemaphore::PermissionDenied; + errorString = QCoreApplication::translate("QSystemSemaphore", "%1: permission denied").arg(function); + break; + default: + errorString = QCoreApplication::translate("QSystemSemaphore", "%1: unknown error %2").arg(function).arg(windowsError); + error = QSystemSemaphore::UnknownError; +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << errorString << "key" << key; +#endif + } +} + +HANDLE QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode) +{ + // don't allow making handles on empty keys + if (key.isEmpty()) + return 0; + + // Create it if it doesn't already exists. + if (semaphore == 0) { + QString safeName = makeKeyFileName(); + QT_WA({ + semaphore = CreateSemaphoreW(0, initialValue, MAXLONG, (TCHAR*)safeName.utf16()); + }, { + semaphore = CreateSemaphoreA(0, initialValue, MAXLONG, safeName.toLocal8Bit().constData()); + }); + if (semaphore == NULL) + setErrorString(QLatin1String("QSystemSemaphore::handle")); + } + + return semaphore; +} + +void QSystemSemaphorePrivate::cleanHandle() +{ + if (semaphore && !CloseHandle(semaphore)) { +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphorePrivate::CloseHandle: sem failed"); +#endif + } + semaphore = 0; +} + +bool QSystemSemaphorePrivate::modifySemaphore(int count) +{ + if (0 == handle()) + return false; + + if (count > 0) { + if (0 == ReleaseSemaphore(semaphore, count, 0)) { + setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore")); +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::modifySemaphore ReleaseSemaphore failed"); +#endif + return false; + } + } else { + if (WAIT_OBJECT_0 != WaitForSingleObject(semaphore, INFINITE)) { + setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore")); +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::modifySemaphore WaitForSingleObject failed"); +#endif + return false; + } + } + + return true; +} + +#endif //QT_NO_SYSTEMSEMAPHORE + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp new file mode 100644 index 0000000..01e81ab --- /dev/null +++ b/src/corelib/kernel/qtimer.cpp @@ -0,0 +1,372 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtimer.h" +#include "qabstracteventdispatcher.h" +#include "qcoreapplication.h" +#include "qobject_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QTimer + \brief The QTimer class provides repetitive and single-shot timers. + + \ingroup time + \ingroup events + \mainclass + + The QTimer class provides a high-level programming interface for + timers. To use it, create a QTimer, connect its timeout() signal + to the appropriate slots, and call start(). From then on it will + emit the timeout() signal at constant intervals. + + Example for a one second (1000 millisecond) timer (from the + \l{widgets/analogclock}{Analog Clock} example): + + \snippet examples/widgets/analogclock/analogclock.cpp 4 + \snippet examples/widgets/analogclock/analogclock.cpp 5 + \snippet examples/widgets/analogclock/analogclock.cpp 6 + + From then on, the \c update() slot is called every second. + + You can set a timer to time out only once by calling + setSingleShot(true). You can also use the static + QTimer::singleShot() function to call a slot after a specified + interval: + + \snippet doc/src/snippets/timers/timers.cpp 3 + + In multithreaded applications, you can use QTimer in any thread + that has an event loop. To start an event loop from a non-GUI + thread, use QThread::exec(). Qt uses the the timer's + \l{QObject::thread()}{thread affinity} to determine which thread + will emit the \l{QTimer::}{timeout()} signal. Because of this, you + must start and stop the timer in its thread; it is not possible to + start a timer from another thread. + + As a special case, a QTimer with a timeout of 0 will time out as + soon as all the events in the window system's event queue have + been processed. This can be used to do heavy work while providing + a snappy user interface: + + \snippet doc/src/snippets/timers/timers.cpp 4 + \snippet doc/src/snippets/timers/timers.cpp 5 + \snippet doc/src/snippets/timers/timers.cpp 6 + + \c processOneThing() will from then on be called repeatedly. It + should be written in such a way that it always returns quickly + (typically after processing one data item) so that Qt can deliver + events to widgets and stop the timer as soon as it has done all + its work. This is the traditional way of implementing heavy work + in GUI applications; multithreading is now becoming available on + more and more platforms, and we expect that zero-millisecond + QTimers will gradually be replaced by \l{QThread}s. + + Note that QTimer's accuracy depends on the underlying operating + system and hardware. Most platforms support an accuracy of + 1 millisecond, but Windows 98 supports only 55. If Qt is + unable to deliver the requested number of timer clicks, it will + silently discard some. + + An alternative to using QTimer is to call QObject::startTimer() + for your object and reimplement the QObject::timerEvent() event + handler in your class (which must inherit QObject). The + disadvantage is that timerEvent() does not support such + high-level features as single-shot timers or signals. + + Another alternative to using QTimer is to use QBasicTimer. It is + typically less cumbersome than using QObject::startTimer() + directly. See \l{Timers} for an overview of all three approaches. + + Some operating systems limit the number of timers that may be + used; Qt tries to work around these limitations. + + \sa QBasicTimer, QTimerEvent, QObject::timerEvent(), Timers, + {Analog Clock Example}, {Wiggly Example} +*/ + + +static const int INV_TIMER = -1; // invalid timer id + +/*! + Constructs a timer with the given \a parent. +*/ + +QTimer::QTimer(QObject *parent) + : QObject(parent), id(INV_TIMER), inter(0), del(0), single(0), nulltimer(0) +{ +} + + +#ifdef QT3_SUPPORT +/*! + Constructs a timer called \a name, with a \a parent. +*/ + +QTimer::QTimer(QObject *parent, const char *name) + : QObject(parent), id(INV_TIMER), single(0), nulltimer(0) +{ + setObjectName(QString::fromAscii(name)); +} +#endif + +/*! + Destroys the timer. +*/ + +QTimer::~QTimer() +{ + if (id != INV_TIMER) // stop running timer + stop(); +} + + +/*! + \fn void QTimer::timeout() + + This signal is emitted when the timer times out. + + \sa interval, start(), stop() +*/ + +/*! + \property QTimer::active + \since 4.3 + + This boolean property is true if the timer is running; otherwise + false. +*/ + +/*! + \fn bool QTimer::isActive() const + + Returns true if the timer is running (pending); otherwise returns + false. +*/ + +/*! + \fn int QTimer::timerId() const + + Returns the ID of the timer if the timer is running; otherwise returns + -1. +*/ + + +/*! \overload start() + + Starts or restarts the timer with the timeout specified in \l interval. + + If \l singleShot is true, the timer will be activated only once. +*/ +void QTimer::start() +{ + if (id != INV_TIMER) // stop running timer + stop(); + nulltimer = (!inter && single); + id = QObject::startTimer(inter); +} + +/*! + Starts or restarts the timer with a timeout interval of \a msec + milliseconds. +*/ +void QTimer::start(int msec) +{ + setInterval(msec); + start(); +} + + +#ifdef QT3_SUPPORT +/*! \overload start() + + Call setSingleShot(\a sshot) and start(\a msec) instead. +*/ + +int QTimer::start(int msec, bool sshot) +{ + if (id >=0 && nulltimer && !msec && sshot) + return id; + stop(); + setInterval(msec); + setSingleShot(sshot); + start(); + return timerId(); +} +#endif + + +/*! + Stops the timer. + + \sa start() +*/ + +void QTimer::stop() +{ + if (id != INV_TIMER) { + QObject::killTimer(id); + id = INV_TIMER; + } +} + + +/*! + \reimp +*/ +void QTimer::timerEvent(QTimerEvent *e) +{ + if (e->timerId() == id) { + if (single) + stop(); + emit timeout(); + } +} + +class QSingleShotTimer : public QObject +{ + Q_OBJECT + int timerId; +public: + ~QSingleShotTimer(); + QSingleShotTimer(int msec, QObject *r, const char * m); +signals: + void timeout(); +protected: + void timerEvent(QTimerEvent *); +}; + +QSingleShotTimer::QSingleShotTimer(int msec, QObject *receiver, const char *member) + : QObject(QAbstractEventDispatcher::instance()) +{ + connect(this, SIGNAL(timeout()), receiver, member); + timerId = startTimer(msec); +} + +QSingleShotTimer::~QSingleShotTimer() +{ + if (timerId > 0) + killTimer(timerId); +} + +void QSingleShotTimer::timerEvent(QTimerEvent *) +{ + // need to kill the timer _before_ we emit timeout() in case the + // slot connected to timeout calls processEvents() + if (timerId > 0) + killTimer(timerId); + timerId = -1; + emit timeout(); + + // we would like to use delete later here, but it feels like a + // waste to post a new event to handle this event, so we just unset the flag + // and explicitly delete... + qDeleteInEventHandler(this); +} + +QT_BEGIN_INCLUDE_NAMESPACE +#include "qtimer.moc" +QT_END_INCLUDE_NAMESPACE + +/*! + \reentrant + This static function calls a slot after a given time interval. + + It is very convenient to use this function because you do not need + to bother with a \link QObject::timerEvent() timerEvent\endlink or + create a local QTimer object. + + Example: + \snippet doc/src/snippets/code/src_corelib_kernel_qtimer.cpp 0 + + This sample program automatically terminates after 10 minutes + (600,000 milliseconds). + + The \a receiver is the receiving object and the \a member is the + slot. The time interval is \a msec milliseconds. + + \sa start() +*/ + +void QTimer::singleShot(int msec, QObject *receiver, const char *member) +{ + if (receiver && member) + (void) new QSingleShotTimer(msec, receiver, member); +} + +/*! + \property QTimer::singleShot + \brief whether the timer is a single-shot timer + + A single-shot timer fires only once, non-single-shot timers fire + every \l interval milliseconds. + + \sa interval, singleShot() +*/ + +/*! + \property QTimer::interval + \brief the timeout interval in milliseconds + + The default value for this property is 0. A QTimer with a timeout + interval of 0 will time out as soon as all the events in the window + system's event queue have been processed. + + Setting the interval of an active timer changes its timerId(). + + \sa singleShot +*/ +void QTimer::setInterval(int msec) +{ + inter = msec; + if (id != INV_TIMER) { // create new timer + QObject::killTimer(id); // restart timer + id = QObject::startTimer(msec); + } +} + +/*! \fn void QTimer::changeInterval(int msec) + + Use setInterval(msec) or start(msec) instead. +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h new file mode 100644 index 0000000..26afe2d --- /dev/null +++ b/src/corelib/kernel/qtimer.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIMER_H +#define QTIMER_H + +#ifndef QT_NO_QOBJECT + +#include <QtCore/qbasictimer.h> // conceptual inheritance +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class Q_CORE_EXPORT QTimer : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool singleShot READ isSingleShot WRITE setSingleShot) + Q_PROPERTY(int interval READ interval WRITE setInterval) + Q_PROPERTY(bool active READ isActive) +public: + explicit QTimer(QObject *parent = 0); +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QTimer(QObject *parent, const char *name); +#endif + ~QTimer(); + + inline bool isActive() const { return id >= 0; } + int timerId() const { return id; } + + void setInterval(int msec); + int interval() const { return inter; } + + inline void setSingleShot(bool singleShot); + inline bool isSingleShot() const { return single; } + + static void singleShot(int msec, QObject *receiver, const char *member); + +public Q_SLOTS: + void start(int msec); + + void start(); + void stop(); + +#ifdef QT3_SUPPORT + inline QT_MOC_COMPAT void changeInterval(int msec) { start(msec); }; + QT_MOC_COMPAT int start(int msec, bool sshot); +#endif + +Q_SIGNALS: + void timeout(); + +protected: + void timerEvent(QTimerEvent *); + +private: + Q_DISABLE_COPY(QTimer) + + inline int startTimer(int){ return -1;} + inline void killTimer(int){} + + int id, inter, del; + uint single : 1; + uint nulltimer : 1; +}; + +inline void QTimer::setSingleShot(bool asingleShot) { single = asingleShot; } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_QOBJECT + +#endif // QTIMER_H diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp new file mode 100644 index 0000000..cdddf36 --- /dev/null +++ b/src/corelib/kernel/qtranslator.cpp @@ -0,0 +1,827 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" + +#include "qtranslator.h" + +#ifndef QT_NO_TRANSLATION + +#include "qfileinfo.h" +#include "qstring.h" +#include "qcoreapplication.h" +#include "qcoreapplication_p.h" +#include "qdatastream.h" +#include "qfile.h" +#include "qmap.h" +#include "qalgorithms.h" +#include "qhash.h" +#include "qtranslator_p.h" + +#if defined(Q_OS_UNIX) +#define QT_USE_MMAP +#endif + +// most of the headers below are already included in qplatformdefs.h +// also this lacks Large File support but that's probably irrelevant +#if defined(QT_USE_MMAP) +// for mmap +#include <sys/mman.h> +#include <errno.h> +#endif + +#include <stdlib.h> + +#include "qobject_p.h" + +QT_BEGIN_NAMESPACE + +enum Tag { Tag_End = 1, Tag_SourceText16, Tag_Translation, Tag_Context16, Tag_Obsolete1, + Tag_SourceText, Tag_Context, Tag_Comment, Tag_Obsolete2 }; +/* +$ mcookie +3cb86418caef9c95cd211cbf60a1bddd +$ +*/ + +// magic number for the file +static const int MagicLength = 16; +static const uchar magic[MagicLength] = { + 0x3c, 0xb8, 0x64, 0x18, 0xca, 0xef, 0x9c, 0x95, + 0xcd, 0x21, 0x1c, 0xbf, 0x60, 0xa1, 0xbd, 0xdd +}; + +static bool match(const uchar* found, const char* target, uint len) +{ + // catch the case if \a found has a zero-terminating symbol and \a len includes it. + // (normalize it to be without the zero-terminating symbol) + if (len > 0 && found[len-1] == '\0') + --len; + // 0 means anything, "" means empty + return !found || (qstrncmp((const char *)found, target, len) == 0 && target[len] == '\0'); +} + +static uint elfHash(const char *name) +{ + const uchar *k; + uint h = 0; + uint g; + + if (name) { + k = (const uchar *) name; + while (*k) { + h = (h << 4) + *k++; + if ((g = (h & 0xf0000000)) != 0) + h ^= g >> 24; + h &= ~g; + } + } + if (!h) + h = 1; + return h; +} + +static int numerusHelper(int n, const uchar *rules, int rulesSize) +{ +#define CHECK_RANGE \ + do { \ + if (i >= rulesSize) \ + return -1; \ + } while (0) + + int result = 0; + int i = 0; + + if (rulesSize == 0) + return 0; + + for (;;) { + bool orExprTruthValue = false; + + for (;;) { + bool andExprTruthValue = true; + + for (;;) { + bool truthValue = true; + + CHECK_RANGE; + int opcode = rules[i++]; + + int leftOperand = n; + if (opcode & Q_MOD_10) { + leftOperand %= 10; + } else if (opcode & Q_MOD_100) { + leftOperand %= 100; + } + + int op = opcode & Q_OP_MASK; + + CHECK_RANGE; + int rightOperand = rules[i++]; + + switch (op) { + default: + return -1; + case Q_EQ: + truthValue = (leftOperand == rightOperand); + break; + case Q_LT: + truthValue = (leftOperand < rightOperand); + break; + case Q_LEQ: + truthValue = (leftOperand <= rightOperand); + break; + case Q_BETWEEN: + int bottom = rightOperand; + CHECK_RANGE; + int top = rules[i++]; + truthValue = (leftOperand >= bottom && leftOperand <= top); + } + + if (opcode & Q_NOT) + truthValue = !truthValue; + + andExprTruthValue = andExprTruthValue && truthValue; + + if (i == rulesSize || rules[i] != Q_AND) + break; + ++i; + } + + orExprTruthValue = orExprTruthValue || andExprTruthValue; + + if (i == rulesSize || rules[i] != Q_OR) + break; + ++i; + } + + if (orExprTruthValue) + return result; + + ++result; + + if (i == rulesSize) + return result; + + if (rules[i++] != Q_NEWRULE) + break; + } + return -1; +} + +extern bool qt_detectRTLLanguage(); + +class QTranslatorPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QTranslator) +public: + enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88 }; + + QTranslatorPrivate() + : used_mmap(0), unmapPointer(0), unmapLength(0), + messageArray(0), offsetArray(0), contextArray(0), numerusRulesArray(0), + messageLength(0), offsetLength(0), contextLength(0), numerusRulesLength(0) {} + + // for mmap'ed files, this is what needs to be unmapped. + bool used_mmap : 1; + char *unmapPointer; + unsigned int unmapLength; + + // for squeezed but non-file data, this is what needs to be deleted + const uchar *messageArray; + const uchar *offsetArray; + const uchar *contextArray; + const uchar *numerusRulesArray; + uint messageLength; + uint offsetLength; + uint contextLength; + uint numerusRulesLength; + + bool do_load(const uchar *data, int len); + QString do_translate(const char *context, const char *sourceText, const char *comment, + int n) const; + void clear(); +}; + +/*! + \class QTranslator + + \brief The QTranslator class provides internationalization support for text + output. + + \ingroup i18n + \ingroup environment + \mainclass + + An object of this class contains a set of translations from a + source language to a target language. QTranslator provides + functions to look up translations in a translation file. + Translation files are created using \l{Qt Linguist}. + + The most common use of QTranslator is to: load a translation + file, install it using QApplication::installTranslator(), and use + it via QObject::tr(). Here's the \c main() function from the + \l{linguist/hellotr}{Hello tr()} example: + + \snippet examples/linguist/hellotr/main.cpp 2 + + Note that the translator must be created \e before the + application's widgets. + + Most applications will never need to do anything else with this + class. The other functions provided by this class are useful for + applications that work on translator files. + + \section1 Looking up Translations + + It is possible to look up a translation using translate() (as tr() + and QApplication::translate() do). The translate() function takes + up to three parameters: + + \list + \o The \e context - usually the class name for the tr() caller. + \o The \e {source text} - usually the argument to tr(). + \o The \e disambiguation - an optional string that helps disambiguate + different uses of the same text in the same context. + \endlist + + For example, the "Cancel" in a dialog might have "Anuluj" when the + program runs in Polish (in this case the source text would be + "Cancel"). The context would (normally) be the dialog's class + name; there would normally be no comment, and the translated text + would be "Anuluj". + + But it's not always so simple. The Spanish version of a printer + dialog with settings for two-sided printing and binding would + probably require both "Activado" and "Activada" as translations + for "Enabled". In this case the source text would be "Enabled" in + both cases, and the context would be the dialog's class name, but + the two items would have disambiguations such as "two-sided printing" + for one and "binding" for the other. The disambiguation enables the + translator to choose the appropriate gender for the Spanish version, + and enables Qt to distinguish between translations. + + \section1 Using Multiple Translations + + Multiple translation files can be installed in an application. + Translations are searched for in the reverse order in which they were + installed, so the most recently installed translation file is searched + for translations first and the earliest translation file is searched + last. The search stops as soon as a translation containing a matching + string is found. + + This mechanism makes it possible for a specific translation to be + "selected" or given priority over the others; simply uninstall the + translator from the application by passing it to the + QApplication::removeTranslator() function and reinstall it with + QApplication::installTranslator(). It will then be the first + translation to be searched for matching strings. + + \sa QApplication::installTranslator(), QApplication::removeTranslator(), + QObject::tr(), QApplication::translate(), {I18N Example}, + {Hello tr() Example}, {Arrow Pad Example}, {Troll Print Example} +*/ + +/*! + Constructs an empty message file object with parent \a parent that + is not connected to any file. +*/ + +QTranslator::QTranslator(QObject * parent) + : QObject(*new QTranslatorPrivate, parent) +{ +} + +#ifdef QT3_SUPPORT +/*! + \overload QTranslator() + \obsolete + */ +QTranslator::QTranslator(QObject * parent, const char * name) + : QObject(*new QTranslatorPrivate, parent) +{ + setObjectName(QString::fromAscii(name)); +} +#endif + +/*! + Destroys the object and frees any allocated resources. +*/ + +QTranslator::~QTranslator() +{ + if (QCoreApplication::instance()) + QCoreApplication::instance()->removeTranslator(this); + Q_D(QTranslator); + d->clear(); +} + +/*! + Loads \a filename + \a suffix (".qm" if the \a suffix is + not specified), which may be an absolute file name or relative + to \a directory. Returns true if the translation is successfully + loaded; otherwise returns false. + + The previous contents of this translator object are discarded. + + If the file name does not exist, other file names are tried + in the following order: + + \list 1 + \o File name without \a suffix appended. + \o File name with text after a character in \a search_delimiters + stripped ("_." is the default for \a search_delimiters if it is + an empty string) and \a suffix. + \o File name stripped without \a suffix appended. + \o File name stripped further, etc. + \endlist + + For example, an application running in the fr_CA locale + (French-speaking Canada) might call load("foo.fr_ca", + "/opt/foolib"). load() would then try to open the first existing + readable file from this list: + + \list 1 + \o \c /opt/foolib/foo.fr_ca.qm + \o \c /opt/foolib/foo.fr_ca + \o \c /opt/foolib/foo.fr.qm + \o \c /opt/foolib/foo.fr + \o \c /opt/foolib/foo.qm + \o \c /opt/foolib/foo + \endlist +*/ + +bool QTranslator::load(const QString & filename, const QString & directory, + const QString & search_delimiters, + const QString & suffix) +{ + Q_D(QTranslator); + d->clear(); + + QString prefix; + if (QFileInfo(filename).isRelative()) { + prefix = directory; + if (prefix.length() && !prefix.endsWith(QLatin1Char('/'))) + prefix += QLatin1Char('/'); + } + + QString fname = filename; + QString realname; + QString delims; + delims = search_delimiters.isNull() ? QString::fromLatin1("_.") : search_delimiters; + + for (;;) { + QFileInfo fi; + + realname = prefix + fname + (suffix.isNull() ? QString::fromLatin1(".qm") : suffix); + fi.setFile(realname); + if (fi.isReadable()) + break; + + realname = prefix + fname; + fi.setFile(realname); + if (fi.isReadable()) + break; + + int rightmost = 0; + for (int i = 0; i < (int)delims.length(); i++) { + int k = fname.lastIndexOf(delims[i]); + if (k > rightmost) + rightmost = k; + } + + // no truncations? fail + if (rightmost == 0) + return false; + + fname.truncate(rightmost); + } + + // realname is now the fully qualified name of a readable file. + + bool ok = false; + +#ifdef QT_USE_MMAP + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif +#ifndef MAP_FAILED +#define MAP_FAILED -1 +#endif + + int fd = -1; + if (!realname.startsWith(QLatin1Char(':'))) + fd = QT_OPEN(QFile::encodeName(realname), O_RDONLY, +#if defined(Q_OS_WIN) + _S_IREAD | _S_IWRITE +#else + 0666 +#endif + ); + if (fd >= 0) { + QT_STATBUF st; + if (!QT_FSTAT(fd, &st)) { + char *ptr; + ptr = reinterpret_cast<char *>( + mmap(0, st.st_size, // any address, whole file + PROT_READ, // read-only memory + MAP_FILE | MAP_PRIVATE, // swap-backed map from file + fd, 0)); // from offset 0 of fd + if (ptr && ptr != reinterpret_cast<char *>(MAP_FAILED)) { + d->used_mmap = true; + d->unmapPointer = ptr; + d->unmapLength = st.st_size; + ok = true; + } + } + ::close(fd); + } +#endif // QT_USE_MMAP + + if (!ok) { + QFile file(realname); + d->unmapLength = file.size(); + if (!d->unmapLength) + return false; + d->unmapPointer = new char[d->unmapLength]; + + if (file.open(QIODevice::ReadOnly)) + ok = (d->unmapLength == (uint)file.read(d->unmapPointer, d->unmapLength)); + + if (!ok) { + delete [] d->unmapPointer; + d->unmapPointer = 0; + d->unmapLength = 0; + return false; + } + } + + return d->do_load(reinterpret_cast<const uchar *>(d->unmapPointer), d->unmapLength); +} + +/*! + \overload load() + \fn bool QTranslator::load(const uchar *data, int len) + + Loads the .qm file data \a data of length \a len into the + translator. + + The data is not copied. The caller must be able to guarantee that \a data + will not be deleted or modified. +*/ +bool QTranslator::load(const uchar *data, int len) +{ + Q_D(QTranslator); + d->clear(); + return d->do_load(data, len); +} + +static quint8 read8(const uchar *data) +{ + return *data; +} + +static quint16 read16(const uchar *data) +{ + return (data[0] << 8) | (data[1]); +} + +static quint32 read32(const uchar *data) +{ + return (data[0] << 24) + | (data[1] << 16) + | (data[2] << 8) + | (data[3]); +} + +bool QTranslatorPrivate::do_load(const uchar *data, int len) +{ + if (!data || len < MagicLength || memcmp(data, magic, MagicLength)) + return false; + + bool ok = true; + const uchar *end = data + len; + + data += MagicLength; + + while (data < end - 4) { + quint8 tag = read8(data++); + quint32 blockLen = read32(data); + data += 4; + if (!tag || !blockLen) + break; + if (data + blockLen > end) { + ok = false; + break; + } + + if (tag == QTranslatorPrivate::Contexts) { + contextArray = data; + contextLength = blockLen; + } else if (tag == QTranslatorPrivate::Hashes) { + offsetArray = data; + offsetLength = blockLen; + } else if (tag == QTranslatorPrivate::Messages) { + messageArray = data; + messageLength = blockLen; + } else if (tag == QTranslatorPrivate::NumerusRules) { + numerusRulesArray = data; + numerusRulesLength = blockLen; + } + + data += blockLen; + } + + return ok; +} + +static QString getMessage(const uchar *m, const uchar *end, const char *context, + const char *sourceText, const char *comment, int numerus) +{ + const uchar *tn = 0; + uint tn_length = 0; + int currentNumerus = -1; + + for (;;) { + uchar tag = 0; + if (m < end) + tag = read8(m++); + switch((Tag)tag) { + case Tag_End: + goto end; + case Tag_Translation: { + int len = read32(m); + if (len % 1) + return QString(); + m += 4; + if (++currentNumerus == numerus) { + tn_length = len; + tn = m; + } + m += len; + break; + } + case Tag_Obsolete1: + m += 4; + break; + case Tag_SourceText: { + quint32 len = read32(m); + m += 4; + if (!match(m, sourceText, len)) + return QString(); + m += len; + } + break; + case Tag_Context: { + quint32 len = read32(m); + m += 4; + if (!match(m, context, len)) + return QString(); + m += len; + } + break; + case Tag_Comment: { + quint32 len = read32(m); + m += 4; + if (*m && !match(m, comment, len)) + return QString(); + m += len; + } + break; + default: + return QString(); + } + } +end: + if (!tn) + return QString(); + QString str = QString::fromUtf16((const ushort *)tn, tn_length/2); + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { + for (int i = 0; i < str.length(); ++i) + str[i] = QChar((str.at(i).unicode() >> 8) + ((str.at(i).unicode() << 8) & 0xff00)); + } + return str; +} + +QString QTranslatorPrivate::do_translate(const char *context, const char *sourceText, + const char *comment, int n) const +{ + if (context == 0) + context = ""; + if (sourceText == 0) + sourceText = ""; + if (comment == 0) + comment = ""; + + if (!offsetLength) + return QString(); + + /* + Check if the context belongs to this QTranslator. If many + translators are installed, this step is necessary. + */ + if (contextLength) { + quint16 hTableSize = read16(contextArray); + uint g = elfHash(context) % hTableSize; + const uchar *c = contextArray + 2 + (g << 1); + quint16 off = read16(c); + c += 2; + if (off == 0) + return QString(); + c = contextArray + (2 + (hTableSize << 1) + (off << 1)); + + for (;;) { + quint8 len = read8(c++); + if (len == 0) + return QString(); + if (match(c, context, len)) + break; + c += len; + } + } + + size_t numItems = offsetLength / (2 * sizeof(quint32)); + if (!numItems) + return QString(); + + int numerus = 0; + if (n >= 0) + numerus = numerusHelper(n, numerusRulesArray, numerusRulesLength); + + for (;;) { + quint32 h = elfHash(QByteArray(sourceText) + comment); + + const uchar *start = offsetArray; + const uchar *end = start + ((numItems-1) << 3); + while (start <= end) { + const uchar *middle = start + (((end - start) >> 4) << 3); + uint hash = read32(middle); + if (h == hash) { + start = middle; + break; + } else if (hash < h) { + start = middle + 8; + } else { + end = middle - 8; + } + } + + if (start <= end) { + // go back on equal key + while (start != offsetArray && read32(start) == read32(start-8)) + start -= 8; + + while (start < offsetArray + offsetLength) { + quint32 rh = read32(start); + start += 4; + if (rh != h) + break; + quint32 ro = read32(start); + start += 4; + QString tn = getMessage(messageArray + ro, messageArray + messageLength, context, + sourceText, comment, numerus); + if (!tn.isNull()) + return tn; + } + } + if (!comment[0]) + break; + comment = ""; + } + return QString(); +} + +/*! + Empties this translator of all contents. + + This function works with stripped translator files. +*/ + +void QTranslatorPrivate::clear() +{ + Q_Q(QTranslator); + if (unmapPointer && unmapLength) { +#if defined(QT_USE_MMAP) + if (used_mmap) + munmap(unmapPointer, unmapLength); + else +#endif + delete [] unmapPointer; + } + + unmapPointer = 0; + unmapLength = 0; + messageArray = 0; + contextArray = 0; + offsetArray = 0; + numerusRulesArray = 0; + messageLength = 0; + contextLength = 0; + offsetLength = 0; + numerusRulesLength = 0; + + if (QCoreApplicationPrivate::isTranslatorInstalled(q)) + QCoreApplication::postEvent(QCoreApplication::instance(), + new QEvent(QEvent::LanguageChange)); +} + +/*! + \since 4.5 + + Returns the translation for the key (\a context, \a sourceText, + \a disambiguation). If none is found, also tries (\a context, \a + sourceText, ""). If that still fails, returns an empty string. + + If you need to programatically insert translations in to a + QTranslator, this function can be reimplemented. + + \sa load() +*/ +QString QTranslator::translate(const char *context, const char *sourceText, const char *disambiguation) const +{ + Q_D(const QTranslator); + return d->do_translate(context, sourceText, disambiguation, -1); +} + + +/*! + \overload translate() + + Returns the translation for the key (\a context, \a sourceText, + \a disambiguation). If none is found, also tries (\a context, \a + sourceText, ""). If that still fails, returns an empty string. + + If \a n is not -1, it is used to choose an appropriate form for + the translation (e.g. "%n file found" vs. "%n files found"). + + \sa load() +*/ +QString QTranslator::translate(const char *context, const char *sourceText, const char *disambiguation, + int n) const +{ + Q_D(const QTranslator); + // this step is necessary because the 3-parameter translate() overload is virtual + if (n == -1) + return translate(context, sourceText, disambiguation); + return d->do_translate(context, sourceText, disambiguation, n); +} + +/*! + Returns true if this translator is empty, otherwise returns false. + This function works with stripped and unstripped translation files. +*/ +bool QTranslator::isEmpty() const +{ + Q_D(const QTranslator); + return !d->unmapPointer && !d->unmapLength && !d->messageArray && + !d->offsetArray && !d->contextArray; +} + +/*! + \fn QString QTranslator::find(const char *context, const char *sourceText, const char * comment = 0) const + + Use translate(\a context, \a sourceText, \a comment) instead. +*/ + +#endif // QT_NO_TRANSLATION + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qtranslator.h b/src/corelib/kernel/qtranslator.h new file mode 100644 index 0000000..08eb994 --- /dev/null +++ b/src/corelib/kernel/qtranslator.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTRANSLATOR_H +#define QTRANSLATOR_H + +#include <QtCore/qobject.h> +#include <QtCore/qbytearray.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_TRANSLATION + +class QTranslatorPrivate; + +class Q_CORE_EXPORT QTranslator : public QObject +{ + Q_OBJECT +public: + explicit QTranslator(QObject *parent = 0); +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QTranslator(QObject * parent, const char * name); +#endif + ~QTranslator(); + + // ### Qt 5: Merge (with "int n = -1") + virtual QString translate(const char *context, const char *sourceText, + const char *disambiguation = 0) const; + QString translate(const char *context, const char *sourceText, const char *disambiguation, + int n) const; + + virtual bool isEmpty() const; + + bool load(const QString & filename, + const QString & directory = QString(), + const QString & search_delimiters = QString(), + const QString & suffix = QString()); + bool load(const uchar *data, int len); + +#ifdef QT3_SUPPORT + QT3_SUPPORT QString find(const char *context, const char *sourceText, const char * comment = 0) const + { return translate(context, sourceText, comment); } +#endif + +private: + Q_DISABLE_COPY(QTranslator) + Q_DECLARE_PRIVATE(QTranslator) +}; + +#endif // QT_NO_TRANSLATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QTRANSLATOR_H diff --git a/src/corelib/kernel/qtranslator_p.h b/src/corelib/kernel/qtranslator_p.h new file mode 100644 index 0000000..77ec8f5 --- /dev/null +++ b/src/corelib/kernel/qtranslator_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTRANSLATOR_P_H +#define QTRANSLATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qfontencodings_x11.cpp and qfont_x11.cpp. This header file may +// change from version to version without notice, or even be removed. +// +// We mean it. +// + +enum { + Q_EQ = 0x01, + Q_LT = 0x02, + Q_LEQ = 0x03, + Q_BETWEEN = 0x04, + + Q_NOT = 0x08, + Q_MOD_10 = 0x10, + Q_MOD_100 = 0x20, + + Q_AND = 0xFD, + Q_OR = 0xFE, + Q_NEWRULE = 0xFF, + + Q_OP_MASK = 0x07, + + Q_NEQ = Q_NOT | Q_EQ, + Q_GT = Q_NOT | Q_LEQ, + Q_GEQ = Q_NOT | Q_LT, + Q_NOT_BETWEEN = Q_NOT | Q_BETWEEN +}; + +#endif diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp new file mode 100644 index 0000000..b4427c0 --- /dev/null +++ b/src/corelib/kernel/qvariant.cpp @@ -0,0 +1,3098 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvariant.h" +#include "qbitarray.h" +#include "qbytearray.h" +#include "qdatastream.h" +#include "qdebug.h" +#include "qmap.h" +#include "qdatetime.h" +#include "qlist.h" +#include "qstring.h" +#include "qstringlist.h" +#include "qurl.h" +#include "qlocale.h" +#include "private/qvariant_p.h" + +#ifndef QT_NO_GEOM_VARIANT +#include "qsize.h" +#include "qpoint.h" +#include "qrect.h" +#include "qline.h" +#endif + +#include <float.h> + +QT_BEGIN_NAMESPACE + +#ifndef DBL_DIG +# define DBL_DIG 10 +#endif +#ifndef FLT_DIG +# define FLT_DIG 6 +#endif + + +static const void *constDataHelper(const QVariant::Private &d) +{ + switch (d.type) { + case QVariant::Int: + return &d.data.i; + case QVariant::UInt: + return &d.data.u; + case QVariant::Bool: + return &d.data.b; + case QVariant::LongLong: + return &d.data.ll; + case QVariant::ULongLong: + return &d.data.ull; + case QVariant::Double: + return &d.data.d; + default: + return d.is_shared ? d.data.shared->ptr : reinterpret_cast<const void *>(&d.data.ptr); + } +} + +static void construct(QVariant::Private *x, const void *copy) +{ + x->is_shared = false; + + switch (x->type) { + case QVariant::String: + v_construct<QString>(x, copy); + break; + case QVariant::Char: + v_construct<QChar>(x, copy); + break; + case QVariant::StringList: + v_construct<QStringList>(x, copy); + break; + case QVariant::Map: + v_construct<QVariantMap>(x, copy); + break; + case QVariant::Hash: + v_construct<QVariantHash>(x, copy); + break; + case QVariant::List: + v_construct<QVariantList>(x, copy); + break; + case QVariant::Date: + v_construct<QDate>(x, copy); + break; + case QVariant::Time: + v_construct<QTime>(x, copy); + break; + case QVariant::DateTime: + v_construct<QDateTime>(x, copy); + break; + case QVariant::ByteArray: + v_construct<QByteArray>(x, copy); + break; + case QVariant::BitArray: + v_construct<QBitArray>(x, copy); + break; +#ifndef QT_NO_GEOM_VARIANT + case QVariant::Size: + v_construct<QSize>(x, copy); + break; + case QVariant::SizeF: + v_construct<QSizeF>(x, copy); + break; + case QVariant::Rect: + v_construct<QRect>(x, copy); + break; + case QVariant::LineF: + v_construct<QLineF>(x, copy); + break; + case QVariant::Line: + v_construct<QLine>(x, copy); + break; + case QVariant::RectF: + v_construct<QRectF>(x, copy); + break; + case QVariant::Point: + v_construct<QPoint>(x, copy); + break; + case QVariant::PointF: + v_construct<QPointF>(x, copy); + break; +#endif + case QVariant::Url: + v_construct<QUrl>(x, copy); + break; + case QVariant::Locale: + v_construct<QLocale>(x, copy); + break; +#ifndef QT_NO_REGEXP + case QVariant::RegExp: + v_construct<QRegExp>(x, copy); + break; +#endif + case QVariant::Int: + x->data.i = copy ? *static_cast<const int *>(copy) : 0; + break; + case QVariant::UInt: + x->data.u = copy ? *static_cast<const uint *>(copy) : 0u; + break; + case QVariant::Bool: + x->data.b = copy ? *static_cast<const bool *>(copy) : false; + break; + case QVariant::Double: + x->data.d = copy ? *static_cast<const double*>(copy) : 0.0; + break; + case QVariant::LongLong: + x->data.ll = copy ? *static_cast<const qlonglong *>(copy) : Q_INT64_C(0); + break; + case QVariant::ULongLong: + x->data.ull = copy ? *static_cast<const qulonglong *>(copy) : Q_UINT64_C(0); + break; + case QVariant::Invalid: + case QVariant::UserType: + break; + default: + x->is_shared = true; + x->data.shared = new QVariant::PrivateShared(QMetaType::construct(x->type, copy)); + if (!x->data.shared->ptr) + x->type = QVariant::Invalid; + break; + } + x->is_null = !copy; +} + +static void clear(QVariant::Private *d) +{ + switch (d->type) { + case QVariant::String: + v_clear<QString>(d); + break; + case QVariant::Char: + v_clear<QChar>(d); + break; + case QVariant::StringList: + v_clear<QStringList>(d); + break; + case QVariant::Map: + v_clear<QVariantMap>(d); + break; + case QVariant::Hash: + v_clear<QVariantHash>(d); + break; + case QVariant::List: + v_clear<QVariantList>(d); + break; + case QVariant::Date: + v_clear<QDate>(d); + break; + case QVariant::Time: + v_clear<QTime>(d); + break; + case QVariant::DateTime: + v_clear<QDateTime>(d); + break; + case QVariant::ByteArray: + v_clear<QByteArray>(d); + break; + case QVariant::BitArray: + v_clear<QBitArray>(d); + break; +#ifndef QT_NO_GEOM_VARIANT + case QVariant::Point: + v_clear<QPoint>(d); + break; + case QVariant::PointF: + v_clear<QPointF>(d); + break; + case QVariant::Size: + v_clear<QSize>(d); + break; + case QVariant::SizeF: + v_clear<QSizeF>(d); + break; + case QVariant::Rect: + v_clear<QRect>(d); + break; + case QVariant::LineF: + v_clear<QLineF>(d); + break; + case QVariant::Line: + v_clear<QLine>(d); + break; + case QVariant::RectF: + v_clear<QRectF>(d); + break; +#endif + case QVariant::Url: + v_clear<QUrl>(d); + break; + case QVariant::Locale: + v_clear<QLocale>(d); + break; +#ifndef QT_NO_REGEXP + case QVariant::RegExp: + v_clear<QRegExp>(d); + break; +#endif + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Double: + break; + case QVariant::Invalid: + case QVariant::UserType: + case QVariant::Int: + case QVariant::UInt: + case QVariant::Bool: + break; + default: + QMetaType::destroy(d->type, d->data.shared->ptr); + delete d->data.shared; + break; + } + + d->type = QVariant::Invalid; + d->is_null = true; + d->is_shared = false; +} + +static bool isNull(const QVariant::Private *d) +{ + switch(d->type) { + case QVariant::String: + return v_cast<QString>(d)->isNull(); + case QVariant::Char: + return v_cast<QChar>(d)->isNull(); + case QVariant::Date: + return v_cast<QDate>(d)->isNull(); + case QVariant::Time: + return v_cast<QTime>(d)->isNull(); + case QVariant::DateTime: + return v_cast<QDateTime>(d)->isNull(); + case QVariant::ByteArray: + return v_cast<QByteArray>(d)->isNull(); + case QVariant::BitArray: + return v_cast<QBitArray>(d)->isNull(); +#ifndef QT_NO_GEOM_VARIANT + case QVariant::Size: + return v_cast<QSize>(d)->isNull(); + case QVariant::SizeF: + return v_cast<QSizeF>(d)->isNull(); + case QVariant::Rect: + return v_cast<QRect>(d)->isNull(); + case QVariant::Line: + return v_cast<QLine>(d)->isNull(); + case QVariant::LineF: + return v_cast<QLineF>(d)->isNull(); + case QVariant::RectF: + return v_cast<QRectF>(d)->isNull(); + case QVariant::Point: + return v_cast<QPoint>(d)->isNull(); + case QVariant::PointF: + return v_cast<QPointF>(d)->isNull(); +#endif + case QVariant::Url: + case QVariant::Locale: + case QVariant::RegExp: + case QVariant::StringList: + case QVariant::Map: + case QVariant::Hash: + case QVariant::List: + case QVariant::Invalid: + case QVariant::UserType: + case QVariant::Int: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Bool: + case QVariant::Double: + break; + } + return d->is_null; +} + +/* + \internal + \since 4.4 + + We cannot use v_cast() for QMetaType's numeric types because they're smaller than QVariant::Private::Data, + which in turns makes v_cast() believe the value is stored in d->data.c. But + it's not, since we're a QMetaType type. + */ +template<typename T> +inline bool compareNumericMetaType(const QVariant::Private *const a, const QVariant::Private *const b) +{ + return *static_cast<const T *>(a->data.shared->ptr) == *static_cast<const T *>(b->data.shared->ptr); +} + +/*! + \internal + + Compares \a a to \a b. The caller guarantees that \a a and \a b + are of the same type. + */ +static bool compare(const QVariant::Private *a, const QVariant::Private *b) +{ + switch(a->type) { + case QVariant::List: + return *v_cast<QVariantList>(a) == *v_cast<QVariantList>(b); + case QVariant::Map: { + const QVariantMap *m1 = v_cast<QVariantMap>(a); + const QVariantMap *m2 = v_cast<QVariantMap>(b); + if (m1->count() != m2->count()) + return false; + QVariantMap::ConstIterator it = m1->constBegin(); + QVariantMap::ConstIterator it2 = m2->constBegin(); + while (it != m1->constEnd()) { + if (*it != *it2 || it.key() != it2.key()) + return false; + ++it; + ++it2; + } + return true; + } + case QVariant::Hash: + return *v_cast<QVariantHash>(a) == *v_cast<QVariantHash>(b); + case QVariant::String: + return *v_cast<QString>(a) == *v_cast<QString>(b); + case QVariant::Char: + return *v_cast<QChar>(a) == *v_cast<QChar>(b); + case QVariant::StringList: + return *v_cast<QStringList>(a) == *v_cast<QStringList>(b); +#ifndef QT_NO_GEOM_VARIANT + case QVariant::Size: + return *v_cast<QSize>(a) == *v_cast<QSize>(b); + case QVariant::SizeF: + return *v_cast<QSizeF>(a) == *v_cast<QSizeF>(b); + case QVariant::Rect: + return *v_cast<QRect>(a) == *v_cast<QRect>(b); + case QVariant::Line: + return *v_cast<QLine>(a) == *v_cast<QLine>(b); + case QVariant::LineF: + return *v_cast<QLineF>(a) == *v_cast<QLineF>(b); + case QVariant::RectF: + return *v_cast<QRectF>(a) == *v_cast<QRectF>(b); + case QVariant::Point: + return *v_cast<QPoint>(a) == *v_cast<QPoint>(b); + case QVariant::PointF: + return *v_cast<QPointF>(a) == *v_cast<QPointF>(b); +#endif + case QVariant::Url: + return *v_cast<QUrl>(a) == *v_cast<QUrl>(b); + case QVariant::Locale: + return *v_cast<QLocale>(a) == *v_cast<QLocale>(b); +#ifndef QT_NO_REGEXP + case QVariant::RegExp: + return *v_cast<QRegExp>(a) == *v_cast<QRegExp>(b); +#endif + case QVariant::Int: + return a->data.i == b->data.i; + case QVariant::UInt: + return a->data.u == b->data.u; + case QVariant::LongLong: + return a->data.ll == b->data.ll; + case QVariant::ULongLong: + return a->data.ull == b->data.ull; + case QVariant::Bool: + return a->data.b == b->data.b; + case QVariant::Double: + return a->data.d == b->data.d; + case QVariant::Date: + return *v_cast<QDate>(a) == *v_cast<QDate>(b); + case QVariant::Time: + return *v_cast<QTime>(a) == *v_cast<QTime>(b); + case QVariant::DateTime: + return *v_cast<QDateTime>(a) == *v_cast<QDateTime>(b); + case QVariant::ByteArray: + return *v_cast<QByteArray>(a) == *v_cast<QByteArray>(b); + case QVariant::BitArray: + return *v_cast<QBitArray>(a) == *v_cast<QBitArray>(b); + case QVariant::Invalid: + return true; + case QMetaType::Long: + return compareNumericMetaType<long>(a, b); + case QMetaType::ULong: + return compareNumericMetaType<ulong>(a, b); + case QMetaType::Short: + return compareNumericMetaType<short>(a, b); + case QMetaType::UShort: + return compareNumericMetaType<ushort>(a, b); + case QMetaType::UChar: + return compareNumericMetaType<uchar>(a, b); + case QMetaType::Char: + return compareNumericMetaType<char>(a, b); + default: + break; + } + if (!QMetaType::isRegistered(a->type)) + qFatal("QVariant::compare: type %d unknown to QVariant.", a->type); + + /* The reason we cannot place this test in a case branch above for the types + * QMetaType::VoidStar, QMetaType::QObjectStar and so forth, is that it wouldn't include + * user defined pointer types. */ + const char *const typeName = QMetaType::typeName(a->type); + if (typeName[qstrlen(typeName) - 1] == '*') + return *static_cast<void **>(a->data.shared->ptr) == + *static_cast<void **>(b->data.shared->ptr); + + return a->data.shared->ptr == b->data.shared->ptr; +} + +/*! + \internal + */ +static qlonglong qMetaTypeNumber(const QVariant::Private *d) +{ + switch (d->type) { + case QMetaType::Int: + return d->data.i; + case QMetaType::LongLong: + return d->data.ll; + case QMetaType::Char: + return qlonglong(*static_cast<signed char *>(d->data.shared->ptr)); + case QMetaType::Short: + return qlonglong(*static_cast<short *>(d->data.shared->ptr)); + case QMetaType::Long: + return qlonglong(*static_cast<long *>(d->data.shared->ptr)); + case QMetaType::Float: + return qRound64(*static_cast<float *>(d->data.shared->ptr)); + case QVariant::Double: + return qRound64(d->data.d); + } + Q_ASSERT(false); + return 0; +} + +static qulonglong qMetaTypeUNumber(const QVariant::Private *d) +{ + switch (d->type) { + case QVariant::UInt: + return d->data.u; + case QVariant::ULongLong: + return d->data.ull; + case QMetaType::UChar: + return qulonglong(*static_cast<unsigned char *>(d->data.shared->ptr)); + case QMetaType::UShort: + return qulonglong(*static_cast<ushort *>(d->data.shared->ptr)); + case QMetaType::ULong: + return qulonglong(*static_cast<ulong *>(d->data.shared->ptr)); + } + Q_ASSERT(false); + return 0; +} + +static qlonglong qConvertToNumber(const QVariant::Private *d, bool *ok) +{ + *ok = true; + + switch (uint(d->type)) { + case QVariant::String: + return v_cast<QString>(d)->toLongLong(ok); + case QVariant::Char: + return v_cast<QChar>(d)->unicode(); + case QVariant::ByteArray: + return v_cast<QByteArray>(d)->toLongLong(ok); + case QVariant::Bool: + return qlonglong(d->data.b); + case QVariant::Double: + case QVariant::Int: + case QMetaType::Char: + case QMetaType::Short: + case QMetaType::Long: + case QMetaType::Float: + case QMetaType::LongLong: + return qMetaTypeNumber(d); + case QVariant::ULongLong: + case QVariant::UInt: + case QMetaType::UChar: + case QMetaType::UShort: + case QMetaType::ULong: + return qlonglong(qMetaTypeUNumber(d)); + } + + *ok = false; + return Q_INT64_C(0); +} + +static qulonglong qConvertToUnsignedNumber(const QVariant::Private *d, bool *ok) +{ + *ok = true; + + switch (uint(d->type)) { + case QVariant::String: + return v_cast<QString>(d)->toULongLong(ok); + case QVariant::Char: + return v_cast<QChar>(d)->unicode(); + case QVariant::ByteArray: + return v_cast<QByteArray>(d)->toULongLong(ok); + case QVariant::Bool: + return qulonglong(d->data.b); + case QVariant::Double: + case QVariant::Int: + case QMetaType::Char: + case QMetaType::Short: + case QMetaType::Long: + case QMetaType::Float: + case QMetaType::LongLong: + return qulonglong(qMetaTypeNumber(d)); + case QVariant::ULongLong: + case QVariant::UInt: + case QMetaType::UChar: + case QMetaType::UShort: + case QMetaType::ULong: + return qMetaTypeUNumber(d); + } + + *ok = false; + return Q_UINT64_C(0); +} + +template<typename TInput, typename LiteralWrapper> +inline bool qt_convertToBool(const QVariant::Private *const d) +{ + TInput str = v_cast<TInput>(d)->toLower(); + return !(str == LiteralWrapper("0") || str == LiteralWrapper("false") || str.isEmpty()); +} + +/*! + \internal + + Converts \a d to type \a t, which is placed in \a result. + */ +static bool convert(const QVariant::Private *d, QVariant::Type t, void *result, bool *ok) +{ + Q_ASSERT(d->type != uint(t)); + Q_ASSERT(result); + + bool dummy; + if (!ok) + ok = &dummy; + + switch (uint(t)) { + case QVariant::String: { + QString *str = static_cast<QString *>(result); + switch (d->type) { + case QVariant::Char: + *str = QString(*v_cast<QChar>(d)); + break; + case QMetaType::Char: + case QMetaType::UChar: + *str = QChar::fromAscii(*static_cast<char *>(d->data.shared->ptr)); + break; + case QMetaType::Short: + case QMetaType::Long: + case QVariant::Int: + case QVariant::LongLong: + *str = QString::number(qMetaTypeNumber(d)); + break; + case QVariant::UInt: + case QVariant::ULongLong: + case QMetaType::UShort: + case QMetaType::ULong: + *str = QString::number(qMetaTypeUNumber(d)); + break; + case QMetaType::Float: + *str = QString::number(*static_cast<float *>(d->data.shared->ptr), 'g', FLT_DIG); + break; + case QVariant::Double: + *str = QString::number(d->data.d, 'g', DBL_DIG); + break; +#if !defined(QT_NO_DATESTRING) + case QVariant::Date: + *str = v_cast<QDate>(d)->toString(Qt::ISODate); + break; + case QVariant::Time: + *str = v_cast<QTime>(d)->toString(Qt::ISODate); + break; + case QVariant::DateTime: + *str = v_cast<QDateTime>(d)->toString(Qt::ISODate); + break; +#endif + case QVariant::Bool: + *str = QLatin1String(d->data.b ? "true" : "false"); + break; + case QVariant::ByteArray: + *str = QString::fromAscii(v_cast<QByteArray>(d)->constData()); + break; + case QVariant::StringList: + if (v_cast<QStringList>(d)->count() == 1) + *str = v_cast<QStringList>(d)->at(0); + break; + default: + return false; + } + break; + } + case QVariant::Char: { + QChar *c = static_cast<QChar *>(result); + switch (d->type) { + case QVariant::Int: + case QVariant::LongLong: + case QMetaType::Char: + case QMetaType::Short: + case QMetaType::Long: + case QMetaType::Float: + *c = QChar(ushort(qMetaTypeNumber(d))); + break; + case QVariant::UInt: + case QVariant::ULongLong: + case QMetaType::UChar: + case QMetaType::UShort: + case QMetaType::ULong: + *c = QChar(ushort(qMetaTypeUNumber(d))); + break; + default: + return false; + } + break; + } +#ifndef QT_NO_GEOM_VARIANT + case QVariant::Size: { + QSize *s = static_cast<QSize *>(result); + switch (d->type) { + case QVariant::SizeF: + *s = v_cast<QSizeF>(d)->toSize(); + break; + default: + return false; + } + break; + } + + case QVariant::SizeF: { + QSizeF *s = static_cast<QSizeF *>(result); + switch (d->type) { + case QVariant::Size: + *s = QSizeF(*(v_cast<QSize>(d))); + break; + default: + return false; + } + break; + } + + case QVariant::Line: { + QLine *s = static_cast<QLine *>(result); + switch (d->type) { + case QVariant::LineF: + *s = v_cast<QLineF>(d)->toLine(); + break; + default: + return false; + } + break; + } + + case QVariant::LineF: { + QLineF *s = static_cast<QLineF *>(result); + switch (d->type) { + case QVariant::Line: + *s = QLineF(*(v_cast<QLine>(d))); + break; + default: + return false; + } + break; + } +#endif + case QVariant::StringList: + if (d->type == QVariant::List) { + QStringList *slst = static_cast<QStringList *>(result); + const QVariantList *list = v_cast<QVariantList >(d); + for (int i = 0; i < list->size(); ++i) + slst->append(list->at(i).toString()); + } else if (d->type == QVariant::String) { + QStringList *slst = static_cast<QStringList *>(result); + *slst = QStringList(*v_cast<QString>(d)); + } else { + return false; + } + break; + case QVariant::Date: { + QDate *dt = static_cast<QDate *>(result); + if (d->type == QVariant::DateTime) + *dt = v_cast<QDateTime>(d)->date(); +#ifndef QT_NO_DATESTRING + else if (d->type == QVariant::String) + *dt = QDate::fromString(*v_cast<QString>(d), Qt::ISODate); +#endif + else + return false; + + return dt->isValid(); + } + case QVariant::Time: { + QTime *t = static_cast<QTime *>(result); + switch (d->type) { + case QVariant::DateTime: + *t = v_cast<QDateTime>(d)->time(); + break; +#ifndef QT_NO_DATESTRING + case QVariant::String: + *t = QTime::fromString(*v_cast<QString>(d), Qt::ISODate); + break; +#endif + default: + return false; + } + return t->isValid(); + } + case QVariant::DateTime: { + QDateTime *dt = static_cast<QDateTime *>(result); + switch (d->type) { +#ifndef QT_NO_DATESTRING + case QVariant::String: + *dt = QDateTime::fromString(*v_cast<QString>(d), Qt::ISODate); + break; +#endif + case QVariant::Date: + *dt = QDateTime(*v_cast<QDate>(d)); + break; + default: + return false; + } + return dt->isValid(); + } + case QVariant::ByteArray: { + QByteArray *ba = static_cast<QByteArray *>(result); + switch (d->type) { + case QVariant::String: + *ba = v_cast<QString>(d)->toAscii(); + break; + case QVariant::Double: + *ba = QByteArray::number(d->data.d, 'g', DBL_DIG); + break; + case QMetaType::Float: + *ba = QByteArray::number(*static_cast<float *>(d->data.shared->ptr), 'g', FLT_DIG); + break; + case QMetaType::Char: + case QMetaType::UChar: + *ba = QByteArray(1, *static_cast<char *>(d->data.shared->ptr)); + break; + case QVariant::Int: + case QVariant::LongLong: + case QMetaType::Short: + case QMetaType::Long: + *ba = QByteArray::number(qMetaTypeNumber(d)); + break; + case QVariant::UInt: + case QVariant::ULongLong: + case QMetaType::UShort: + case QMetaType::ULong: + *ba = QByteArray::number(qMetaTypeUNumber(d)); + break; + case QVariant::Bool: + *ba = QByteArray(d->data.b ? "true" : "false"); + break; + default: + return false; + } + } + break; + case QMetaType::Short: + *static_cast<short *>(result) = short(qConvertToNumber(d, ok)); + return *ok; + case QMetaType::Long: + *static_cast<long *>(result) = long(qConvertToNumber(d, ok)); + return *ok; + case QMetaType::UShort: + *static_cast<ushort *>(result) = ushort(qConvertToUnsignedNumber(d, ok)); + return *ok; + case QMetaType::ULong: + *static_cast<ulong *>(result) = ulong(qConvertToUnsignedNumber(d, ok)); + return *ok; + case QVariant::Int: + *static_cast<int *>(result) = int(qConvertToNumber(d, ok)); + return *ok; + case QVariant::UInt: + *static_cast<uint *>(result) = uint(qConvertToUnsignedNumber(d, ok)); + return *ok; + case QVariant::LongLong: + *static_cast<qlonglong *>(result) = qConvertToNumber(d, ok); + return *ok; + case QVariant::ULongLong: { + *static_cast<qulonglong *>(result) = qConvertToUnsignedNumber(d, ok); + return *ok; + } + case QMetaType::UChar: { + *static_cast<uchar *>(result) = qConvertToUnsignedNumber(d, ok); + return *ok; + } + case QVariant::Bool: { + bool *b = static_cast<bool *>(result); + switch(d->type) { + case QVariant::ByteArray: + *b = qt_convertToBool<QByteArray, QByteArray>(d); + break; + case QVariant::String: + *b = qt_convertToBool<QString, QLatin1String>(d); + break; + case QVariant::Char: + *b = !v_cast<QChar>(d)->isNull(); + break; + case QVariant::Double: + case QVariant::Int: + case QVariant::LongLong: + case QMetaType::Char: + case QMetaType::Short: + case QMetaType::Long: + case QMetaType::Float: + *b = qMetaTypeNumber(d) != Q_INT64_C(0); + break; + case QVariant::UInt: + case QVariant::ULongLong: + case QMetaType::UChar: + case QMetaType::UShort: + case QMetaType::ULong: + *b = qMetaTypeUNumber(d) != Q_UINT64_C(0); + break; + default: + *b = false; + return false; + } + break; + } + case QVariant::Double: { + double *f = static_cast<double *>(result); + switch (d->type) { + case QVariant::String: + *f = v_cast<QString>(d)->toDouble(ok); + break; + case QVariant::ByteArray: + *f = v_cast<QByteArray>(d)->toDouble(ok); + break; + case QVariant::Bool: + *f = double(d->data.b); + break; + case QMetaType::Float: + *f = *static_cast<float *>(d->data.shared->ptr); + break; + case QVariant::LongLong: + case QVariant::Int: + case QMetaType::Char: + case QMetaType::Short: + case QMetaType::Long: + *f = double(qMetaTypeNumber(d)); + break; + case QVariant::UInt: + case QVariant::ULongLong: + case QMetaType::UChar: + case QMetaType::UShort: + case QMetaType::ULong: +#if defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET) + *f = (double)(qlonglong)qMetaTypeUNumber(d); +#else + *f = double(qMetaTypeUNumber(d)); +#endif + break; + default: + *f = 0.0; + return false; + } + break; + } + case QMetaType::Float: { + float *f = static_cast<float *>(result); + switch (d->type) { + case QVariant::String: + *f = float(v_cast<QString>(d)->toDouble(ok)); + break; + case QVariant::ByteArray: + *f = float(v_cast<QByteArray>(d)->toDouble(ok)); + break; + case QVariant::Bool: + *f = float(d->data.b); + break; + case QVariant::Double: + *f = float(d->data.d); + break; + case QVariant::LongLong: + case QVariant::Int: + case QMetaType::Char: + case QMetaType::Short: + case QMetaType::Long: + *f = float(qMetaTypeNumber(d)); + break; + case QVariant::UInt: + case QVariant::ULongLong: + case QMetaType::UChar: + case QMetaType::UShort: + case QMetaType::ULong: +#if defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET) + *f = (float)(qlonglong)qMetaTypeUNumber(d); +#else + *f = float(qMetaTypeUNumber(d)); +#endif + break; + default: + *f = 0.0f; + return false; + } + break; + } + case QVariant::List: + if (d->type == QVariant::StringList) { + QVariantList *lst = static_cast<QVariantList *>(result); + const QStringList *slist = v_cast<QStringList>(d); + for (int i = 0; i < slist->size(); ++i) + lst->append(QVariant(slist->at(i))); + } else if (qstrcmp(QMetaType::typeName(d->type), "QList<QVariant>") == 0) { + *static_cast<QVariantList *>(result) = + *static_cast<QList<QVariant> *>(d->data.shared->ptr); + } else { + return false; + } + break; + case QVariant::Map: + if (qstrcmp(QMetaType::typeName(d->type), "QMap<QString, QVariant>") == 0) { + *static_cast<QVariantMap *>(result) = + *static_cast<QMap<QString, QVariant> *>(d->data.shared->ptr); + } else { + return false; + } + break; + case QVariant::Hash: + if (qstrcmp(QMetaType::typeName(d->type), "QHash<QString, QVariant>") == 0) { + *static_cast<QVariantHash *>(result) = + *static_cast<QHash<QString, QVariant> *>(d->data.shared->ptr); + } else { + return false; + } + break; +#ifndef QT_NO_GEOM_VARIANT + case QVariant::Rect: + if (d->type == QVariant::RectF) + *static_cast<QRect *>(result) = (v_cast<QRectF>(d))->toRect(); + else + return false; + break; + case QVariant::RectF: + if (d->type == QVariant::Rect) + *static_cast<QRectF *>(result) = *v_cast<QRect>(d); + else + return false; + break; + case QVariant::PointF: + if (d->type == QVariant::Point) + *static_cast<QPointF *>(result) = *v_cast<QPoint>(d); + else + return false; + break; + case QVariant::Point: + if (d->type == QVariant::PointF) + *static_cast<QPoint *>(result) = (v_cast<QPointF>(d))->toPoint(); + else + return false; + break; + case QMetaType::Char: + { + *static_cast<qint8 *>(result) = qint8(qConvertToNumber(d, ok)); + return *ok; + } +#endif + default: + return false; + } + return true; +} + +#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) +static void streamDebug(QDebug dbg, const QVariant &v) +{ + switch (v.type()) { + case QVariant::Int: + dbg.nospace() << v.toInt(); + break; + case QVariant::UInt: + dbg.nospace() << v.toUInt(); + break; + case QVariant::LongLong: + dbg.nospace() << v.toLongLong(); + break; + case QVariant::ULongLong: + dbg.nospace() << v.toULongLong(); + break; + case QVariant::Double: + dbg.nospace() << v.toDouble(); + break; + case QVariant::Bool: + dbg.nospace() << v.toBool(); + break; + case QVariant::String: + dbg.nospace() << v.toString(); + break; + case QVariant::Char: + dbg.nospace() << v.toChar(); + break; + case QVariant::StringList: + dbg.nospace() << v.toStringList(); + break; + case QVariant::Map: + dbg.nospace() << v.toMap(); + break; + case QVariant::Hash: + dbg.nospace() << v.toHash(); + break; + case QVariant::List: + dbg.nospace() << v.toList(); + break; + case QVariant::Date: + dbg.nospace() << v.toDate(); + break; + case QVariant::Time: + dbg.nospace() << v.toTime(); + break; + case QVariant::DateTime: + dbg.nospace() << v.toDateTime(); + break; + case QVariant::ByteArray: + dbg.nospace() << v.toByteArray(); + break; + case QVariant::Url: + dbg.nospace() << v.toUrl(); + break; +#ifndef QT_NO_GEOM_VARIANT + case QVariant::Point: + dbg.nospace() << v.toPoint(); + break; + case QVariant::PointF: + dbg.nospace() << v.toPointF(); + break; + case QVariant::Rect: + dbg.nospace() << v.toRect(); + break; + case QVariant::Size: + dbg.nospace() << v.toSize(); + break; + case QVariant::SizeF: + dbg.nospace() << v.toSizeF(); + break; + case QVariant::Line: + dbg.nospace() << v.toLine(); + break; + case QVariant::LineF: + dbg.nospace() << v.toLineF(); + break; + case QVariant::RectF: + dbg.nospace() << v.toRectF(); + break; +#endif + case QVariant::BitArray: + //dbg.nospace() << v.toBitArray(); + break; + default: + break; + } +} +#endif + +const QVariant::Handler qt_kernel_variant_handler = { + construct, + clear, + isNull, +#ifndef QT_NO_DATASTREAM + 0, + 0, +#endif + compare, + convert, + 0, +#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) + streamDebug +#else + 0 +#endif +}; + +Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler() +{ + return &qt_kernel_variant_handler; +} + + +const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; + +/*! + \class QVariant + \brief The QVariant class acts like a union for the most common Qt data types. + + \ingroup objectmodel + \ingroup misc + \ingroup shared + \mainclass + + Because C++ forbids unions from including types that have + non-default constructors or destructors, most interesting Qt + classes cannot be used in unions. Without QVariant, this would be + a problem for QObject::property() and for database work, etc. + + A QVariant object holds a single value of a single type() at a + time. (Some type()s are multi-valued, for example a string list.) + You can find out what type, T, the variant holds, convert it to a + different type using convert(), get its value using one of the + toT() functions (e.g., toSize()) and check whether the type can + be converted to a particular type using canConvert(). + + The methods named toT() (e.g., toInt(), toString()) are const. If + you ask for the stored type, they return a copy of the stored + object. If you ask for a type that can be generated from the + stored type, toT() copies and converts and leaves the object + itself unchanged. If you ask for a type that cannot be generated + from the stored type, the result depends on the type; see the + function documentation for details. + + Here is some example code to demonstrate the use of QVariant: + + \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 0 + + You can even store QList<QVariant> and QMap<QString, QVariant> + values in a variant, so you can easily construct arbitrarily + complex data structures of arbitrary types. This is very powerful + and versatile, but may prove less memory and speed efficient than + storing specific types in standard data structures. + + QVariant also supports the notion of null values, where you have + a defined type with no value set. + + \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 1 + + QVariant can be extended to support other types than those + mentioned in the \l Type enum. See the \l QMetaType documentation + for details. + + \section1 A Note on GUI Types + + Because QVariant is part of the QtCore library, it cannot provide + conversion functions to data types defined in QtGui, such as + QColor, QImage, and QPixmap. In other words, there is no \c + toColor() function. Instead, you can use the QVariant::value() or + the qVariantValue() template function. For example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 2 + + The inverse conversion (e.g., from QColor to QVariant) is + automatic for all data types supported by QVariant, including + GUI-related types: + + \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 3 + + \section1 Using canConvert() and convert() Consecutively + + When using canConvert() and convert() consecutively, it is possible for + canConvert() to return true, but convert() to return false. This + is typically because canConvert() only reports the general ability of + QVariant to convert between types given suitable data; it is still + possible to supply data which cannot actually be converted. + + For example, canConvert() would return true when called on a variant + containing a string because, in principle, QVariant is able to convert + strings of numbers to integers. + However, if the string contains non-numeric characters, it cannot be + converted to an integer, and any attempt to convert it will fail. + Hence, it is important to have both functions return true for a + successful conversion. + + \sa QMetaType +*/ + +/*! + \enum QVariant::Type + + This enum type defines the types of variable that a QVariant can + contain. + + \value Invalid no type + \value BitArray a QBitArray + \value Bitmap a QBitmap + \value Bool a bool + \value Brush a QBrush + \value ByteArray a QByteArray + \value Char a QChar + \value Color a QColor + \value Cursor a QCursor + \value Date a QDate + \value DateTime a QDateTime + \value Double a double + \value Font a QFont + \value Hash a QVariantHash + \value Icon a QIcon + \value Image a QImage + \value Int an int + \value KeySequence a QKeySequence + \value Line a QLine + \value LineF a QLineF + \value List a QVariantList + \value Locale a QLocale + \value LongLong a \l qlonglong + \value Map a QVariantMap + \value Matrix a QMatrix + \value Transform a QTransform + \value Palette a QPalette + \value Pen a QPen + \value Pixmap a QPixmap + \value Point a QPoint + \value PointArray a QPointArray + \value PointF a QPointF + \value Polygon a QPolygon + \value Rect a QRect + \value RectF a QRectF + \value RegExp a QRegExp + \value Region a QRegion + \value Size a QSize + \value SizeF a QSizeF + \value SizePolicy a QSizePolicy + \value String a QString + \value StringList a QStringList + \value TextFormat a QTextFormat + \value TextLength a QTextLength + \value Time a QTime + \value UInt a \l uint + \value ULongLong a \l qulonglong + \value Url a QUrl + + \value UserType Base value for user-defined types. + + \omitvalue CString + \omitvalue ColorGroup + \omitvalue IconSet + \omitvalue LastGuiType + \omitvalue LastCoreType + \omitvalue LastType +*/ + +/*! + \fn QVariant::QVariant() + + Constructs an invalid variant. +*/ + + +/*! + \fn QVariant::QVariant(int typeOrUserType, const void *copy) + + Constructs variant of type \a typeOrUserType, and initializes with + \a copy if \a copy is not 0. + + Note that you have to pass the address of the variable you want stored. + + Usually, you never have to use this constructor, use qVariantFromValue() + instead to construct variants from the pointer types represented by + \c QMetaType::VoidStar, \c QMetaType::QObjectStar and + \c QMetaType::QWidgetStar. + + \sa qVariantFromValue(), Type +*/ + +/*! + \fn QVariant::QVariant(Type type) + + Constructs a null variant of type \a type. +*/ + + + +/*! + \fn QVariant::create(int type, const void *copy) + + \internal + + Constructs a variant private of type \a type, and initializes with \a copy if + \a copy is not 0. +*/ + +void QVariant::create(int type, const void *copy) +{ + d.type = type; + handler->construct(&d, copy); +} + +/*! + \fn QVariant::~QVariant() + + Destroys the QVariant and the contained object. + + Note that subclasses that reimplement clear() should reimplement + the destructor to call clear(). This destructor calls clear(), but + because it is the destructor, QVariant::clear() is called rather + than a subclass's clear(). +*/ + +QVariant::~QVariant() +{ + if (d.type > Char && (!d.is_shared || !d.data.shared->ref.deref())) + handler->clear(&d); +} + +/*! + \fn QVariant::QVariant(const QVariant &p) + + Constructs a copy of the variant, \a p, passed as the argument to + this constructor. +*/ + +QVariant::QVariant(const QVariant &p) + : d(p.d) +{ + if (d.is_shared) { + d.data.shared->ref.ref(); + } else if (p.d.type > Char) { + handler->construct(&d, p.constData()); + d.is_null = p.d.is_null; + } +} + +#ifndef QT_NO_DATASTREAM +/*! + Reads the variant from the data stream, \a s. +*/ +QVariant::QVariant(QDataStream &s) +{ + d.is_null = true; + s >> *this; +} +#endif //QT_NO_DATASTREAM + +/*! + \fn QVariant::QVariant(const QString &val) + + Constructs a new variant with a string value, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QLatin1String &val) + + Constructs a new variant with a string value, \a val. +*/ + +/*! + \fn QVariant::QVariant(const char *val) + + Constructs a new variant with a string value of \a val. + The variant creates a deep copy of \a val, using the encoding + set by QTextCodec::setCodecForCStrings(). + + Note that \a val is converted to a QString for storing in the + variant and QVariant::type() will return QMetaType::QString for + the variant. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. + + \sa QTextCodec::setCodecForCStrings() +*/ + +#ifndef QT_NO_CAST_FROM_ASCII +QVariant::QVariant(const char *val) +{ + QString s = QString::fromAscii(val); + create(String, &s); +} +#endif + +/*! + \fn QVariant::QVariant(const QStringList &val) + + Constructs a new variant with a string list value, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QMap<QString, QVariant> &val) + + Constructs a new variant with a map of QVariants, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QHash<QString, QVariant> &val) + + Constructs a new variant with a hash of QVariants, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QDate &val) + + Constructs a new variant with a date value, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QTime &val) + + Constructs a new variant with a time value, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QDateTime &val) + + Constructs a new variant with a date/time value, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QByteArray &val) + + Constructs a new variant with a bytearray value, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QBitArray &val) + + Constructs a new variant with a bitarray value, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QPoint &val) + + Constructs a new variant with a point value of \a val. + */ + +/*! + \fn QVariant::QVariant(const QPointF &val) + + Constructs a new variant with a point value of \a val. + */ + +/*! + \fn QVariant::QVariant(const QRectF &val) + + Constructs a new variant with a rect value of \a val. + */ + +/*! + \fn QVariant::QVariant(const QLineF &val) + + Constructs a new variant with a line value of \a val. + */ + +/*! + \fn QVariant::QVariant(const QLine &val) + + Constructs a new variant with a line value of \a val. + */ + +/*! + \fn QVariant::QVariant(const QRect &val) + + Constructs a new variant with a rect value of \a val. + */ + +/*! + \fn QVariant::QVariant(const QSize &val) + + Constructs a new variant with a size value of \a val. + */ + +/*! + \fn QVariant::QVariant(const QSizeF &val) + + Constructs a new variant with a size value of \a val. + */ + +/*! + \fn QVariant::QVariant(const QUrl &val) + + Constructs a new variant with a url value of \a val. + */ + +/*! + \fn QVariant::QVariant(int val) + + Constructs a new variant with an integer value, \a val. +*/ + +/*! + \fn QVariant::QVariant(uint val) + + Constructs a new variant with an unsigned integer value, \a val. +*/ + +/*! + \fn QVariant::QVariant(qlonglong val) + + Constructs a new variant with a long long integer value, \a val. +*/ + +/*! + \fn QVariant::QVariant(qulonglong val) + + Constructs a new variant with an unsigned long long integer value, \a val. +*/ + + +/*! + \fn QVariant::QVariant(bool val) + + Constructs a new variant with a boolean value, \a val. +*/ + +/*! + \fn QVariant::QVariant(double val) + + Constructs a new variant with a floating point value, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QList<QVariant> &val) + + Constructs a new variant with a list value, \a val. +*/ + +/*! + \fn QVariant::QVariant(const QChar &c) + + Constructs a new variant with a char value, \a c. +*/ + +/*! + \fn QVariant::QVariant(const QLocale &l) + + Constructs a new variant with a locale value, \a l. +*/ + +/*! + \fn QVariant::QVariant(const QRegExp ®Exp) + + Constructs a new variant with the regexp value \a regExp. +*/ + +/*! \since 4.2 + \fn QVariant::QVariant(Qt::GlobalColor color) + + Constructs a new variant of type QVariant::Color and initializes + it with \a color. + + This is a convenience constructor that allows \c{QVariant(Qt::blue);} + to create a valid QVariant storing a QColor. + + Note: This constructor will assert if the application does not link + to the Qt GUI library. + */ + +QVariant::QVariant(Type type) +{ create(type, 0); } +QVariant::QVariant(int typeOrUserType, const void *copy) +{ create(typeOrUserType, copy); d.is_null = false; } +QVariant::QVariant(int val) +{ d.is_null = false; d.type = Int; d.data.i = val; } +QVariant::QVariant(uint val) +{ d.is_null = false; d.type = UInt; d.data.u = val; } +QVariant::QVariant(qlonglong val) +{ d.is_null = false; d.type = LongLong; d.data.ll = val; } +QVariant::QVariant(qulonglong val) +{ d.is_null = false; d.type = ULongLong; d.data.ull = val; } +QVariant::QVariant(bool val) +{ d.is_null = false; d.type = Bool; d.data.b = val; } +QVariant::QVariant(double val) +{ d.is_null = false; d.type = Double; d.data.d = val; } + +QVariant::QVariant(const QByteArray &val) +{ create(ByteArray, &val); } +QVariant::QVariant(const QBitArray &val) +{ create(BitArray, &val); } +QVariant::QVariant(const QString &val) +{ create(String, &val); } +QVariant::QVariant(const QChar &val) +{ create (Char, &val); } +QVariant::QVariant(const QLatin1String &val) +{ QString str(val); create(String, &str); } +QVariant::QVariant(const QStringList &val) +{ create(StringList, &val); } + +QVariant::QVariant(const QDate &val) +{ create(Date, &val); } +QVariant::QVariant(const QTime &val) +{ create(Time, &val); } +QVariant::QVariant(const QDateTime &val) +{ create(DateTime, &val); } +QVariant::QVariant(const QList<QVariant> &list) +{ create(List, &list); } +QVariant::QVariant(const QMap<QString, QVariant> &map) +{ create(Map, &map); } +QVariant::QVariant(const QHash<QString, QVariant> &hash) +{ create(Hash, &hash); } +#ifndef QT_NO_GEOM_VARIANT +QVariant::QVariant(const QPoint &pt) { create(Point, &pt); } +QVariant::QVariant(const QPointF &pt) { create (PointF, &pt); } +QVariant::QVariant(const QRectF &r) { create (RectF, &r); } +QVariant::QVariant(const QLineF &l) { create (LineF, &l); } +QVariant::QVariant(const QLine &l) { create (Line, &l); } +QVariant::QVariant(const QRect &r) { create(Rect, &r); } +QVariant::QVariant(const QSize &s) { create(Size, &s); } +QVariant::QVariant(const QSizeF &s) { create(SizeF, &s); } +#endif +QVariant::QVariant(const QUrl &u) { create(Url, &u); } +QVariant::QVariant(const QLocale &l) { create(Locale, &l); } +#ifndef QT_NO_REGEXP +QVariant::QVariant(const QRegExp ®Exp) { create(RegExp, ®Exp); } +#endif +QVariant::QVariant(Qt::GlobalColor color) { create(62, &color); } + +/*! + Returns the storage type of the value stored in the variant. + Although this function is declared as returning QVariant::Type, + the return value should be interpreted as QMetaType::Type. In + particular, QVariant::UserType is returned here only if the value + is equal or greater than QMetaType::User. + + Note that return values in the ranges QVariant::Char through + QVariant::RegExp and QVariant::Font through QVariant::Transform + correspond to the values in the ranges QMetaType::QChar through + QMetaType::QRegExp and QMetaType::QFont through QMetaType::QTransform. + + Pay particular attention when working with char and QChar + variants. Note that there is no QVariant constructor specifically + for type char, but there is one for QChar. For a variant of type + QChar, this function returns QVariant::Char, which is the same as + QMetaType::QChar, but for a variant of type \c char, this function + returns QMetaType::Char, which is \e not the same as + QVariant::Char. + + Also note that the types \c void*, \c long, \c short, \c unsigned + \c long, \c unsigned \c short, \c unsigned \c char, \c float, \c + QObject*, and \c QWidget* are represented in QMetaType::Type but + not in QVariant::Type, and they can be returned by this function. + However, they are considered to be user defined types when tested + against QVariant::Type. + + To test whether an instance of QVariant contains a data type that + is compatible with the data type you are interested in, use + canConvert(). +*/ + +QVariant::Type QVariant::type() const +{ + return d.type >= QMetaType::User ? UserType : static_cast<Type>(d.type); +} + +/*! + Returns the storage type of the value stored in the variant. For + non-user types, this is the same as type(). + + \sa type() +*/ + +int QVariant::userType() const +{ + return d.type; +} + +/*! + Assigns the value of the variant \a variant to this variant. +*/ +QVariant& QVariant::operator=(const QVariant &variant) +{ + if (this == &variant) + return *this; + + clear(); + if (variant.d.is_shared) { + variant.d.data.shared->ref.ref(); + d = variant.d; + } else if (variant.d.type > Char) { + d.type = variant.d.type; + handler->construct(&d, variant.constData()); + d.is_null = variant.d.is_null; + } else { + d = variant.d; + } + + return *this; +} + +/*! + \fn void QVariant::detach() + + \internal +*/ + +void QVariant::detach() +{ + if (!d.is_shared || d.data.shared->ref == 1) + return; + + Private dd; + dd.type = d.type; + handler->construct(&dd, constData()); + if (!d.data.shared->ref.deref()) + handler->clear(&d); + d.data.shared = dd.data.shared; +} + +/*! + \fn bool QVariant::isDetached() const + + \internal +*/ + +// ### Qt 5: change typeName()(and froends= to return a QString. Suggestion from Harald. +/*! + Returns the name of the type stored in the variant. The returned + strings describe the C++ datatype used to store the data: for + example, "QFont", "QString", or "QVariantList". An Invalid + variant returns 0. +*/ +const char *QVariant::typeName() const +{ + return typeToName(Type(d.type)); +} + +/*! + Convert this variant to type Invalid and free up any resources + used. +*/ +void QVariant::clear() +{ + if (!d.is_shared || !d.data.shared->ref.deref()) + handler->clear(&d); + d.type = Invalid; + d.is_null = true; + d.is_shared = false; +} + +/*! + Converts the enum representation of the storage type, \a typ, to + its string representation. + + Returns a null pointer if the type is QVariant::Invalid or doesn't exist. +*/ +const char *QVariant::typeToName(Type typ) +{ + if (typ == Invalid) + return 0; + if (typ == UserType) + return "UserType"; + + return QMetaType::typeName(typ); +} + + +/*! + Converts the string representation of the storage type given in \a + name, to its enum representation. + + If the string representation cannot be converted to any enum + representation, the variant is set to \c Invalid. +*/ +QVariant::Type QVariant::nameToType(const char *name) +{ + if (!name || !*name) + return Invalid; + if (strcmp(name, "Q3CString") == 0) + return ByteArray; + if (strcmp(name, "Q_LLONG") == 0) + return LongLong; + if (strcmp(name, "Q_ULLONG") == 0) + return ULongLong; + if (strcmp(name, "QIconSet") == 0) + return Icon; + if (strcmp(name, "UserType") == 0) + return UserType; + + int metaType = QMetaType::type(name); + return metaType <= int(LastGuiType) ? QVariant::Type(metaType) : UserType; +} + +#ifndef QT_NO_DATASTREAM +enum { MapFromThreeCount = 35 }; +static const uint map_from_three[MapFromThreeCount] = +{ + QVariant::Invalid, + QVariant::Map, + QVariant::List, + QVariant::String, + QVariant::StringList, + QVariant::Font, + QVariant::Pixmap, + QVariant::Brush, + QVariant::Rect, + QVariant::Size, + QVariant::Color, + QVariant::Palette, + 63, // ColorGroup + QVariant::Icon, + QVariant::Point, + QVariant::Image, + QVariant::Int, + QVariant::UInt, + QVariant::Bool, + QVariant::Double, + QVariant::ByteArray, + QVariant::Polygon, + QVariant::Region, + QVariant::Bitmap, + QVariant::Cursor, + QVariant::SizePolicy, + QVariant::Date, + QVariant::Time, + QVariant::DateTime, + QVariant::ByteArray, + QVariant::BitArray, + QVariant::KeySequence, + QVariant::Pen, + QVariant::LongLong, + QVariant::ULongLong +}; + +/*! + Internal function for loading a variant from stream \a s. Use the + stream operators instead. + + \internal +*/ +void QVariant::load(QDataStream &s) +{ + clear(); + + quint32 u; + s >> u; + if (s.version() < QDataStream::Qt_4_0) { + if (u >= MapFromThreeCount) + return; + u = map_from_three[u]; + } + qint8 is_null = false; + if (s.version() >= QDataStream::Qt_4_2) + s >> is_null; + if (u == QVariant::UserType) { + QByteArray name; + s >> name; + u = QMetaType::type(name); + if (!u) { + s.setStatus(QDataStream::ReadCorruptData); + return; + } + } + create(static_cast<int>(u), 0); + d.is_null = is_null; + + if (d.type == QVariant::Invalid) { + // Since we wrote something, we should read something + QString x; + s >> x; + d.is_null = true; + return; + } + + // const cast is safe since we operate on a newly constructed variant + if (!QMetaType::load(s, d.type, const_cast<void *>(constDataHelper(d)))) { + s.setStatus(QDataStream::ReadCorruptData); + qWarning("QVariant::load: unable to load type %d.", d.type); + } +} + +/*! + Internal function for saving a variant to the stream \a s. Use the + stream operators instead. + + \internal +*/ +void QVariant::save(QDataStream &s) const +{ + quint32 tp = type(); + if (s.version() < QDataStream::Qt_4_0) { + int i; + for (i = MapFromThreeCount - 1; i >= 0; i--) { + if (map_from_three[i] == tp) { + tp = i; + break; + } + } + if (i == -1) { + s << QVariant(); + return; + } + } + s << tp; + if (s.version() >= QDataStream::Qt_4_2) + s << qint8(d.is_null); + if (tp == QVariant::UserType) { + s << QMetaType::typeName(userType()); + } + + if (d.type == QVariant::Invalid) { + s << QString(); + return; + } + + if (!QMetaType::save(s, d.type, constDataHelper(d))) { + Q_ASSERT_X(false, "QVariant::save", "Invalid type to save"); + qWarning("QVariant::save: unable to save type %d.", d.type); + } +} + +/*! + \since 4.4 + + Reads a variant \a p from the stream \a s. + + \sa \link datastreamformat.html Format of the QDataStream + operators \endlink +*/ +QDataStream& operator>>(QDataStream &s, QVariant &p) +{ + p.load(s); + return s; +} + +/*! + Writes a variant \a p to the stream \a s. + + \sa \link datastreamformat.html Format of the QDataStream + operators \endlink +*/ +QDataStream& operator<<(QDataStream &s, const QVariant &p) +{ + p.save(s); + return s; +} + +/*! + Reads a variant type \a p in enum representation from the stream \a s. +*/ +QDataStream& operator>>(QDataStream &s, QVariant::Type &p) +{ + quint32 u; + s >> u; + p = (QVariant::Type)u; + + return s; +} + +/*! + Writes a variant type \a p to the stream \a s. +*/ +QDataStream& operator<<(QDataStream &s, const QVariant::Type p) +{ + s << static_cast<quint32>(p); + + return s; +} + +#endif //QT_NO_DATASTREAM + +/*! + \fn bool QVariant::isValid() const + + Returns true if the storage type of this variant is not + QVariant::Invalid; otherwise returns false. +*/ + +template <typename T> +inline T qVariantToHelper(const QVariant::Private &d, QVariant::Type t, + const QVariant::Handler *handler, T * = 0) +{ + if (d.type == t) + return *v_cast<T>(&d); + + T ret; + handler->convert(&d, t, &ret, 0); + return ret; +} + +/*! + \fn QStringList QVariant::toStringList() const + + Returns the variant as a QStringList if the variant has type() + StringList, \l String, or \l List of a type that can be converted + to QString; otherwise returns an empty list. + + \sa canConvert(), convert() +*/ +QStringList QVariant::toStringList() const +{ + return qVariantToHelper<QStringList>(d, StringList, handler); +} + +/*! + Returns the variant as a QString if the variant has type() \l + String, \l Bool, \l ByteArray, \l Char, \l Date, \l DateTime, \l + Double, \l Int, \l LongLong, \l StringList, \l Time, \l UInt, or + \l ULongLong; otherwise returns an empty string. + + \sa canConvert(), convert() +*/ +QString QVariant::toString() const +{ + return qVariantToHelper<QString>(d, String, handler); +} + +/*! + Returns the variant as a QMap<QString, QVariant> if the variant + has type() \l Map; otherwise returns an empty map. + + \sa canConvert(), convert() +*/ +QVariantMap QVariant::toMap() const +{ + return qVariantToHelper<QVariantMap>(d, Map, handler); +} + +/*! + Returns the variant as a QHash<QString, QVariant> if the variant + has type() \l Hash; otherwise returns an empty map. + + \sa canConvert(), convert() +*/ +QVariantHash QVariant::toHash() const +{ + return qVariantToHelper<QVariantHash>(d, Hash, handler); +} + +/*! + \fn QDate QVariant::toDate() const + + Returns the variant as a QDate if the variant has type() \l Date, + \l DateTime, or \l String; otherwise returns an invalid date. + + If the type() is \l String, an invalid date will be returned if the + string cannot be parsed as a Qt::ISODate format date. + + \sa canConvert(), convert() +*/ +QDate QVariant::toDate() const +{ + return qVariantToHelper<QDate>(d, Date, handler); +} + +/*! + \fn QTime QVariant::toTime() const + + Returns the variant as a QTime if the variant has type() \l Time, + \l DateTime, or \l String; otherwise returns an invalid time. + + If the type() is \l String, an invalid time will be returned if + the string cannot be parsed as a Qt::ISODate format time. + + \sa canConvert(), convert() +*/ +QTime QVariant::toTime() const +{ + return qVariantToHelper<QTime>(d, Time, handler); +} + +/*! + \fn QDateTime QVariant::toDateTime() const + + Returns the variant as a QDateTime if the variant has type() \l + DateTime, \l Date, or \l String; otherwise returns an invalid + date/time. + + If the type() is \l String, an invalid date/time will be returned + if the string cannot be parsed as a Qt::ISODate format date/time. + + \sa canConvert(), convert() +*/ +QDateTime QVariant::toDateTime() const +{ + return qVariantToHelper<QDateTime>(d, DateTime, handler); +} + +/*! + \fn QByteArray QVariant::toByteArray() const + + Returns the variant as a QByteArray if the variant has type() \l + ByteArray or \l String (converted using QString::fromAscii()); + otherwise returns an empty byte array. + + \sa canConvert(), convert() +*/ +QByteArray QVariant::toByteArray() const +{ + return qVariantToHelper<QByteArray>(d, ByteArray, handler); +} + +#ifndef QT_NO_GEOM_VARIANT +/*! + \fn QPoint QVariant::toPoint() const + + Returns the variant as a QPoint if the variant has type() + \l Point or \l PointF; otherwise returns a null QPoint. + + \sa canConvert(), convert() +*/ +QPoint QVariant::toPoint() const +{ + return qVariantToHelper<QPoint>(d, Point, handler); +} + +/*! + \fn QRect QVariant::toRect() const + + Returns the variant as a QRect if the variant has type() \l Rect; + otherwise returns an invalid QRect. + + \sa canConvert(), convert() +*/ +QRect QVariant::toRect() const +{ + return qVariantToHelper<QRect>(d, Rect, handler); +} + +/*! + \fn QSize QVariant::toSize() const + + Returns the variant as a QSize if the variant has type() \l Size; + otherwise returns an invalid QSize. + + \sa canConvert(), convert() +*/ +QSize QVariant::toSize() const +{ + return qVariantToHelper<QSize>(d, Size, handler); +} + +/*! + \fn QSizeF QVariant::toSizeF() const + + Returns the variant as a QSizeF if the variant has type() \l + SizeF; otherwise returns an invalid QSizeF. + + \sa canConvert(), convert() +*/ +QSizeF QVariant::toSizeF() const +{ + return qVariantToHelper<QSizeF>(d, SizeF, handler); +} + +/*! + \fn QRectF QVariant::toRectF() const + + Returns the variant as a QRectF if the variant has type() \l Rect + or \l RectF; otherwise returns an invalid QRectF. + + \sa canConvert(), convert() +*/ +QRectF QVariant::toRectF() const +{ + return qVariantToHelper<QRectF>(d, RectF, handler); +} + +/*! + \fn QLineF QVariant::toLineF() const + + Returns the variant as a QLineF if the variant has type() \l + LineF; otherwise returns an invalid QLineF. + + \sa canConvert(), convert() +*/ +QLineF QVariant::toLineF() const +{ + return qVariantToHelper<QLineF>(d, LineF, handler); +} + +/*! + \fn QLine QVariant::toLine() const + + Returns the variant as a QLine if the variant has type() \l Line; + otherwise returns an invalid QLine. + + \sa canConvert(), convert() +*/ +QLine QVariant::toLine() const +{ + return qVariantToHelper<QLine>(d, Line, handler); +} + +/*! + \fn QPointF QVariant::toPointF() const + + Returns the variant as a QPointF if the variant has type() \l + Point or \l PointF; otherwise returns a null QPointF. + + \sa canConvert(), convert() +*/ +QPointF QVariant::toPointF() const +{ + return qVariantToHelper<QPointF>(d, PointF, handler); +} + +#endif // QT_NO_GEOM_VARIANT + +/*! + \fn QUrl QVariant::toUrl() const + + Returns the variant as a QUrl if the variant has type() + \l Url; otherwise returns an invalid QUrl. + + \sa canConvert(), convert() +*/ +QUrl QVariant::toUrl() const +{ + return qVariantToHelper<QUrl>(d, Url, handler); +} + +/*! + \fn QLocale QVariant::toLocale() const + + Returns the variant as a QLocale if the variant has type() + \l Locale; otherwise returns an invalid QLocale. + + \sa canConvert(), convert() +*/ +QLocale QVariant::toLocale() const +{ + return qVariantToHelper<QLocale>(d, Locale, handler); +} + +/*! + \fn QRegExp QVariant::toRegExp() const + \since 4.1 + + Returns the variant as a QRegExp if the variant has type() \l + RegExp; otherwise returns an empty QRegExp. + + \sa canConvert(), convert() +*/ +#ifndef QT_NO_REGEXP +QRegExp QVariant::toRegExp() const +{ + return qVariantToHelper<QRegExp>(d, RegExp, handler); +} +#endif + +/*! + \fn QChar QVariant::toChar() const + + Returns the variant as a QChar if the variant has type() \l Char, + \l Int, or \l UInt; otherwise returns an invalid QChar. + + \sa canConvert(), convert() +*/ +QChar QVariant::toChar() const +{ + return qVariantToHelper<QChar>(d, Char, handler); +} + +/*! + Returns the variant as a QBitArray if the variant has type() + \l BitArray; otherwise returns an empty bit array. + + \sa canConvert(), convert() +*/ +QBitArray QVariant::toBitArray() const +{ + return qVariantToHelper<QBitArray>(d, BitArray, handler); +} + +template <typename T> +inline T qNumVariantToHelper(const QVariant::Private &d, QVariant::Type t, + const QVariant::Handler *handler, bool *ok, const T& val) +{ + if (ok) + *ok = true; + if (d.type == t) + return val; + + T ret; + if (!handler->convert(&d, t, &ret, ok) && ok) + *ok = false; + return ret; +} + +/*! + Returns the variant as an int if the variant has type() \l Int, + \l Bool, \l ByteArray, \l Char, \l Double, \l LongLong, \l + String, \l UInt, or \l ULongLong; otherwise returns 0. + + If \a ok is non-null: \c{*}\a{ok} is set to true if the value could be + converted to an int; otherwise \c{*}\a{ok} is set to false. + + \bold{Warning:} If the value is convertible to a \l LongLong but is too + large to be represented in an int, the resulting arithmetic overflow will + not be reflected in \a ok. A simple workaround is to use QString::toInt(). + Fixing this bug has been postponed to Qt 5 in order to avoid breaking existing code. + + \sa canConvert(), convert() +*/ +int QVariant::toInt(bool *ok) const +{ + return qNumVariantToHelper<int>(d, Int, handler, ok, d.data.i); +} + +/*! + Returns the variant as an unsigned int if the variant has type() + \l UInt, \l Bool, \l ByteArray, \l Char, \l Double, \l Int, \l + LongLong, \l String, or \l ULongLong; otherwise returns 0. + + If \a ok is non-null: \c{*}\a{ok} is set to true if the value could be + converted to an unsigned int; otherwise \c{*}\a{ok} is set to false. + + \bold{Warning:} If the value is convertible to a \l ULongLong but is too + large to be represented in an unsigned int, the resulting arithmetic overflow will + not be reflected in \a ok. A simple workaround is to use QString::toUInt(). + Fixing this bug has been postponed to Qt 5 in order to avoid breaking existing code. + + \sa canConvert(), convert() +*/ +uint QVariant::toUInt(bool *ok) const +{ + return qNumVariantToHelper<uint>(d, UInt, handler, ok, d.data.u); +} + +/*! + Returns the variant as a long long int if the variant has type() + \l LongLong, \l Bool, \l ByteArray, \l Char, \l Double, \l Int, + \l String, \l UInt, or \l ULongLong; otherwise returns 0. + + If \a ok is non-null: \c{*}\c{ok} is set to true if the value could be + converted to an int; otherwise \c{*}\c{ok} is set to false. + + \sa canConvert(), convert() +*/ +qlonglong QVariant::toLongLong(bool *ok) const +{ + return qNumVariantToHelper<qlonglong>(d, LongLong, handler, ok, d.data.ll); +} + +/*! + Returns the variant as as an unsigned long long int if the + variant has type() \l ULongLong, \l Bool, \l ByteArray, \l Char, + \l Double, \l Int, \l LongLong, \l String, or \l UInt; otherwise + returns 0. + + If \a ok is non-null: \c{*}\a{ok} is set to true if the value could be + converted to an int; otherwise \c{*}\a{ok} is set to false. + + \sa canConvert(), convert() +*/ +qulonglong QVariant::toULongLong(bool *ok) const +{ + return qNumVariantToHelper<qulonglong>(d, ULongLong, handler, ok, d.data.ull); +} + +/*! + Returns the variant as a bool if the variant has type() Bool. + + Returns true if the variant has type() \l Bool, \l Char, \l Double, + \l Int, \l LongLong, \l UInt, or \l ULongLong and the value is + non-zero, or if the variant has type \l String or \l ByteArray and + its lower-case content is not empty, "0" or "false"; otherwise + returns false. + + \sa canConvert(), convert() +*/ +bool QVariant::toBool() const +{ + if (d.type == Bool) + return d.data.b; + + bool res = false; + handler->convert(&d, Bool, &res, 0); + + return res; +} + +/*! + Returns the variant as a double if the variant has type() \l + Double, \l Bool, \l ByteArray, \l Int, \l LongLong, \l String, \l + UInt, or \l ULongLong; otherwise returns 0.0. + + If \a ok is non-null: \c{*}\a{ok} is set to true if the value could be + converted to a double; otherwise \c{*}\a{ok} is set to false. + + \sa canConvert(), convert() +*/ +double QVariant::toDouble(bool *ok) const +{ + return qNumVariantToHelper<double>(d, Double, handler, ok, d.data.d); +} + +/*! + Returns the variant as a QVariantList if the variant has type() + \l List or \l StringList; otherwise returns an empty list. + + \sa canConvert(), convert() +*/ +QVariantList QVariant::toList() const +{ + return qVariantToHelper<QVariantList>(d, List, handler); +} + +/*! \fn QVariant::canCast(Type t) const + Use canConvert() instead. +*/ + +/*! \fn QVariant::cast(Type t) + Use convert() instead. +*/ + + +static const quint32 qCanConvertMatrix[QVariant::LastCoreType + 1] = +{ +/*Invalid*/ 0, + +/*Bool*/ 1 << QVariant::Double | 1 << QVariant::Int | 1 << QVariant::UInt + | 1 << QVariant::LongLong | 1 << QVariant::ULongLong | 1 << QVariant::ByteArray + | 1 << QVariant::String | 1 << QVariant::Char, + +/*Int*/ 1 << QVariant::UInt | 1 << QVariant::String | 1 << QVariant::Double + | 1 << QVariant::Bool | 1 << QVariant::LongLong | 1 << QVariant::ULongLong + | 1 << QVariant::Char | 1 << QVariant::ByteArray, + +/*UInt*/ 1 << QVariant::Int | 1 << QVariant::String | 1 << QVariant::Double + | 1 << QVariant::Bool | 1 << QVariant::LongLong | 1 << QVariant::ULongLong + | 1 << QVariant::Char | 1 << QVariant::ByteArray, + +/*LLong*/ 1 << QVariant::Int | 1 << QVariant::String | 1 << QVariant::Double + | 1 << QVariant::Bool | 1 << QVariant::UInt | 1 << QVariant::ULongLong + | 1 << QVariant::Char | 1 << QVariant::ByteArray, + +/*ULlong*/ 1 << QVariant::Int | 1 << QVariant::String | 1 << QVariant::Double + | 1 << QVariant::Bool | 1 << QVariant::UInt | 1 << QVariant::LongLong + | 1 << QVariant::Char | 1 << QVariant::ByteArray, + +/*double*/ 1 << QVariant::Int | 1 << QVariant::String | 1 << QVariant::ULongLong + | 1 << QVariant::Bool | 1 << QVariant::UInt | 1 << QVariant::LongLong + | 1 << QVariant::ByteArray, + +/*QChar*/ 1 << QVariant::Int | 1 << QVariant::UInt | 1 << QVariant::LongLong + | 1 << QVariant::ULongLong, + +/*QMap*/ 0, + +/*QList*/ 1 << QVariant::StringList, + +/*QString*/ 1 << QVariant::StringList | 1 << QVariant::ByteArray | 1 << QVariant::Int + | 1 << QVariant::UInt | 1 << QVariant::Bool | 1 << QVariant::Double + | 1 << QVariant::Date | 1 << QVariant::Time | 1 << QVariant::DateTime + | 1 << QVariant::LongLong | 1 << QVariant::ULongLong | 1 << QVariant::Char, + +/*QStringList*/ 1 << QVariant::List | 1 << QVariant::String, + +/*QByteArray*/ 1 << QVariant::String | 1 << QVariant::Int | 1 << QVariant::UInt | 1 << QVariant::Bool + | 1 << QVariant::Double | 1 << QVariant::LongLong | 1 << QVariant::ULongLong, + +/*QBitArray*/ 0, + +/*QDate*/ 1 << QVariant::String | 1 << QVariant::DateTime, + +/*QTime*/ 1 << QVariant::String | 1 << QVariant::DateTime, + +/*QDateTime*/ 1 << QVariant::String | 1 << QVariant::Date, + +/*QUrl*/ 0, + +/*QLocale*/ 0, + +/*QRect*/ 1 << QVariant::RectF, + +/*QRectF*/ 1 << QVariant::Rect, + +/*QSize*/ 1 << QVariant::SizeF, + +/*QSizeF*/ 1 << QVariant::Size, + +/*QLine*/ 1 << QVariant::LineF, + +/*QLineF*/ 1 << QVariant::Line, + +/*QPoint*/ 1 << QVariant::PointF, + +/*QPointF*/ 1 << QVariant::Point, + +/*QRegExp*/ 0, + +/*QHash*/ 0 + +}; + +/*! + Returns true if the variant's type can be cast to the requested + type, \a t. Such casting is done automatically when calling the + toInt(), toBool(), ... methods. + + The following casts are done automatically: + + \table + \header \o Type \o Automatically Cast To + \row \o \l Bool \o \l Char, \l Double, \l Int, \l LongLong, \l String, \l UInt, \l ULongLong + \row \o \l ByteArray \o \l Double, \l Int, \l LongLong, \l String, \l UInt, \l ULongLong + \row \o \l Char \o \l Bool, \l Int, \l UInt, \l LongLong, \l ULongLong + \row \o \l Color \o \l String + \row \o \l Date \o \l DateTime, \l String + \row \o \l DateTime \o \l Date, \l String, \l Time + \row \o \l Double \o \l Bool, \l Int, \l LongLong, \l String, \l UInt, \l ULongLong + \row \o \l Font \o \l String + \row \o \l Int \o \l Bool, \l Char, \l Double, \l LongLong, \l String, \l UInt, \l ULongLong + \row \o \l KeySequence \o \l Int, \l String + \row \o \l List \o \l StringList (if the list's items can be converted to strings) + \row \o \l LongLong \o \l Bool, \l ByteArray, \l Char, \l Double, \l Int, \l String, \l UInt, \l ULongLong + \row \o \l Point \o PointF + \row \o \l Rect \o RectF + \row \o \l String \o \l Bool, \l ByteArray, \l Char, \l Color, \l Date, \l DateTime, \l Double, + \l Font, \l Int, \l KeySequence, \l LongLong, \l StringList, \l Time, \l UInt, + \l ULongLong + \row \o \l StringList \o \l List, \l String (if the list contains exactly one item) + \row \o \l Time \o \l String + \row \o \l UInt \o \l Bool, \l Char, \l Double, \l Int, \l LongLong, \l String, \l ULongLong + \row \o \l ULongLong \o \l Bool, \l Char, \l Double, \l Int, \l LongLong, \l String, \l UInt + \endtable + + \sa convert() +*/ +bool QVariant::canConvert(Type t) const +{ + if (d.type == uint(t)) + return true; + + if (d.type > QVariant::LastCoreType || t > QVariant::LastCoreType) { + switch (uint(t)) { + case QVariant::Int: + return d.type == QVariant::KeySequence + || d.type == QMetaType::ULong + || d.type == QMetaType::Long + || d.type == QMetaType::UShort + || d.type == QMetaType::UChar + || d.type == QMetaType::Char + || d.type == QMetaType::Short; + case QVariant::Image: + return d.type == QVariant::Pixmap || d.type == QVariant::Bitmap; + case QVariant::Pixmap: + return d.type == QVariant::Image || d.type == QVariant::Bitmap + || d.type == QVariant::Brush; + case QVariant::Bitmap: + return d.type == QVariant::Pixmap || d.type == QVariant::Image; + case QVariant::ByteArray: + return d.type == QVariant::Color; + case QVariant::String: + return d.type == QVariant::KeySequence || d.type == QVariant::Font + || d.type == QVariant::Color; + case QVariant::KeySequence: + return d.type == QVariant::String || d.type == QVariant::Int; + case QVariant::Font: + return d.type == QVariant::String; + case QVariant::Color: + return d.type == QVariant::String || d.type == QVariant::ByteArray + || d.type == QVariant::Brush; + case QVariant::Brush: + return d.type == QVariant::Color || d.type == QVariant::Pixmap; + case QMetaType::Long: + case QMetaType::Char: + case QMetaType::UChar: + case QMetaType::ULong: + case QMetaType::Short: + case QMetaType::UShort: + case QMetaType::Float: + return qCanConvertMatrix[QVariant::Int] & (1 << d.type) || d.type == QVariant::Int; + default: + return false; + } + } + + if(t == String && d.type == StringList) + return v_cast<QStringList>(&d)->count() == 1; + else + return qCanConvertMatrix[t] & (1 << d.type); +} + +/*! + Casts the variant to the requested type, \a t. If the cast cannot be + done, the variant is cleared. Returns true if the current type of + the variant was successfully cast; otherwise returns false. + + \warning For historical reasons, converting a null QVariant results + in a null value of the desired type (e.g., an empty string for + QString) and a result of false. + + \sa canConvert(), clear() +*/ + +bool QVariant::convert(Type t) +{ + if (d.type == uint(t)) + return true; + + QVariant oldValue = *this; + + clear(); + if (!oldValue.canConvert(t)) + return false; + + create(t, 0); + if (oldValue.isNull()) + return false; + + bool isOk = true; + if (!handler->convert(&oldValue.d, t, data(), &isOk)) + isOk = false; + d.is_null = !isOk; + return isOk; +} + +/*! + \fn bool operator==(const QVariant &v1, const QVariant &v2) + + \relates QVariant + + Returns true if \a v1 and \a v2 are equal; otherwise returns false. + + \warning This function doesn't support custom types registered + with qRegisterMetaType(). +*/ +/*! + \fn bool operator!=(const QVariant &v1, const QVariant &v2) + + \relates QVariant + + Returns false if \a v1 and \a v2 are equal; otherwise returns true. + + \warning This function doesn't support custom types registered + with qRegisterMetaType(). +*/ + +/*! \fn bool QVariant::operator==(const QVariant &v) const + + Compares this QVariant with \a v and returns true if they are + equal; otherwise returns false. + + In the case of custom types, their equalness operators are not called. + Instead the values' addresses are compared. +*/ + +/*! + \fn bool QVariant::operator!=(const QVariant &v) const + + Compares this QVariant with \a v and returns true if they are not + equal; otherwise returns false. + + \warning This function doesn't support custom types registered + with qRegisterMetaType(). +*/ + +static bool qIsNumericType(uint tp) +{ + return (tp >= QVariant::Bool && tp <= QVariant::Double) + || (tp >= QMetaType::Long && tp <= QMetaType::Float); +} + +static bool qIsFloatingPoint(uint tp) +{ + return tp == QVariant::Double || tp == QMetaType::Float; +} + +/*! \internal + */ +bool QVariant::cmp(const QVariant &v) const +{ + QVariant v2 = v; + if (d.type != v2.d.type) { + if (qIsNumericType(d.type) && qIsNumericType(v.d.type)) { + if (qIsFloatingPoint(d.type) || qIsFloatingPoint(v.d.type)) + return qFuzzyCompare(toDouble(), v.toDouble()); + else + return toLongLong() == v.toLongLong(); + } + if (!v2.canConvert(Type(d.type)) || !v2.convert(Type(d.type))) + return false; + } + return handler->compare(&d, &v2.d); +} + +/*! \internal + */ + +const void *QVariant::constData() const +{ + return constDataHelper(d); +} + +/*! + \fn const void* QVariant::data() const + + \internal +*/ + +/*! \internal */ +void* QVariant::data() +{ + detach(); + return const_cast<void *>(constDataHelper(d)); +} + + +#ifdef QT3_SUPPORT +/*! \internal + */ +void *QVariant::castOrDetach(Type t) +{ + if (d.type != uint(t)) { + if (!convert(t)) + create(t, 0); + } else { + detach(); + } + return data(); +} +#endif + +/*! + Returns true if this is a NULL variant, false otherwise. +*/ +bool QVariant::isNull() const +{ + return handler->isNull(&d); +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QVariant &v) +{ +#ifndef Q_BROKEN_DEBUG_STREAM + dbg.nospace() << "QVariant(" << v.typeName() << ", "; + QVariant::handler->debugStream(dbg, v); + dbg.nospace() << ')'; + return dbg.space(); +#else + qWarning("This compiler doesn't support streaming QVariant to QDebug"); + return dbg; + Q_UNUSED(v); +#endif +} + +QDebug operator<<(QDebug dbg, const QVariant::Type p) +{ +#ifndef Q_BROKEN_DEBUG_STREAM + dbg.nospace() << "QVariant::" << QVariant::typeToName(p); + return dbg.space(); +#else + qWarning("This compiler doesn't support streaming QVariant::Type to QDebug"); + return dbg; + Q_UNUSED(p); +#endif +} +#endif + +/*! + \fn int &QVariant::asInt() + + Use toInt() instead. +*/ + +/*! + \fn uint &QVariant::asUInt() + + Use toUInt() instead. +*/ + +/*! + \fn qlonglong &QVariant::asLongLong() + + Use toLongLong() instead. +*/ + +/*! + \fn qulonglong &QVariant::asULongLong() + + Use toULongLong() instead. +*/ + +/*! + \fn bool &QVariant::asBool() + + Use toBool() instead. +*/ + +/*! + \fn double &QVariant::asDouble() + + Use toDouble() instead. +*/ + +/*! + \fn QByteArray &QVariant::asByteArray() + + Use toByteArray() instead. +*/ + +/*! + \fn QBitArray &QVariant::asBitArray() + + Use toBitArray() instead. +*/ + +/*! + \fn QString &QVariant::asString() + + Use toString() instead. +*/ + +/*! + \fn QStringList &QVariant::asStringList() + + Use toStringList() instead. +*/ + +/*! + \fn QDate &QVariant::asDate() + + Use toDate() instead. +*/ + +/*! + \fn QTime &QVariant::asTime() + + Use toTime() instead. +*/ + +/*! + \fn QDateTime &QVariant::asDateTime() + + Use toDateTime() instead. +*/ + +/*! + \fn QList<QVariant> &QVariant::asList() + + Use toList() instead. +*/ + +/*! + \fn QMap<QString, QVariant> &QVariant::asMap() + + Use toMap() instead. +*/ + +/*! + \fn QVariant::QVariant(bool b, int dummy) + + Use the QVariant(bool) constructor instead. + +*/ + +/*! + \fn const QByteArray QVariant::toCString() const + + Use toByteArray() instead. +*/ + +/*! + \fn QByteArray &QVariant::asCString() + + Use toByteArray() instead. +*/ + +/*! + \fn QPoint &QVariant::asPoint() + + Use toPoint() instead. + */ + +/*! + \fn QRect &QVariant::asRect() + + Use toRect() instead. + */ + +/*! + \fn QSize &QVariant::asSize() + + Use toSize() instead. + */ + +/*! \fn void QVariant::setValue(const T &value) + + Stores a copy of \a value. If \c{T} is a type that QVariant + doesn't support, QMetaType is used to store the value. A compile + error will occur if QMetaType doesn't handle the type. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 4 + + \warning This function is not available with MSVC 6. Use + qVariantSetValue() instead if you need to support that version of + the compiler. + + \sa value(), fromValue(), canConvert() + */ + +/*! \fn T QVariant::value() const + + Returns the stored value converted to the template type \c{T}. + Call canConvert() to find out whether a type can be converted. + If the value cannot be converted, \l{default-constructed value} + will be returned. + + If the type \c{T} is supported by QVariant, this function behaves + exactly as toString(), toInt() etc. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 5 + + \warning This function is not available with MSVC 6. Use + qVariantValue() or qvariant_cast() instead if you need to support + that version of the compiler. + + \sa setValue(), fromValue(), canConvert() +*/ + +/*! \fn bool QVariant::canConvert() const + + Returns true if the variant can be converted to the template type \c{T}, + otherwise false. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 6 + + \warning This function is not available with MSVC 6. Use + qVariantCanConvert() instead if you need to support that version + of the compiler. + + \sa convert() +*/ + +/*! \fn static QVariant QVariant::fromValue(const T &value) + + Returns a QVariant containing a copy of \a value. Behaves + exactly like setValue() otherwise. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 7 + + \note If you are working with custom types, you should use + the Q_DECLARE_METATYPE() macro to register your custom type. + + \warning This function is not available with MSVC 6. Use + qVariantFromValue() instead if you need to support that version + of the compiler. + + \sa setValue(), value() +*/ + +/*! + \fn QVariant qVariantFromValue(const T &value) + \relates QVariant + + Returns a variant containing a copy of the given \a value + with template type \c{T}. + + This function is equivalent to QVariant::fromValue(\a value). It + is provided as a work-around for MSVC 6, which doesn't support + member template functions. + + For example, a QObject pointer can be stored in a variant with the + following code: + + \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 8 + + \sa QVariant::fromValue() +*/ + +/*! \fn void qVariantSetValue(QVariant &variant, const T &value) + \relates QVariant + + Sets the contents of the given \a variant to a copy of the + \a value with the specified template type \c{T}. + + This function is equivalent to QVariant::setValue(\a value). It + is provided as a work-around for MSVC 6, which doesn't support + member template functions. + + \sa QVariant::setValue() +*/ + +/*! + \fn T qvariant_cast(const QVariant &value) + \relates QVariant + + Returns the given \a value converted to the template type \c{T}. + + This function is equivalent to qVariantValue(). + + \sa qVariantValue(), QVariant::value() +*/ + +/*! \fn T qVariantValue(const QVariant &value) + \relates QVariant + + Returns the given \a value converted to the template type \c{T}. + + This function is equivalent to + \l{QVariant::value()}{QVariant::value}<T>(\a value). It is + provided as a work-around for MSVC 6, which doesn't support + member template functions. + + \sa QVariant::value(), qvariant_cast() +*/ + +/*! \fn bool qVariantCanConvert(const QVariant &value) + \relates QVariant + + Returns true if the given \a value can be converted to the + template type specified; otherwise returns false. + + This function is equivalent to QVariant::canConvert(\a value). It + is provided as a work-around for MSVC 6, which doesn't support + member template functions. + + \sa QVariant::canConvert() +*/ + +/*! + \typedef QVariantList + \relates QVariant + + Synonym for QList<QVariant>. +*/ + +/*! + \typedef QVariantMap + \relates QVariant + + Synonym for QMap<QString, QVariant>. +*/ + +/*! + \typedef QVariantHash + \relates QVariant + \since 4.5 + + Synonym for QHash<QString, QVariant>. +*/ + +/*! + \typedef QVariant::DataPtr + \internal +*/ + +/*! + \fn DataPtr &QVariant::data_ptr() + \internal +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h new file mode 100644 index 0000000..d7b7e3c --- /dev/null +++ b/src/corelib/kernel/qvariant.h @@ -0,0 +1,605 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVARIANT_H +#define QVARIANT_H + +#include <QtCore/qatomic.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qlist.h> +#include <QtCore/qmetatype.h> +#include <QtCore/qmap.h> +#include <QtCore/qhash.h> +#include <QtCore/qstring.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QBitArray; +class QDataStream; +class QDate; +class QDateTime; +class QLine; +class QLineF; +class QLocale; +class QMatrix; +class QTransform; +class QStringList; +class QTime; +class QPoint; +class QPointF; +class QSize; +class QSizeF; +class QRect; +class QRectF; +#ifndef QT_NO_REGEXP +class QRegExp; +#endif +class QTextFormat; +class QTextLength; +class QUrl; +class QVariant; +class QVariantComparisonHelper; + +#ifndef QT_NO_MEMBER_TEMPLATES +template <typename T> +inline QVariant qVariantFromValue(const T &); + +template <typename T> +inline void qVariantSetValue(QVariant &, const T &); + +template<typename T> +inline T qVariantValue(const QVariant &); + +template<typename T> +inline bool qVariantCanConvert(const QVariant &); +#endif + +class Q_CORE_EXPORT QVariant +{ + public: + enum Type { + Invalid = 0, + + Bool = 1, + Int = 2, + UInt = 3, + LongLong = 4, + ULongLong = 5, + Double = 6, + Char = 7, + Map = 8, + List = 9, + String = 10, + StringList = 11, + ByteArray = 12, + BitArray = 13, + Date = 14, + Time = 15, + DateTime = 16, + Url = 17, + Locale = 18, + Rect = 19, + RectF = 20, + Size = 21, + SizeF = 22, + Line = 23, + LineF = 24, + Point = 25, + PointF = 26, + RegExp = 27, + Hash = 28, + LastCoreType = Hash, + + // value 62 is internally reserved +#ifdef QT3_SUPPORT + ColorGroup = 63, +#endif + Font = 64, + Pixmap = 65, + Brush = 66, + Color = 67, + Palette = 68, + Icon = 69, + Image = 70, + Polygon = 71, + Region = 72, + Bitmap = 73, + Cursor = 74, + SizePolicy = 75, + KeySequence = 76, + Pen = 77, + TextLength = 78, + TextFormat = 79, + Matrix = 80, + Transform = 81, + LastGuiType = Transform, + + UserType = 127, +#ifdef QT3_SUPPORT + IconSet = Icon, + CString = ByteArray, + PointArray = Polygon, +#endif + LastType = 0xffffffff // need this so that gcc >= 3.4 allocates 32 bits for Type + }; + + inline QVariant(); + ~QVariant(); + QVariant(Type type); + QVariant(int typeOrUserType, const void *copy); + QVariant(const QVariant &other); + +#ifndef QT_NO_DATASTREAM + QVariant(QDataStream &s); +#endif + + QVariant(int i); + QVariant(uint ui); + QVariant(qlonglong ll); + QVariant(qulonglong ull); + QVariant(bool b); + QVariant(double d); +#ifndef QT_NO_CAST_FROM_ASCII + QT_ASCII_CAST_WARN_CONSTRUCTOR QVariant(const char *str); +#endif + + QVariant(const QByteArray &bytearray); + QVariant(const QBitArray &bitarray); + QVariant(const QString &string); + QVariant(const QLatin1String &string); + QVariant(const QStringList &stringlist); + QVariant(const QChar &qchar); + QVariant(const QDate &date); + QVariant(const QTime &time); + QVariant(const QDateTime &datetime); + QVariant(const QList<QVariant> &list); + QVariant(const QMap<QString,QVariant> &map); + QVariant(const QHash<QString,QVariant> &hash); +#ifndef QT_NO_GEOM_VARIANT + QVariant(const QSize &size); + QVariant(const QSizeF &size); + QVariant(const QPoint &pt); + QVariant(const QPointF &pt); + QVariant(const QLine &line); + QVariant(const QLineF &line); + QVariant(const QRect &rect); + QVariant(const QRectF &rect); +#endif + QVariant(const QUrl &url); + QVariant(const QLocale &locale); +#ifndef QT_NO_REGEXP + QVariant(const QRegExp ®Exp); +#endif + QVariant(Qt::GlobalColor color); + + QVariant& operator=(const QVariant &other); + + Type type() const; + int userType() const; + const char *typeName() const; + + bool canConvert(Type t) const; + bool convert(Type t); + +#ifdef QT3_SUPPORT + inline QT3_SUPPORT bool canCast(Type t) const + { return canConvert(t); } + inline QT3_SUPPORT bool cast(Type t) + { return convert(t); } +#endif + + inline bool isValid() const; + bool isNull() const; + + void clear(); + + void detach(); + inline bool isDetached() const; + + int toInt(bool *ok = 0) const; + uint toUInt(bool *ok = 0) const; + qlonglong toLongLong(bool *ok = 0) const; + qulonglong toULongLong(bool *ok = 0) const; + bool toBool() const; + double toDouble(bool *ok = 0) const; + QByteArray toByteArray() const; + QBitArray toBitArray() const; + QString toString() const; + QStringList toStringList() const; + QChar toChar() const; + QDate toDate() const; + QTime toTime() const; + QDateTime toDateTime() const; + QList<QVariant> toList() const; + QMap<QString, QVariant> toMap() const; + QHash<QString, QVariant> toHash() const; + +#ifndef QT_NO_GEOM_VARIANT + QPoint toPoint() const; + QPointF toPointF() const; + QRect toRect() const; + QSize toSize() const; + QSizeF toSizeF() const; + QLine toLine() const; + QLineF toLineF() const; + QRectF toRectF() const; +#endif + QUrl toUrl() const; + QLocale toLocale() const; +#ifndef QT_NO_REGEXP + QRegExp toRegExp() const; +#endif + +#ifdef QT3_SUPPORT + inline QT3_SUPPORT int &asInt(); + inline QT3_SUPPORT uint &asUInt(); + inline QT3_SUPPORT qlonglong &asLongLong(); + inline QT3_SUPPORT qulonglong &asULongLong(); + inline QT3_SUPPORT bool &asBool(); + inline QT3_SUPPORT double &asDouble(); + inline QT3_SUPPORT QByteArray &asByteArray(); + inline QT3_SUPPORT QBitArray &asBitArray(); + inline QT3_SUPPORT QString &asString(); + inline QT3_SUPPORT QStringList &asStringList(); + inline QT3_SUPPORT QDate &asDate(); + inline QT3_SUPPORT QTime &asTime(); + inline QT3_SUPPORT QDateTime &asDateTime(); + inline QT3_SUPPORT QList<QVariant> &asList(); + inline QT3_SUPPORT QMap<QString,QVariant> &asMap(); + inline QT3_SUPPORT QPoint &asPoint(); + inline QT3_SUPPORT QRect &asRect(); + inline QT3_SUPPORT QSize &asSize(); +#endif //QT3_SUPPORT + +#ifndef QT_NO_DATASTREAM + void load(QDataStream &ds); + void save(QDataStream &ds) const; +#endif + static const char *typeToName(Type type); + static Type nameToType(const char *name); + +#ifdef QT3_SUPPORT + inline QT3_SUPPORT_CONSTRUCTOR QVariant(bool val, int) { create(Bool, &val); } + inline QT3_SUPPORT const QByteArray toCString() const { return toByteArray(); } + inline QT3_SUPPORT QByteArray &asCString() { return *reinterpret_cast<QByteArray *>(castOrDetach(ByteArray)); } +#endif + + void *data(); + const void *constData() const; + inline const void *data() const { return constData(); } + +#ifndef QT_NO_MEMBER_TEMPLATES + template<typename T> + inline void setValue(const T &value); + + template<typename T> + inline T value() const + { return qVariantValue<T>(*this); } + + template<typename T> + static inline QVariant fromValue(const T &value) + { return qVariantFromValue(value); } + + template<typename T> + bool canConvert() const + { return qVariantCanConvert<T>(*this); } +#endif + + public: +#ifndef qdoc + struct PrivateShared + { + inline PrivateShared(void *v) : ptr(v), ref(1) { } + void *ptr; + QAtomicInt ref; + }; + struct Private + { + inline Private(): type(Invalid), is_shared(false), is_null(true) { data.ptr = 0; } + inline Private(const Private &other) + : data(other.data), type(other.type), + is_shared(other.is_shared), is_null(other.is_null) + {} + union Data + { + char c; + int i; + uint u; + bool b; + double d; + qlonglong ll; + qulonglong ull; + void *ptr; + PrivateShared *shared; + } data; + uint type : 30; + uint is_shared : 1; + uint is_null : 1; + }; + public: + typedef void (*f_construct)(Private *, const void *); + typedef void (*f_clear)(Private *); + typedef bool (*f_null)(const Private *); +#ifndef QT_NO_DATASTREAM + typedef void (*f_load)(Private *, QDataStream &); + typedef void (*f_save)(const Private *, QDataStream &); +#endif + typedef bool (*f_compare)(const Private *, const Private *); + typedef bool (*f_convert)(const QVariant::Private *d, Type t, void *, bool *); + typedef bool (*f_canConvert)(const QVariant::Private *d, Type t); + typedef void (*f_debugStream)(QDebug, const QVariant &); + struct Handler { + f_construct construct; + f_clear clear; + f_null isNull; +#ifndef QT_NO_DATASTREAM + f_load load; + f_save save; +#endif + f_compare compare; + f_convert convert; + f_canConvert canConvert; + f_debugStream debugStream; + }; +#endif + + inline bool operator==(const QVariant &v) const + { return cmp(v); } + inline bool operator!=(const QVariant &v) const + { return !cmp(v); } + +protected: + friend inline bool qvariant_cast_helper(const QVariant &, QVariant::Type, void *); + friend int qRegisterGuiVariant(); + friend int qUnregisterGuiVariant(); + friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &); +#ifndef QT_NO_DEBUG_STREAM + friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &); +#endif + Private d; + + static const Handler *handler; + + void create(int type, const void *copy); +#ifdef QT3_SUPPORT + void *castOrDetach(Type t); +#endif + bool cmp(const QVariant &other) const; + +private: + // force compile error, prevent QVariant(bool) to be called + inline QVariant(void *) { Q_ASSERT(false); } +#ifdef QT_NO_CAST_FROM_ASCII + // force compile error when implicit conversion is not wanted + inline QVariant(const char *) { Q_ASSERT(false); } +#endif +#ifndef QT3_SUPPORT + // force compile error, prevent QVariant(QVariant::Type, int) to be called + inline QVariant(bool, int) { Q_ASSERT(false); } +#endif +public: + typedef Private DataPtr; + inline DataPtr &data_ptr() { return d; } +}; + +typedef QList<QVariant> QVariantList; +typedef QMap<QString, QVariant> QVariantMap; +typedef QHash<QString, QVariant> QVariantHash; + +inline bool qvariant_cast_helper(const QVariant &v, QVariant::Type tp, void *ptr) +{ return QVariant::handler->convert(&v.d, tp, ptr, 0); } + +template <typename T> +inline QVariant qVariantFromValue(const T &t) +{ + return QVariant(qMetaTypeId<T>(reinterpret_cast<T *>(0)), &t); +} + +template <> +inline QVariant qVariantFromValue(const QVariant &t) { return t; } + +template <typename T> +inline void qVariantSetValue(QVariant &v, const T &t) +{ + v = QVariant(qMetaTypeId<T>(reinterpret_cast<T *>(0)), &t); +} + +inline QVariant::QVariant() {} +inline bool QVariant::isValid() const { return d.type != Invalid; } + +#ifdef QT3_SUPPORT +inline int &QVariant::asInt() +{ return *reinterpret_cast<int *>(castOrDetach(Int)); } +inline uint &QVariant::asUInt() +{ return *reinterpret_cast<uint *>(castOrDetach(UInt)); } +inline qlonglong &QVariant::asLongLong() +{ return *reinterpret_cast<qlonglong *>(castOrDetach(LongLong)); } +inline qulonglong &QVariant::asULongLong() +{ return *reinterpret_cast<qulonglong *>(castOrDetach(ULongLong)); } +inline bool &QVariant::asBool() +{ return *reinterpret_cast<bool *>(castOrDetach(Bool)); } +inline double &QVariant::asDouble() +{ return *reinterpret_cast<double *>(castOrDetach(Double)); } +inline QByteArray& QVariant::asByteArray() +{ return *reinterpret_cast<QByteArray *>(castOrDetach(ByteArray)); } +inline QBitArray& QVariant::asBitArray() +{ return *reinterpret_cast<QBitArray *>(castOrDetach(BitArray)); } +inline QString& QVariant::asString() +{ return *reinterpret_cast<QString *>(castOrDetach(String)); } +inline QStringList& QVariant::asStringList() +{ return *reinterpret_cast<QStringList *>(castOrDetach(StringList)); } +inline QDate& QVariant::asDate() +{ return *reinterpret_cast<QDate *>(castOrDetach(Date)); } +inline QTime& QVariant::asTime() +{ return *reinterpret_cast<QTime *>(castOrDetach(Time)); } +inline QDateTime& QVariant::asDateTime() +{ return *reinterpret_cast<QDateTime *>(castOrDetach(DateTime)); } +inline QList<QVariant>& QVariant::asList() +{ return *reinterpret_cast<QList<QVariant> *>(castOrDetach(List)); } +inline QMap<QString, QVariant>& QVariant::asMap() +{ return *reinterpret_cast<QMap<QString, QVariant> *>(castOrDetach(Map)); } +inline QPoint &QVariant::asPoint() +{ return *reinterpret_cast<QPoint *>(castOrDetach(Point)); } +inline QRect &QVariant::asRect() +{ return *reinterpret_cast<QRect *>(castOrDetach(Rect)); } +inline QSize &QVariant::asSize() +{ return *reinterpret_cast<QSize *>(castOrDetach(Size)); } +#endif //QT3_SUPPORT + +#ifndef QT_NO_MEMBER_TEMPLATES +template<typename T> +inline void QVariant::setValue(const T &avalue) +{ qVariantSetValue(*this, avalue); } +#endif + +#ifndef QT_NO_DATASTREAM +Q_CORE_EXPORT QDataStream& operator>> (QDataStream& s, QVariant& p); +Q_CORE_EXPORT QDataStream& operator<< (QDataStream& s, const QVariant& p); +Q_CORE_EXPORT QDataStream& operator>> (QDataStream& s, QVariant::Type& p); +Q_CORE_EXPORT QDataStream& operator<< (QDataStream& s, const QVariant::Type p); +#endif + +inline bool QVariant::isDetached() const +{ return !d.is_shared || d.data.shared->ref == 1; } + + +#ifdef qdoc + inline bool operator==(const QVariant &v1, const QVariant &v2); + inline bool operator!=(const QVariant &v1, const QVariant &v2); +#else + +/* Helper class to add one more level of indirection to prevent + implicit casts. +*/ +class QVariantComparisonHelper +{ +public: + inline QVariantComparisonHelper(const QVariant &var) + : v(&var) {} +private: + friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &); + const QVariant *v; +}; + +inline bool operator==(const QVariant &v1, const QVariantComparisonHelper &v2) +{ + return v1.cmp(*v2.v); +} + +inline bool operator!=(const QVariant &v1, const QVariantComparisonHelper &v2) +{ + return !operator==(v1, v2); +} +#endif + +#ifndef QT_MOC +#if !defined qdoc && defined Q_CC_MSVC && _MSC_VER < 1300 + +template<typename T> T qvariant_cast(const QVariant &v, T * = 0) +{ + const int vid = qMetaTypeId<T>(static_cast<T *>(0)); + if (vid == v.userType()) + return *reinterpret_cast<const T *>(v.constData()); + if (vid < int(QMetaType::User)) { + T t; + if (qvariant_cast_helper(v, QVariant::Type(vid), &t)) + return t; + } + return T(); +} + +template<typename T> +inline T qVariantValue(const QVariant &variant, T *t = 0) +{ return qvariant_cast<T>(variant, t); } + +template<typename T> +inline bool qVariantCanConvert(const QVariant &variant, T *t = 0) +{ + return variant.canConvert(static_cast<QVariant::Type>(qMetaTypeId<T>(t))); +} +#else + +template<typename T> T qvariant_cast(const QVariant &v) +{ + const int vid = qMetaTypeId<T>(static_cast<T *>(0)); + if (vid == v.userType()) + return *reinterpret_cast<const T *>(v.constData()); + if (vid < int(QMetaType::User)) { + T t; + if (qvariant_cast_helper(v, QVariant::Type(vid), &t)) + return t; + } + return T(); +} + +template<typename T> +inline T qVariantValue(const QVariant &variant) +{ return qvariant_cast<T>(variant); } + +template<typename T> +inline bool qVariantCanConvert(const QVariant &variant) +{ + return variant.canConvert(static_cast<QVariant::Type>( + qMetaTypeId<T>(static_cast<T *>(0)))); +} +#endif +#endif +Q_DECLARE_SHARED(QVariant) +Q_DECLARE_TYPEINFO(QVariant, Q_MOVABLE_TYPE); + +#ifndef QT_NO_DEBUG_STREAM +Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &); +Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant::Type); +#endif + +QT_END_NAMESPACE + +Q_DECLARE_BUILTIN_METATYPE(QVariantList, QVariantList) +Q_DECLARE_BUILTIN_METATYPE(QVariantMap, QVariantMap) +Q_DECLARE_BUILTIN_METATYPE(QVariantHash, QVariantHash) + +QT_END_HEADER + +#endif // QVARIANT_H diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h new file mode 100644 index 0000000..0764fe3 --- /dev/null +++ b/src/corelib/kernel/qvariant_p.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVARIANT_P_H +#define QVARIANT_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. +// + +// takes a type, returns the internal void* pointer cast +// to a pointer of the input type + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +extern Q_CORE_EXPORT const QVariant::Handler *qExtendedVariantHandler; + +#ifdef Q_CC_SUN // Sun CC picks the wrong overload, so introduce awful hack + +template <typename T> +inline T *v_cast(const QVariant::Private *nd, T * = 0) +{ + QVariant::Private *d = const_cast<QVariant::Private *>(nd); + return ((sizeof(T) > sizeof(QVariant::Private::Data)) + ? static_cast<T *>(d->data.shared->ptr) + : reinterpret_cast<T*>(&d->data.c)); +} + +#else // every other compiler in this world + +template <typename T> +inline const T *v_cast(const QVariant::Private *d, T * = 0) +{ + return ((sizeof(T) > sizeof(QVariant::Private::Data)) + ? static_cast<const T *>(d->data.shared->ptr) + : reinterpret_cast<const T *>(&d->data.c)); +} + +template <typename T> +inline T *v_cast(QVariant::Private *d, T * = 0) +{ + return ((sizeof(T) > sizeof(QVariant::Private::Data)) + ? static_cast<T *>(d->data.shared->ptr) + : reinterpret_cast<T *>(&d->data.c)); +} + +#endif + +//a simple template that avoids to allocate 2 buffers when creating a QVariant +template <class T> class QVariantPrivateSharedEx : public QVariant::PrivateShared +{ +public: + QVariantPrivateSharedEx(const T&t) : QVariant::PrivateShared(&m_t), m_t(t) { } + +private: + T m_t; +}; + +// constructs a new variant if copy is 0, otherwise copy-constructs +template <class T> +inline void v_construct(QVariant::Private *x, const T& t) +{ + x->type = qMetaTypeId<T>(reinterpret_cast<T *>(0)); + if (sizeof(T) > sizeof(QVariant::Private::Data)) { + x->data.shared = new QVariantPrivateSharedEx<T>(t); + x->is_shared = true; + } else { + x->is_shared = false; + new (&x->data.ptr) T(t); + } +} + +template <class T> +inline void v_construct(QVariant::Private *x, const void *copy, T * = 0) +{ + if (copy) { + v_construct<T>(x, *reinterpret_cast<const T*>(copy)); + } else { + T t; + v_construct<T>(x, t); + } +} + + +// deletes the internal structures +template <class T> +inline void v_clear(QVariant::Private *d, T* = 0) +{ + //now we need to call the destructor in any case + //because QVariant::PrivateShared doesn't have a virtual destructor + v_cast<T>(d)->~T(); + if (sizeof(T) > sizeof(QVariant::Private::Data)) + delete d->data.shared; +} + +QT_END_NAMESPACE + +#endif // QVARIANT_P_H diff --git a/src/corelib/kernel/qwineventnotifier_p.cpp b/src/corelib/kernel/qwineventnotifier_p.cpp new file mode 100644 index 0000000..dfbae7a --- /dev/null +++ b/src/corelib/kernel/qwineventnotifier_p.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwineventnotifier_p.h" + +#include "qeventdispatcher_win_p.h" +#include "qcoreapplication.h" + +#include <private/qthread_p.h> + +QT_BEGIN_NAMESPACE + +/* + \class QWinEventNotifier + \brief The QWinEventNotifier class provides support for the Windows Wait functions. + + \ingroup io + + The QWinEventNotifier class makes it possible to use the wait + functions on windows in a asynchronous manner. With this class + you can register a HANDLE to an event and get notification when + that event becomes signalled. The state of the event is not modified + in the process so if it is a manual reset event you will need to + reset it after the notification. +*/ + + +QWinEventNotifier::QWinEventNotifier(QObject *parent) + : QObject(parent), handleToEvent(0), enabled(false) +{} + +QWinEventNotifier::QWinEventNotifier(HANDLE hEvent, QObject *parent) + : QObject(parent), handleToEvent(hEvent), enabled(false) +{ + Q_D(QObject); + QEventDispatcherWin32 *eventDispatcher = qobject_cast<QEventDispatcherWin32 *>(d->threadData->eventDispatcher); + Q_ASSERT_X(eventDispatcher, "QWinEventNotifier::QWinEventNotifier()", + "Cannot create a win event notifier without a QEventDispatcherWin32"); + eventDispatcher->registerEventNotifier(this); + enabled = true; +} + +QWinEventNotifier::~QWinEventNotifier() +{ + setEnabled(false); +} + +void QWinEventNotifier::setHandle(HANDLE hEvent) +{ + setEnabled(false); + handleToEvent = hEvent; +} + +HANDLE QWinEventNotifier::handle() const +{ + return handleToEvent; +} + +bool QWinEventNotifier::isEnabled() const +{ + return enabled; +} + +void QWinEventNotifier::setEnabled(bool enable) +{ + if (enabled == enable) // no change + return; + enabled = enable; + + Q_D(QObject); + QEventDispatcherWin32 *eventDispatcher = qobject_cast<QEventDispatcherWin32 *>(d->threadData->eventDispatcher); + if (!eventDispatcher) // perhaps application is shutting down + return; + + if (enabled) + eventDispatcher->registerEventNotifier(this); + else + eventDispatcher->unregisterEventNotifier(this); +} + +bool QWinEventNotifier::event(QEvent * e) +{ + if (e->type() == QEvent::ThreadChange) { + if (enabled) { + QMetaObject::invokeMethod(this, "setEnabled", Qt::QueuedConnection, + Q_ARG(bool, enabled)); + setEnabled(false); + } + } + QObject::event(e); // will activate filters + if (e->type() == QEvent::WinEventAct) { + emit activated(handleToEvent); + return true; + } + return false; +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qwineventnotifier_p.h b/src/corelib/kernel/qwineventnotifier_p.h new file mode 100644 index 0000000..458c71c --- /dev/null +++ b/src/corelib/kernel/qwineventnotifier_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINEVENTNOTIFIER_P_H +#define QWINEVENTNOTIFIER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qobject.h" +#include "QtCore/qt_windows.h" + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QWinEventNotifier : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QObject) + +public: + explicit QWinEventNotifier(QObject *parent = 0); + explicit QWinEventNotifier(HANDLE hEvent, QObject *parent = 0); + ~QWinEventNotifier(); + + void setHandle(HANDLE hEvent); + HANDLE handle() const; + + bool isEnabled() const; + +public Q_SLOTS: + void setEnabled(bool enable); + +Q_SIGNALS: + void activated(HANDLE hEvent); + +protected: + bool event(QEvent * e); + +private: + Q_DISABLE_COPY(QWinEventNotifier) + + HANDLE handleToEvent; + bool enabled; +}; + +QT_END_NAMESPACE + +#endif // QWINEVENTNOTIFIER_P_H |