summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/animation/animation.pri25
-rw-r--r--src/corelib/animation/qabstractanimation.cpp728
-rw-r--r--src/corelib/animation/qabstractanimation.h137
-rw-r--r--src/corelib/animation/qabstractanimation_p.h153
-rw-r--r--src/corelib/animation/qanimationgroup.cpp302
-rw-r--r--src/corelib/animation/qanimationgroup.h88
-rw-r--r--src/corelib/animation/qanimationgroup_p.h83
-rw-r--r--src/corelib/animation/qparallelanimationgroup.cpp324
-rw-r--r--src/corelib/animation/qparallelanimationgroup.h86
-rw-r--r--src/corelib/animation/qparallelanimationgroup_p.h89
-rw-r--r--src/corelib/animation/qpauseanimation.cpp154
-rw-r--r--src/corelib/animation/qpauseanimation.h84
-rw-r--r--src/corelib/animation/qpropertyanimation.cpp300
-rw-r--r--src/corelib/animation/qpropertyanimation.h89
-rw-r--r--src/corelib/animation/qpropertyanimation_p.h90
-rw-r--r--src/corelib/animation/qsequentialanimationgroup.cpp594
-rw-r--r--src/corelib/animation/qsequentialanimationgroup.h96
-rw-r--r--src/corelib/animation/qsequentialanimationgroup_p.h114
-rw-r--r--src/corelib/animation/qvariantanimation.cpp669
-rw-r--r--src/corelib/animation/qvariantanimation.h130
-rw-r--r--src/corelib/animation/qvariantanimation_p.h124
-rw-r--r--src/corelib/arch/arch.pri9
-rw-r--r--src/corelib/arch/generic/qatomic_generic_unix.cpp5
-rw-r--r--src/corelib/arch/qatomic_arch.h6
-rw-r--r--src/corelib/arch/qatomic_arm.h32
-rw-r--r--src/corelib/arch/qatomic_symbian.h56
-rw-r--r--src/corelib/arch/qatomic_vxworks.h318
-rw-r--r--src/corelib/arch/qatomic_windows.h9
-rw-r--r--src/corelib/arch/symbian/arch.pri5
-rw-r--r--src/corelib/arch/symbian/qatomic_symbian.cpp116
-rw-r--r--src/corelib/arch/vxworks/arch.pri6
-rw-r--r--src/corelib/arch/vxworks/qatomic_ppc.s415
-rw-r--r--src/corelib/codecs/codecs.pri2
-rw-r--r--src/corelib/codecs/codecs.qdoc546
-rw-r--r--src/corelib/codecs/qfontlaocodec.cpp3
-rw-r--r--src/corelib/codecs/qiconvcodec.cpp13
-rw-r--r--src/corelib/codecs/qisciicodec.cpp9
-rw-r--r--src/corelib/codecs/qlatincodec.cpp6
-rw-r--r--src/corelib/codecs/qsimplecodec.cpp6
-rw-r--r--src/corelib/codecs/qtextcodec.cpp191
-rw-r--r--src/corelib/codecs/qtextcodec.h3
-rw-r--r--src/corelib/codecs/qtextcodec_p.h27
-rw-r--r--src/corelib/codecs/qtsciicodec.cpp3
-rw-r--r--src/corelib/codecs/qtsciicodec_p.h2
-rw-r--r--src/corelib/codecs/qutfcodec.cpp370
-rw-r--r--src/corelib/codecs/qutfcodec_p.h53
-rw-r--r--src/corelib/concurrent/qfuture.cpp6
-rw-r--r--src/corelib/concurrent/qfuturesynchronizer.cpp6
-rw-r--r--src/corelib/concurrent/qfuturewatcher.cpp10
-rw-r--r--src/corelib/concurrent/qfuturewatcher_p.h6
-rw-r--r--src/corelib/concurrent/qrunnable.cpp2
-rw-r--r--src/corelib/concurrent/qtconcurrentfilter.cpp4
-rw-r--r--src/corelib/concurrent/qtconcurrentiteratekernel.cpp16
-rw-r--r--src/corelib/concurrent/qtconcurrentiteratekernel.h23
-rw-r--r--src/corelib/concurrent/qtconcurrentmap.cpp15
-rw-r--r--src/corelib/concurrent/qtconcurrentrun.cpp6
-rw-r--r--src/corelib/concurrent/qtconcurrentthreadengine.cpp94
-rw-r--r--src/corelib/concurrent/qtconcurrentthreadengine.h79
-rw-r--r--src/corelib/concurrent/qthreadpool.cpp20
-rw-r--r--src/corelib/corelib.pro12
-rw-r--r--src/corelib/global/qendian.qdoc168
-rw-r--r--src/corelib/global/qfeatures.h10
-rw-r--r--src/corelib/global/qfeatures.txt29
-rw-r--r--src/corelib/global/qglobal.cpp598
-rw-r--r--src/corelib/global/qglobal.h494
-rw-r--r--src/corelib/global/qlibraryinfo.cpp49
-rw-r--r--src/corelib/global/qnamespace.h95
-rw-r--r--src/corelib/global/qnamespace.qdoc2775
-rw-r--r--src/corelib/global/qt_windows.h40
-rw-r--r--src/corelib/io/io.pri16
-rw-r--r--src/corelib/io/qabstractfileengine.cpp27
-rw-r--r--src/corelib/io/qabstractfileengine.h7
-rw-r--r--src/corelib/io/qdatastream.cpp12
-rw-r--r--src/corelib/io/qdatastream.h10
-rw-r--r--src/corelib/io/qdebug.cpp3
-rw-r--r--src/corelib/io/qdebug.h52
-rw-r--r--src/corelib/io/qdir.cpp143
-rw-r--r--src/corelib/io/qdir.h3
-rw-r--r--src/corelib/io/qdiriterator.cpp252
-rw-r--r--src/corelib/io/qdiriterator.h2
-rw-r--r--src/corelib/io/qfile.cpp45
-rw-r--r--src/corelib/io/qfileinfo.cpp91
-rw-r--r--src/corelib/io/qfileinfo.h3
-rw-r--r--src/corelib/io/qfileinfo_p.h62
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp24
-rw-r--r--src/corelib/io/qfilesystemwatcher_dnotify.cpp22
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents.cpp472
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents_p.h128
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify.cpp40
-rw-r--r--src/corelib/io/qfilesystemwatcher_kqueue.cpp5
-rw-r--r--src/corelib/io/qfilesystemwatcher_p.h7
-rw-r--r--src/corelib/io/qfilesystemwatcher_symbian.cpp291
-rw-r--r--src/corelib/io/qfilesystemwatcher_symbian_p.h130
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp435
-rw-r--r--src/corelib/io/qfilesystemwatcher_win_p.h53
-rw-r--r--src/corelib/io/qfsfileengine.cpp8
-rw-r--r--src/corelib/io/qfsfileengine_iterator.cpp1
-rw-r--r--src/corelib/io/qfsfileengine_iterator_p.h2
-rw-r--r--src/corelib/io/qfsfileengine_iterator_unix.cpp14
-rw-r--r--src/corelib/io/qfsfileengine_iterator_win.cpp44
-rw-r--r--src/corelib/io/qfsfileengine_p.h8
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp477
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp1410
-rw-r--r--src/corelib/io/qiodevice.cpp31
-rw-r--r--src/corelib/io/qiodevice.h3
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice.cpp543
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice_p.h184
-rw-r--r--src/corelib/io/qprocess.cpp452
-rw-r--r--src/corelib/io/qprocess.h41
-rw-r--r--src/corelib/io/qprocess_p.h26
-rw-r--r--src/corelib/io/qprocess_symbian.cpp1043
-rw-r--r--src/corelib/io/qprocess_unix.cpp370
-rw-r--r--src/corelib/io/qprocess_win.cpp275
-rw-r--r--src/corelib/io/qresource.cpp114
-rw-r--r--src/corelib/io/qresource.h2
-rw-r--r--src/corelib/io/qresource_iterator.cpp8
-rw-r--r--src/corelib/io/qresource_iterator_p.h4
-rw-r--r--src/corelib/io/qsettings.cpp149
-rw-r--r--src/corelib/io/qsettings.h2
-rw-r--r--src/corelib/io/qsettings_p.h6
-rw-r--r--src/corelib/io/qsettings_win.cpp211
-rw-r--r--src/corelib/io/qtemporaryfile.cpp28
-rw-r--r--src/corelib/io/qtextstream.cpp31
-rw-r--r--src/corelib/io/qtextstream.h3
-rw-r--r--src/corelib/io/qurl.cpp361
-rw-r--r--src/corelib/io/qurl.h7
-rw-r--r--src/corelib/kernel/kernel.pri43
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher.cpp26
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher_p.h2
-rw-r--r--src/corelib/kernel/qabstractitemmodel.cpp1353
-rw-r--r--src/corelib/kernel/qabstractitemmodel.h20
-rw-r--r--src/corelib/kernel/qabstractitemmodel_p.h15
-rw-r--r--src/corelib/kernel/qbasictimer.cpp1
-rw-r--r--src/corelib/kernel/qcore_symbian_p.cpp206
-rw-r--r--src/corelib/kernel/qcore_symbian_p.h155
-rw-r--r--src/corelib/kernel/qcore_unix.cpp163
-rw-r--r--src/corelib/kernel/qcore_unix_p.h324
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp377
-rw-r--r--src/corelib/kernel/qcoreapplication.h4
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h7
-rw-r--r--src/corelib/kernel/qcoreapplication_win.cpp123
-rw-r--r--src/corelib/kernel/qcorecmdlineargs_p.h9
-rw-r--r--src/corelib/kernel/qcoreevent.cpp10
-rw-r--r--src/corelib/kernel/qcoreevent.h21
-rw-r--r--src/corelib/kernel/qcoreglobaldata.cpp2
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian.cpp1000
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian_p.h307
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix.cpp210
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix_p.h64
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp89
-rw-r--r--src/corelib/kernel/qfunctions_p.h2
-rw-r--r--src/corelib/kernel/qfunctions_vxworks.cpp202
-rw-r--r--src/corelib/kernel/qfunctions_vxworks.h153
-rw-r--r--src/corelib/kernel/qfunctions_wince.cpp24
-rw-r--r--src/corelib/kernel/qfunctions_wince.h11
-rw-r--r--src/corelib/kernel/qguard_p.h157
-rw-r--r--src/corelib/kernel/qmath.h4
-rw-r--r--src/corelib/kernel/qmetaobject.cpp243
-rw-r--r--src/corelib/kernel/qmetaobject.h4
-rw-r--r--src/corelib/kernel/qmetaobject_p.h79
-rw-r--r--src/corelib/kernel/qmetatype.cpp32
-rw-r--r--src/corelib/kernel/qmetatype.h25
-rw-r--r--src/corelib/kernel/qmimedata.cpp2
-rw-r--r--src/corelib/kernel/qobject.cpp1074
-rw-r--r--src/corelib/kernel/qobject.h17
-rw-r--r--src/corelib/kernel/qobject_p.h171
-rw-r--r--src/corelib/kernel/qobjectdefs.h19
-rw-r--r--src/corelib/kernel/qpointer.cpp2
-rw-r--r--src/corelib/kernel/qsharedmemory.cpp18
-rw-r--r--src/corelib/kernel/qsharedmemory_p.h9
-rw-r--r--src/corelib/kernel/qsharedmemory_symbian.cpp176
-rw-r--r--src/corelib/kernel/qsharedmemory_unix.cpp12
-rw-r--r--src/corelib/kernel/qsharedmemory_win.cpp19
-rw-r--r--src/corelib/kernel/qsignalmapper.cpp4
-rw-r--r--src/corelib/kernel/qsocketnotifier.cpp1
-rw-r--r--src/corelib/kernel/qsystemsemaphore.cpp17
-rw-r--r--src/corelib/kernel/qsystemsemaphore.h3
-rw-r--r--src/corelib/kernel/qsystemsemaphore_p.h13
-rw-r--r--src/corelib/kernel/qsystemsemaphore_symbian.cpp126
-rw-r--r--src/corelib/kernel/qsystemsemaphore_win.cpp6
-rw-r--r--src/corelib/kernel/qtimer.cpp30
-rw-r--r--src/corelib/kernel/qtranslator.cpp9
-rw-r--r--src/corelib/kernel/qvariant.cpp302
-rw-r--r--src/corelib/kernel/qvariant.h29
-rw-r--r--src/corelib/kernel/qvariant_p.h37
-rw-r--r--src/corelib/kernel/qwineventnotifier_p.cpp2
-rw-r--r--src/corelib/plugin/plugin.pri2
-rw-r--r--src/corelib/plugin/qfactoryloader.cpp15
-rw-r--r--src/corelib/plugin/qlibrary.cpp141
-rw-r--r--src/corelib/plugin/qlibrary_unix.cpp51
-rw-r--r--src/corelib/plugin/qlibrary_win.cpp34
-rw-r--r--src/corelib/plugin/qplugin.h2
-rw-r--r--src/corelib/plugin/qplugin.qdoc135
-rw-r--r--src/corelib/plugin/qpluginloader.cpp58
-rw-r--r--src/corelib/plugin/quuid.cpp5
-rw-r--r--src/corelib/statemachine/qabstractstate.cpp206
-rw-r--r--src/corelib/statemachine/qabstractstate.h97
-rw-r--r--src/corelib/statemachine/qabstractstate_p.h83
-rw-r--r--src/corelib/statemachine/qabstracttransition.cpp331
-rw-r--r--src/corelib/statemachine/qabstracttransition.h118
-rw-r--r--src/corelib/statemachine/qabstracttransition_p.h92
-rw-r--r--src/corelib/statemachine/qeventtransition.cpp260
-rw-r--r--src/corelib/statemachine/qeventtransition.h95
-rw-r--r--src/corelib/statemachine/qeventtransition_p.h79
-rw-r--r--src/corelib/statemachine/qfinalstate.cpp139
-rw-r--r--src/corelib/statemachine/qfinalstate.h80
-rw-r--r--src/corelib/statemachine/qhistorystate.cpp226
-rw-r--r--src/corelib/statemachine/qhistorystate.h95
-rw-r--r--src/corelib/statemachine/qhistorystate_p.h79
-rw-r--r--src/corelib/statemachine/qsignalevent.h83
-rw-r--r--src/corelib/statemachine/qsignaleventgenerator_p.h78
-rw-r--r--src/corelib/statemachine/qsignaltransition.cpp267
-rw-r--r--src/corelib/statemachine/qsignaltransition.h90
-rw-r--r--src/corelib/statemachine/qsignaltransition_p.h82
-rw-r--r--src/corelib/statemachine/qstate.cpp492
-rw-r--r--src/corelib/statemachine/qstate.h119
-rw-r--r--src/corelib/statemachine/qstate_p.h108
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp2215
-rw-r--r--src/corelib/statemachine/qstatemachine.h158
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h224
-rw-r--r--src/corelib/statemachine/qwrappedevent.h80
-rw-r--r--src/corelib/statemachine/statemachine.pri30
-rw-r--r--src/corelib/thread/qmutex.cpp3
-rw-r--r--src/corelib/thread/qmutex_unix.cpp4
-rw-r--r--src/corelib/thread/qmutex_win.cpp16
-rw-r--r--src/corelib/thread/qmutexpool.cpp20
-rw-r--r--src/corelib/thread/qmutexpool_p.h7
-rw-r--r--src/corelib/thread/qreadwritelock.cpp3
-rw-r--r--src/corelib/thread/qreadwritelock.h3
-rw-r--r--src/corelib/thread/qsemaphore.cpp1
-rw-r--r--src/corelib/thread/qthread.cpp130
-rw-r--r--src/corelib/thread/qthread.h9
-rw-r--r--src/corelib/thread/qthread_p.h106
-rw-r--r--src/corelib/thread/qthread_unix.cpp161
-rw-r--r--src/corelib/thread/qthread_win.cpp49
-rw-r--r--src/corelib/thread/qthreadstorage.cpp16
-rw-r--r--src/corelib/thread/qwaitcondition.qdoc187
-rw-r--r--src/corelib/thread/qwaitcondition_win.cpp6
-rw-r--r--src/corelib/tools/qalgorithms.h17
-rw-r--r--src/corelib/tools/qalgorithms.qdoc651
-rw-r--r--src/corelib/tools/qbitarray.cpp7
-rw-r--r--src/corelib/tools/qbytearray.cpp107
-rw-r--r--src/corelib/tools/qbytearray.h24
-rw-r--r--src/corelib/tools/qbytearraymatcher.cpp2
-rw-r--r--src/corelib/tools/qbytearraymatcher.h11
-rw-r--r--src/corelib/tools/qbytedata_p.h213
-rw-r--r--src/corelib/tools/qcache.qdoc244
-rw-r--r--src/corelib/tools/qchar.cpp44
-rw-r--r--src/corelib/tools/qcontiguouscache.cpp432
-rw-r--r--src/corelib/tools/qcontiguouscache.h437
-rw-r--r--src/corelib/tools/qcryptographichash.cpp4
-rw-r--r--src/corelib/tools/qdatetime.cpp57
-rw-r--r--src/corelib/tools/qdatetime.h3
-rw-r--r--src/corelib/tools/qdatetime_p.h18
-rw-r--r--src/corelib/tools/qdumper.cpp1157
-rw-r--r--src/corelib/tools/qeasingcurve.cpp850
-rw-r--r--src/corelib/tools/qeasingcurve.h114
-rw-r--r--src/corelib/tools/qharfbuzz.cpp5
-rw-r--r--src/corelib/tools/qharfbuzz_p.h2
-rw-r--r--src/corelib/tools/qhash.cpp82
-rw-r--r--src/corelib/tools/qhash.h64
-rw-r--r--src/corelib/tools/qiterator.qdoc1431
-rw-r--r--src/corelib/tools/qline.cpp8
-rw-r--r--src/corelib/tools/qlinkedlist.cpp2
-rw-r--r--src/corelib/tools/qlinkedlist.h44
-rw-r--r--src/corelib/tools/qlist.cpp (renamed from src/corelib/tools/qlistdata.cpp)117
-rw-r--r--src/corelib/tools/qlist.h129
-rw-r--r--src/corelib/tools/qlocale.cpp263
-rw-r--r--src/corelib/tools/qlocale.h2
-rw-r--r--src/corelib/tools/qlocale_data_p.h10
-rw-r--r--src/corelib/tools/qlocale_p.h40
-rw-r--r--src/corelib/tools/qlocale_symbian.cpp879
-rw-r--r--src/corelib/tools/qmap.cpp41
-rw-r--r--src/corelib/tools/qmap.h45
-rw-r--r--src/corelib/tools/qpair.qdoc229
-rw-r--r--src/corelib/tools/qpodlist_p.h192
-rw-r--r--src/corelib/tools/qpoint.cpp21
-rw-r--r--src/corelib/tools/qpoint.h6
-rw-r--r--src/corelib/tools/qqueue.cpp2
-rw-r--r--src/corelib/tools/qrect.cpp4
-rw-r--r--src/corelib/tools/qregexp.cpp410
-rw-r--r--src/corelib/tools/qregexp.h2
-rw-r--r--src/corelib/tools/qringbuffer_p.h102
-rw-r--r--src/corelib/tools/qscopedpointer.cpp218
-rw-r--r--src/corelib/tools/qscopedpointer.h307
-rw-r--r--src/corelib/tools/qset.h14
-rw-r--r--src/corelib/tools/qset.qdoc953
-rw-r--r--src/corelib/tools/qshareddata.cpp673
-rw-r--r--src/corelib/tools/qshareddata.h18
-rw-r--r--src/corelib/tools/qsharedpointer.cpp723
-rw-r--r--src/corelib/tools/qsharedpointer.h7
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h483
-rw-r--r--src/corelib/tools/qsize.cpp4
-rw-r--r--src/corelib/tools/qsize.h12
-rw-r--r--src/corelib/tools/qstack.cpp2
-rw-r--r--src/corelib/tools/qstring.cpp499
-rw-r--r--src/corelib/tools/qstring.h14
-rw-r--r--src/corelib/tools/qstringbuilder.cpp145
-rw-r--r--src/corelib/tools/qstringbuilder.h260
-rw-r--r--src/corelib/tools/qstringlist.cpp5
-rw-r--r--src/corelib/tools/qstringlist.h1
-rw-r--r--src/corelib/tools/qstringmatcher.cpp2
-rw-r--r--src/corelib/tools/qstringmatcher.h11
-rw-r--r--src/corelib/tools/qtextboundaryfinder.cpp14
-rw-r--r--src/corelib/tools/qtimeline.cpp130
-rw-r--r--src/corelib/tools/qtimeline.h5
-rw-r--r--src/corelib/tools/qunicodetables_p.h2
-rw-r--r--src/corelib/tools/qvarlengtharray.h82
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc274
-rw-r--r--src/corelib/tools/qvector.cpp3
-rw-r--r--src/corelib/tools/qvector.h253
-rw-r--r--src/corelib/tools/tools.pri23
-rwxr-xr-xsrc/corelib/xml/make-parser.sh4
-rw-r--r--src/corelib/xml/qxmlstream.cpp157
-rw-r--r--src/corelib/xml/qxmlstream.g4
-rw-r--r--src/corelib/xml/qxmlstream.h23
-rw-r--r--src/corelib/xml/qxmlstream_p.h47
-rw-r--r--src/corelib/xml/qxmlutils.cpp4
-rw-r--r--src/corelib/xml/qxmlutils_p.h2
319 files changed, 40371 insertions, 7686 deletions
diff --git a/src/corelib/animation/animation.pri b/src/corelib/animation/animation.pri
new file mode 100644
index 0000000..cb7850c
--- /dev/null
+++ b/src/corelib/animation/animation.pri
@@ -0,0 +1,25 @@
+# Qt core animation module
+
+HEADERS += \
+ animation/qabstractanimation.h \
+ animation/qabstractanimation_p.h \
+ animation/qvariantanimation.h \
+ animation/qvariantanimation_p.h \
+ animation/qpropertyanimation.h \
+ animation/qpropertyanimation_p.h \
+ animation/qanimationgroup.h \
+ animation/qanimationgroup_p.h \
+ animation/qsequentialanimationgroup.h \
+ animation/qsequentialanimationgroup_p.h \
+ animation/qparallelanimationgroup.h \
+ animation/qparallelanimationgroup_p.h \
+ animation/qpauseanimation.h
+
+SOURCES += \
+ animation/qabstractanimation.cpp \
+ animation/qvariantanimation.cpp \
+ animation/qpropertyanimation.cpp \
+ animation/qanimationgroup.cpp \
+ animation/qsequentialanimationgroup.cpp \
+ animation/qparallelanimationgroup.cpp \
+ animation/qpauseanimation.cpp
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
new file mode 100644
index 0000000..49bd8e9
--- /dev/null
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -0,0 +1,728 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QAbstractAnimation
+ \ingroup animation
+ \brief The QAbstractAnimation class is the base of all animations.
+ \since 4.6
+
+ The class defines the functions for the functionality shared by
+ all animations. By inheriting this class, you can create custom
+ animations that plug into the rest of the animation framework.
+
+ The progress of an animation is given by its current time
+ (currentTime()), which is measured in milliseconds from the start
+ of the animation (0) to its end (duration()). The value is updated
+ automatically while the animation is running. It can also be set
+ directly with setCurrentTime().
+
+ At any point an animation is in one of three states:
+ \l{QAbstractAnimation::}{Running},
+ \l{QAbstractAnimation::}{Stopped}, or
+ \l{QAbstractAnimation::}{Paused}--as defined by the
+ \l{QAbstractAnimation::}{State} enum. The current state can be
+ changed by calling start(), stop(), pause(), or resume(). An
+ animation will always reset its \l{currentTime()}{current time}
+ when it is started. If paused, it will continue with the same
+ current time when resumed. When an animation is stopped, it cannot
+ be resumed, but will keep its current time (until started again).
+ QAbstractAnimation will emit stateChanged() whenever its state
+ changes.
+
+ An animation can loop any number of times by setting the loopCount
+ property. When an animation's current time reaches its duration(),
+ it will reset the current time and keep running. A loop count of 1
+ (the default value) means that the animation will run one time.
+ Note that a duration of -1 means that the animation will run until
+ stopped; the current time will increase indefinitely. When the
+ current time equals duration() and the animation is in its
+ final loop, the \l{QAbstractAnimation::}{Stopped} state is
+ entered, and the finished() signal is emitted.
+
+ QAbstractAnimation provides pure virtual functions used by
+ subclasses to track the progress of the animation: duration() and
+ updateCurrentTime(). The duration() function lets you report a
+ duration for the animation (as discussed above). The current time
+ is delivered by the animation framework through calls to
+ updateCurrentTime(). By reimplementing this function, you can
+ track the animation progress. Note that neither the interval
+ between calls nor the number of calls to this function are
+ defined; though, it will normally be 60 updates per second.
+
+ By reimplementing updateState(), you can track the animation's
+ state changes, which is particularly useful for animations that
+ are not driven by time.
+
+ \sa QVariantAnimation, QPropertyAnimation, QAnimationGroup, {The Animation Framework}
+*/
+
+/*!
+ \enum QAbstractAnimation::DeletionPolicy
+
+ \value KeepWhenStopped The animation will not be deleted when stopped.
+ \value DeleteWhenStopped The animation will be automatically deleted when
+ stopped.
+*/
+
+/*!
+ \fn QAbstractAnimation::finished()
+
+ QAbstractAnimation emits this signal after the animation has stopped and
+ has reached the end.
+
+ This signal is emitted after stateChanged().
+
+ \sa stateChanged()
+*/
+
+/*!
+ \fn QAbstractAnimation::stateChanged(QAbstractAnimation::State oldState, QAbstractAnimation::State newState)
+
+ QAbstractAnimation emits this signal whenever the state of the animation has
+ changed from \a oldState to \a newState. This signal is emitted after the virtual
+ updateState() function is called.
+
+ \sa updateState()
+*/
+
+/*!
+ \fn QAbstractAnimation::currentLoopChanged(int currentLoop)
+
+ QAbstractAnimation emits this signal whenever the current loop
+ changes. \a currentLoop is the current loop.
+
+ \sa currentLoop(), loopCount()
+*/
+
+/*!
+ \fn QAbstractAnimation::directionChanged(QAbstractAnimation::Direction newDirection);
+
+ QAbstractAnimation emits this signal whenever the direction has been
+ changed. \a newDirection is the new direction.
+
+ \sa direction
+*/
+
+#include "qabstractanimation.h"
+#include "qanimationgroup.h"
+#include <QtCore/qdebug.h>
+
+#include "qabstractanimation_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/qthreadstorage.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qpointer.h>
+
+#ifndef QT_NO_ANIMATION
+
+#define DEFAULT_TIMER_INTERVAL 16
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer)
+
+QUnifiedTimer::QUnifiedTimer() :
+ QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
+ currentAnimationIdx(0), consistentTiming(false)
+{
+}
+
+QUnifiedTimer *QUnifiedTimer::instance()
+{
+ QUnifiedTimer *inst;
+ if (!unifiedTimer()->hasLocalData()) {
+ inst = new QUnifiedTimer;
+ unifiedTimer()->setLocalData(inst);
+ } else {
+ inst = unifiedTimer()->localData();
+ }
+ return inst;
+}
+
+void QUnifiedTimer::timerEvent(QTimerEvent *event)
+{
+ //this is simply the time we last received a tick
+ const int oldLastTick = lastTick;
+ if (time.isValid())
+ lastTick = consistentTiming ? oldLastTick + timingInterval : time.elapsed();
+
+
+ if (event->timerId() == startStopAnimationTimer.timerId()) {
+ startStopAnimationTimer.stop();
+ //we transfer the waiting animations into the "really running" state
+ animations += animationsToStart;
+ animationsToStart.clear();
+ if (animations.isEmpty()) {
+ animationTimer.stop();
+ time = QTime();
+ } else if (!animationTimer.isActive()) {
+ animationTimer.start(timingInterval, this);
+ lastTick = 0;
+ time.start();
+ }
+ } else if (event->timerId() == animationTimer.timerId()) {
+ const int delta = lastTick - oldLastTick;
+ for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) {
+ QAbstractAnimation *animation = animations.at(currentAnimationIdx);
+ int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime
+ + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
+ animation->setCurrentTime(elapsed);
+ }
+ currentAnimationIdx = 0;
+ }
+}
+
+void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation)
+{
+ if (animations.contains(animation) || animationsToStart.contains(animation))
+ return;
+ animationsToStart << animation;
+ startStopAnimationTimer.start(0, this); // we delay the check if we should start/stop the global timer
+}
+
+void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
+{
+ Q_ASSERT(animations.count(animation) + animationsToStart.count(animation) <= 1);
+
+ int idx = animations.indexOf(animation);
+ if (idx != -1) {
+ animations.removeAt(idx);
+ // this is needed if we unregister an animation while its running
+ if (idx <= currentAnimationIdx)
+ --currentAnimationIdx;
+ } else {
+ animationsToStart.removeOne(animation);
+ }
+ startStopAnimationTimer.start(0, this); // we delay the check if we should start/stop the global timer
+}
+
+
+void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
+{
+ Q_Q(QAbstractAnimation);
+ if (state == newState)
+ return;
+
+ QAbstractAnimation::State oldState = state;
+ int oldCurrentTime = currentTime;
+ int oldCurrentLoop = currentLoop;
+ QAbstractAnimation::Direction oldDirection = direction;
+
+ // check if we should Rewind
+ if ((newState == QAbstractAnimation::Paused || newState == QAbstractAnimation::Running)
+ && oldState == QAbstractAnimation::Stopped) {
+ //here we reset the time if needed
+ //we don't call setCurrentTime because this might change the way the animation
+ //behaves: changing the state or changing the current value
+ totalCurrentTime = currentTime =(direction == QAbstractAnimation::Forward) ?
+ 0 : (loopCount == -1 ? q->duration() : q->totalDuration());
+ }
+
+ state = newState;
+ QWeakPointer<QAbstractAnimation> guard(q);
+
+ q->updateState(oldState, newState);
+ if (!guard)
+ return;
+
+ //this is to be safe if updateState changes the state
+ if (state == oldState)
+ return;
+
+ // Notify state change
+ emit q->stateChanged(oldState, newState);
+ if (!guard)
+ return;
+
+ switch (state) {
+ case QAbstractAnimation::Paused:
+ case QAbstractAnimation::Running:
+ //this ensures that the value is updated now that the animation is running
+ if(oldState == QAbstractAnimation::Stopped) {
+ q->setCurrentTime(currentTime);
+ if (!guard)
+ return;
+ }
+
+ // Register timer if our parent is not running.
+ if (state == QAbstractAnimation::Running) {
+ if (!group || group->state() == QAbstractAnimation::Stopped) {
+ QUnifiedTimer::instance()->registerAnimation(q);
+ }
+ } else {
+ //new state is paused
+ QUnifiedTimer::instance()->unregisterAnimation(q);
+ }
+ break;
+ case QAbstractAnimation::Stopped:
+ // Leave running state.
+ int dura = q->duration();
+ if (!guard)
+ return;
+
+ if (deleteWhenStopped)
+ q->deleteLater();
+
+ QUnifiedTimer::instance()->unregisterAnimation(q);
+
+ if (dura == -1 || loopCount < 0
+ || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount))
+ || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) {
+ emit q->finished();
+ }
+ break;
+ }
+
+}
+
+/*!
+ Constructs the QAbstractAnimation base class, and passes \a parent to
+ QObject's constructor.
+
+ \sa QVariantAnimation, QAnimationGroup
+*/
+QAbstractAnimation::QAbstractAnimation(QObject *parent)
+ : QObject(*new QAbstractAnimationPrivate, 0)
+{
+ // Allow auto-add on reparent
+ setParent(parent);
+}
+
+/*!
+ \internal
+*/
+QAbstractAnimation::QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent)
+ : QObject(dd, 0)
+{
+ // Allow auto-add on reparent
+ setParent(parent);
+}
+
+/*!
+ Stops the animation if it's running, then destroys the
+ QAbstractAnimation. If the animation is part of a QAnimationGroup, it is
+ automatically removed before it's destroyed.
+*/
+QAbstractAnimation::~QAbstractAnimation()
+{
+ Q_D(QAbstractAnimation);
+ //we can't call stop here. Otherwise we get pure virtual calls
+ if (d->state != Stopped) {
+ QAbstractAnimation::State oldState = d->state;
+ d->state = Stopped;
+ emit stateChanged(oldState, d->state);
+ QUnifiedTimer::instance()->unregisterAnimation(this);
+ }
+}
+
+/*!
+ \property QAbstractAnimation::state
+ \brief state of the animation.
+
+ This property describes the current state of the animation. When the
+ animation state changes, QAbstractAnimation emits the stateChanged()
+ signal.
+*/
+QAbstractAnimation::State QAbstractAnimation::state() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->state;
+}
+
+/*!
+ If this animation is part of a QAnimationGroup, this function returns a
+ pointer to the group; otherwise, it returns 0.
+
+ \sa QAnimationGroup::addAnimation()
+*/
+QAnimationGroup *QAbstractAnimation::group() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->group;
+}
+
+/*!
+ \enum QAbstractAnimation::State
+
+ This enum describes the state of the animation.
+
+ \value Stopped The animation is not running. This is the initial state
+ of QAbstractAnimation, and the state QAbstractAnimation reenters when finished. The current
+ time remain unchanged until either setCurrentTime() is
+ called, or the animation is started by calling start().
+
+ \value Paused The animation is paused (i.e., temporarily
+ suspended). Calling resume() will resume animation activity.
+
+ \value Running The animation is running. While control is in the event
+ loop, QAbstractAnimation will update its current time at regular intervals,
+ calling updateCurrentTime() when appropriate.
+
+ \sa state(), stateChanged()
+*/
+
+/*!
+ \enum QAbstractAnimation::Direction
+
+ This enum describes the direction of the animation when in \l Running state.
+
+ \value Forward The current time of the animation increases with time (i.e.,
+ moves from 0 and towards the end / duration).
+
+ \value Backward The current time of the animation decreases with time (i.e.,
+ moves from the end / duration and towards 0).
+
+ \sa direction
+*/
+
+/*!
+ \property QAbstractAnimation::direction
+ \brief the direction of the animation when it is in \l Running
+ state.
+
+ This direction indicates whether the time moves from 0 towards the
+ animation duration, or from the value of the duration and towards 0 after
+ start() has been called.
+
+ By default, this property is set to \l Forward.
+*/
+QAbstractAnimation::Direction QAbstractAnimation::direction() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->direction;
+}
+void QAbstractAnimation::setDirection(Direction direction)
+{
+ Q_D(QAbstractAnimation);
+ if (d->direction == direction)
+ return;
+
+ d->direction = direction;
+ if (state() == Stopped) {
+ if (direction == Backward) {
+ d->currentTime = duration();
+ d->currentLoop = d->loopCount - 1;
+ } else {
+ d->currentTime = 0;
+ d->currentLoop = 0;
+ }
+ }
+ updateDirection(direction);
+ emit directionChanged(direction);
+}
+
+/*!
+ \property QAbstractAnimation::duration
+ \brief the duration of the animation.
+
+ If the duration is -1, it means that the duration is undefined.
+ In this case, loopCount is ignored.
+*/
+
+/*!
+ \property QAbstractAnimation::loopCount
+ \brief the loop count of the animation
+
+ This property describes the loop count of the animation as an integer.
+ By default this value is 1, indicating that the animation
+ should run once only, and then stop. By changing it you can let the
+ animation loop several times. With a value of 0, the animation will not
+ run at all, and with a value of -1, the animation will loop forever
+ until stopped.
+ It is not supported to have loop on an animation that has an undefined
+ duration. It will only run once.
+*/
+int QAbstractAnimation::loopCount() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->loopCount;
+}
+void QAbstractAnimation::setLoopCount(int loopCount)
+{
+ Q_D(QAbstractAnimation);
+ d->loopCount = loopCount;
+}
+
+/*!
+ \property QAbstractAnimation::currentLoop
+ \brief the current loop of the animation
+
+ This property describes the current loop of the animation. By default,
+ the animation's loop count is 1, and so the current loop will
+ always be 0. If the loop count is 2 and the animation runs past its
+ duration, it will automatically rewind and restart at current time 0, and
+ current loop 1, and so on.
+
+ When the current loop changes, QAbstractAnimation emits the
+ currentLoopChanged() signal.
+*/
+int QAbstractAnimation::currentLoop() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->currentLoop;
+}
+
+/*!
+ \fn virtual int QAbstractAnimation::duration() const = 0
+
+ This pure virtual function returns the duration of the animation, and
+ defines for how long QAbstractAnimation should update the current
+ time. This duration is local, and does not include the loop count.
+
+ A return value of -1 indicates that the animation has no defined duration;
+ the animation should run forever until stopped. This is useful for
+ animations that are not time driven, or where you cannot easily predict
+ its duration (e.g., event driven audio playback in a game).
+
+ If the animation is a parallel QAnimationGroup, the duration will be the longest
+ duration of all its animations. If the animation is a sequential QAnimationGroup,
+ the duration will be the sum of the duration of all its animations.
+ \sa loopCount
+*/
+
+/*!
+ Returns the total and effective duration of the animation, including the
+ loop count.
+
+ \sa duration(), currentTime
+*/
+int QAbstractAnimation::totalDuration() const
+{
+ Q_D(const QAbstractAnimation);
+ if (d->loopCount < 0)
+ return -1;
+ int dura = duration();
+ if (dura == -1)
+ return -1;
+ return dura * d->loopCount;
+}
+
+/*!
+ \property QAbstractAnimation::currentTime
+ \brief the current time and progress of the animation
+
+ This property describes the animation's current time. You can change the
+ current time by calling setCurrentTime, or you can call start() and let
+ the animation run, setting the current time automatically as the animation
+ progresses.
+
+ The animation's current time starts at 0, and ends at duration(). If the
+ animation's loopCount is larger than 1, the current time will rewind and
+ start at 0 again for the consecutive loops. If the animation has a pause.
+ currentTime will also include the duration of the pause.
+
+ \sa loopCount
+ */
+int QAbstractAnimation::currentTime() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->currentTime;
+}
+void QAbstractAnimation::setCurrentTime(int msecs)
+{
+ Q_D(QAbstractAnimation);
+ msecs = qMax(msecs, 0);
+
+ // Calculate new time and loop.
+ int dura = duration();
+ int totalDura = (d->loopCount < 0 || dura == -1) ? -1 : dura * d->loopCount;
+ if (totalDura != -1)
+ msecs = qMin(totalDura, msecs);
+ d->totalCurrentTime = msecs;
+
+ // Update new values.
+ int oldLoop = d->currentLoop;
+ d->currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
+ if (d->currentLoop == d->loopCount) {
+ //we're at the end
+ d->currentTime = qMax(0, dura);
+ d->currentLoop = qMax(0, d->loopCount - 1);
+ } else {
+ if (d->direction == Forward) {
+ d->currentTime = (dura <= 0) ? msecs : (msecs % dura);
+ } else {
+ d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
+ if (d->currentTime == dura)
+ --d->currentLoop;
+ }
+ }
+
+ updateCurrentTime(msecs);
+ if (d->currentLoop != oldLoop)
+ emit currentLoopChanged(d->currentLoop);
+
+ // All animations are responsible for stopping the animation when their
+ // own end state is reached; in this case the animation is time driven,
+ // and has reached the end.
+ if ((d->direction == Forward && d->totalCurrentTime == totalDura)
+ || (d->direction == Backward && d->totalCurrentTime == 0)) {
+ stop();
+ }
+}
+
+/*!
+ Starts the animation. The \a policy argument says whether or not the
+ animation should be deleted when it's done. When the animation starts, the
+ stateChanged() signal is emitted, and state() returns Running. When control
+ reaches the event loop, the animation will run by itself, periodically
+ calling updateCurrentTime() as the animation progresses.
+
+ If the animation is currently stopped or has already reached the end,
+ calling start() will rewind the animation and start again from the beginning.
+ When the animation reaches the end, the animation will either stop, or
+ if the loop level is more than 1, it will rewind and continue from the beginning.
+
+ If the animation is already running, this function does nothing.
+
+ \sa stop(), state()
+*/
+void QAbstractAnimation::start(DeletionPolicy policy)
+{
+ Q_D(QAbstractAnimation);
+ if (d->state == Running)
+ return;
+ d->deleteWhenStopped = policy;
+ d->setState(Running);
+}
+
+/*!
+ Stops the animation. When the animation is stopped, it emits the stateChanged()
+ signal, and state() returns Stopped. The current time is not changed.
+
+ If the animation stops by itself after reaching the end (i.e.,
+ currentTime() == duration() and currentLoop() > loopCount() - 1), the
+ finished() signal is emitted.
+
+ \sa start(), state()
+ */
+void QAbstractAnimation::stop()
+{
+ Q_D(QAbstractAnimation);
+
+ d->setState(Stopped);
+}
+
+/*!
+ Pauses the animation. When the animation is paused, state() returns Paused.
+ The value of currentTime will remain unchanged until resume() or start()
+ is called. If you want to continue from the current time, call resume().
+
+ \sa start(), state(), resume()
+ */
+void QAbstractAnimation::pause()
+{
+ Q_D(QAbstractAnimation);
+ if (d->state == Stopped) {
+ qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation");
+ return;
+ }
+
+ d->setState(Paused);
+}
+
+/*!
+ Resumes the animation after it was paused. When the animation is resumed,
+ it emits the resumed() and stateChanged() signals. The currenttime is not
+ changed.
+
+ \sa start(), pause(), state()
+ */
+void QAbstractAnimation::resume()
+{
+ Q_D(QAbstractAnimation);
+ if (d->state != Paused) {
+ qWarning("QAbstractAnimation::resume: "
+ "Cannot resume an animation that is not paused");
+ return;
+ }
+
+ d->setState(Running);
+}
+
+/*!
+ \reimp
+*/
+bool QAbstractAnimation::event(QEvent *event)
+{
+ return QObject::event(event);
+}
+
+/*!
+ \fn virtual void QAbstractAnimation::updateCurrentTime(int msecs) = 0;
+
+ This pure virtual function is called every time the animation's current
+ time changes. The \a msecs argument is the current time.
+
+ \sa updateState()
+*/
+
+/*!
+ This virtual function is called by QAbstractAnimation when the state
+ of the animation is changed from \a oldState to \a newState.
+
+ \sa start(), stop(), pause(), resume()
+*/
+void QAbstractAnimation::updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ Q_UNUSED(oldState);
+ Q_UNUSED(newState);
+}
+
+/*!
+ This virtual function is called by QAbstractAnimation when the direction
+ of the animation is changed. The \a direction argument is the new direction.
+
+ \sa setDirection(), direction()
+*/
+void QAbstractAnimation::updateDirection(QAbstractAnimation::Direction direction)
+{
+ Q_UNUSED(direction);
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_qabstractanimation.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h
new file mode 100644
index 0000000..fe757ae
--- /dev/null
+++ b/src/corelib/animation/qabstractanimation.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTANIMATION_H
+#define QABSTRACTANIMATION_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QAnimationGroup;
+class QSequentialAnimationGroup;
+
+class QAbstractAnimationPrivate;
+class Q_CORE_EXPORT QAbstractAnimation : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(State state READ state NOTIFY stateChanged)
+ Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount)
+ Q_PROPERTY(int currentTime READ currentTime WRITE setCurrentTime)
+ Q_PROPERTY(int currentLoop READ currentLoop NOTIFY currentLoopChanged)
+ Q_PROPERTY(Direction direction READ direction WRITE setDirection NOTIFY directionChanged)
+ Q_PROPERTY(int duration READ duration)
+
+public:
+ enum Direction {
+ Forward,
+ Backward
+ };
+
+ enum State {
+ Stopped,
+ Paused,
+ Running
+ };
+
+ enum DeletionPolicy {
+ KeepWhenStopped = 0,
+ DeleteWhenStopped
+ };
+
+ QAbstractAnimation(QObject *parent = 0);
+ virtual ~QAbstractAnimation();
+
+ State state() const;
+
+ QAnimationGroup *group() const;
+
+ Direction direction() const;
+ void setDirection(Direction direction);
+
+ int loopCount() const;
+ void setLoopCount(int loopCount);
+ int currentLoop() const;
+
+ virtual int duration() const = 0;
+ int totalDuration() const;
+
+ int currentTime() const;
+
+Q_SIGNALS:
+ void finished();
+ void stateChanged(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+ void currentLoopChanged(int currentLoop);
+ void directionChanged(QAbstractAnimation::Direction);
+
+public Q_SLOTS:
+ void start(QAbstractAnimation::DeletionPolicy policy = KeepWhenStopped);
+ void pause();
+ void resume();
+ void stop();
+ void setCurrentTime(int msecs);
+
+protected:
+ QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent = 0);
+ bool event(QEvent *event);
+
+ virtual void updateCurrentTime(int msecs) = 0;
+ virtual void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+ virtual void updateDirection(QAbstractAnimation::Direction direction);
+
+private:
+ Q_DISABLE_COPY(QAbstractAnimation)
+ Q_DECLARE_PRIVATE(QAbstractAnimation)
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTANIMATION_H
diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h
new file mode 100644
index 0000000..bcd7354
--- /dev/null
+++ b/src/corelib/animation/qabstractanimation_p.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTANIMATION_P_H
+#define QABSTRACTANIMATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qbasictimer.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qtimer.h>
+#include <private/qobject_p.h>
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+class QAnimationGroup;
+class QAbstractAnimation;
+class QAbstractAnimationPrivate : public QObjectPrivate
+{
+public:
+ QAbstractAnimationPrivate()
+ : state(QAbstractAnimation::Stopped),
+ direction(QAbstractAnimation::Forward),
+ deleteWhenStopped(false),
+ totalCurrentTime(0),
+ currentTime(0),
+ loopCount(1),
+ currentLoop(0),
+ group(0)
+ {
+ }
+
+ virtual ~QAbstractAnimationPrivate() {}
+
+ static QAbstractAnimationPrivate *get(QAbstractAnimation *q)
+ {
+ return q->d_func();
+ }
+
+ QAbstractAnimation::State state;
+ QAbstractAnimation::Direction direction;
+ bool deleteWhenStopped;
+ void setState(QAbstractAnimation::State state);
+
+ int totalCurrentTime;
+ int currentTime;
+ int loopCount;
+ int currentLoop;
+
+ QAnimationGroup *group;
+
+private:
+ Q_DECLARE_PUBLIC(QAbstractAnimation)
+};
+
+
+class QUnifiedTimer : public QObject
+{
+private:
+ QUnifiedTimer();
+
+public:
+ //XXX this is needed by dui
+ static Q_CORE_EXPORT QUnifiedTimer *instance();
+
+ void registerAnimation(QAbstractAnimation *animation);
+ void unregisterAnimation(QAbstractAnimation *animation);
+
+ //defines the timing interval. Default is DEFAULT_TIMER_INTERVAL
+ void setTimingInterval(int interval)
+ {
+ timingInterval = interval;
+ if (animationTimer.isActive()) {
+ //we changed the timing interval
+ animationTimer.start(timingInterval, this);
+ }
+ }
+
+ /*
+ this allows to have a consistent timer interval at each tick from the timer
+ not taking the real time that passed into account.
+ */
+ void setConsistentTiming(bool consistent) { consistentTiming = consistent; }
+
+ int elapsedTime() const { return lastTick; }
+
+protected:
+ void timerEvent(QTimerEvent *);
+
+private:
+ QBasicTimer animationTimer, startStopAnimationTimer;
+ QTime time;
+ int lastTick;
+ int timingInterval;
+ int currentAnimationIdx;
+ bool consistentTiming;
+ QList<QAbstractAnimation*> animations, animationsToStart;
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ANIMATION
+
+#endif //QABSTRACTANIMATION_P_H
diff --git a/src/corelib/animation/qanimationgroup.cpp b/src/corelib/animation/qanimationgroup.cpp
new file mode 100644
index 0000000..78777f1
--- /dev/null
+++ b/src/corelib/animation/qanimationgroup.cpp
@@ -0,0 +1,302 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QAnimationGroup
+ \brief The QAnimationGroup class is an abstract base class for groups of animations.
+ \since 4.6
+ \ingroup animation
+
+ An animation group is a container for animations (subclasses of
+ QAbstractAnimation). A group is usually responsible for managing
+ the \l{QAbstractAnimation::State}{state} of its animations, i.e.,
+ it decides when to start, stop, resume, and pause them. Currently,
+ Qt provides two such groups: QParallelAnimationGroup and
+ QSequentialAnimationGroup. Look up their class descriptions for
+ details.
+
+ Since QAnimationGroup inherits from QAbstractAnimation, you can
+ combine groups, and easily construct complex animation graphs.
+ You can query QAbstractAnimation for the group it belongs to
+ (using the \l{QAbstractAnimation::}{group()} function).
+
+ To start a top-level animation group, you simply use the
+ \l{QAbstractAnimation::}{start()} function from
+ QAbstractAnimation. By a top-level animation group, we think of a
+ group that itself is not contained within another group. Starting
+ sub groups directly is not supported, and may lead to unexpected
+ behavior.
+
+ \omit OK, we'll put in a snippet on this here \endomit
+
+ QAnimationGroup provides methods for adding and retrieving
+ animations. Besides that, you can remove animations by calling
+ remove(), and clear the animation group by calling
+ clearAnimations(). You may keep track of changes in the group's
+ animations by listening to QEvent::ChildAdded and
+ QEvent::ChildRemoved events.
+
+ \omit OK, let's find a snippet here as well. \endomit
+
+ QAnimationGroup takes ownership of the animations it manages, and
+ ensures that they are deleted when the animation group is deleted.
+
+ \sa QAbstractAnimation, QVariantAnimation, {The Animation Framework}
+*/
+
+#include "qanimationgroup.h"
+#include <QtCore/qdebug.h>
+#include <QtCore/qcoreevent.h>
+#include "qanimationgroup_p.h"
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ Constructs a QAnimationGroup.
+ \a parent is passed to QObject's constructor.
+*/
+QAnimationGroup::QAnimationGroup(QObject *parent)
+ : QAbstractAnimation(*new QAnimationGroupPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QAnimationGroup::QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent)
+ : QAbstractAnimation(dd, parent)
+{
+}
+
+/*!
+ Destroys the animation group. It will also destroy all its animations.
+*/
+QAnimationGroup::~QAnimationGroup()
+{
+}
+
+/*!
+ Returns a pointer to the animation at \a index in this group. This
+ function is useful when you need access to a particular animation. \a
+ index is between 0 and animationCount() - 1.
+
+ \sa animationCount(), indexOfAnimation()
+*/
+QAbstractAnimation *QAnimationGroup::animationAt(int index) const
+{
+ Q_D(const QAnimationGroup);
+
+ if (index < 0 || index >= d->animations.size()) {
+ qWarning("QAnimationGroup::animationAt: index is out of bounds");
+ return 0;
+ }
+
+ return d->animations.at(index);
+}
+
+
+/*!
+ Returns the number of animations managed by this group.
+
+ \sa indexOfAnimation(), addAnimation(), animationAt()
+*/
+int QAnimationGroup::animationCount() const
+{
+ Q_D(const QAnimationGroup);
+ return d->animations.size();
+}
+
+/*!
+ Returns the index of \a animation. The returned index can be passed
+ to the other functions that take an index as an argument.
+
+ \sa insertAnimationAt(), animationAt(), takeAnimationAt()
+*/
+int QAnimationGroup::indexOfAnimation(QAbstractAnimation *animation) const
+{
+ Q_D(const QAnimationGroup);
+ return d->animations.indexOf(animation);
+}
+
+/*!
+ Adds \a animation to this group. This will call insertAnimationAt with
+ index equals to animationCount().
+
+ \note The group takes ownership of the animation.
+
+ \sa removeAnimation()
+*/
+void QAnimationGroup::addAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QAnimationGroup);
+ insertAnimationAt(d->animations.count(), animation);
+}
+
+/*!
+ Inserts \a animation into this animation group at \a index.
+ If \a index is 0 the animation is inserted at the beginning.
+ If \a index is animationCount(), the animation is inserted at the end.
+
+ \note The group takes ownership of the animation.
+
+ \sa takeAnimationAt(), addAnimation(), indexOfAnimation(), removeAnimation()
+*/
+void QAnimationGroup::insertAnimationAt(int index, QAbstractAnimation *animation)
+{
+ Q_D(QAnimationGroup);
+
+ if (index < 0 || index > d->animations.size()) {
+ qWarning("QAnimationGroup::insertAnimationAt: index is out of bounds");
+ return;
+ }
+
+ if (QAnimationGroup *oldGroup = animation->group())
+ oldGroup->removeAnimation(animation);
+
+ d->animations.insert(index, animation);
+ QAbstractAnimationPrivate::get(animation)->group = this;
+ // this will make sure that ChildAdded event is sent to 'this'
+ animation->setParent(this);
+ d->animationInsertedAt(index);
+}
+
+/*!
+ Removes \a animation from this group. The ownership of \a animation is
+ transferred to the caller.
+
+ \sa takeAnimationAt(), insertAnimationAt(), addAnimation()
+*/
+void QAnimationGroup::removeAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QAnimationGroup);
+
+ if (!animation) {
+ qWarning("QAnimationGroup::remove: cannot remove null animation");
+ return;
+ }
+ int index = d->animations.indexOf(animation);
+ if (index == -1) {
+ qWarning("QAnimationGroup::remove: animation is not part of this group");
+ return;
+ }
+
+ takeAnimationAt(index);
+}
+
+/*!
+ Returns the animation at \a index and removes it from the animation group.
+
+ \note The ownership of the animation is transferred to the caller.
+
+ \sa removeAnimation(), addAnimation(), insertAnimationAt(), indexOfAnimation()
+*/
+QAbstractAnimation *QAnimationGroup::takeAnimationAt(int index)
+{
+ Q_D(QAnimationGroup);
+ if (index < 0 || index >= d->animations.size()) {
+ qWarning("QAnimationGroup::takeAnimationAt: no animation at index %d", index);
+ return 0;
+ }
+ QAbstractAnimation *animation = d->animations.at(index);
+ QAbstractAnimationPrivate::get(animation)->group = 0;
+ // ### removing from list before doing setParent to avoid inifinite recursion
+ // in ChildRemoved event
+ d->animations.removeAt(index);
+ animation->setParent(0);
+ d->animationRemovedAt(index);
+ return animation;
+}
+
+/*!
+ Removes and deletes all animations in this animation group, and resets the current
+ time to 0.
+
+ \sa addAnimation(), removeAnimation()
+*/
+void QAnimationGroup::clearAnimations()
+{
+ Q_D(QAnimationGroup);
+ qDeleteAll(d->animations);
+}
+
+/*!
+ \reimp
+*/
+bool QAnimationGroup::event(QEvent *event)
+{
+ Q_D(QAnimationGroup);
+ if (event->type() == QEvent::ChildAdded) {
+ QChildEvent *childEvent = static_cast<QChildEvent *>(event);
+ if (QAbstractAnimation *a = qobject_cast<QAbstractAnimation *>(childEvent->child())) {
+ if (a->group() != this)
+ addAnimation(a);
+ }
+ } else if (event->type() == QEvent::ChildRemoved) {
+ QChildEvent *childEvent = static_cast<QChildEvent *>(event);
+ QAbstractAnimation *a = static_cast<QAbstractAnimation *>(childEvent->child());
+ // You can only rely on the child being a QObject because in the QEvent::ChildRemoved
+ // case it might be called from the destructor.
+ int index = d->animations.indexOf(a);
+ if (index != -1)
+ takeAnimationAt(index);
+ }
+ return QAbstractAnimation::event(event);
+}
+
+
+void QAnimationGroupPrivate::animationRemovedAt(int index)
+{
+ Q_Q(QAnimationGroup);
+ Q_UNUSED(index);
+ if (animations.isEmpty()) {
+ currentTime = 0;
+ q->stop();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qanimationgroup.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qanimationgroup.h b/src/corelib/animation/qanimationgroup.h
new file mode 100644
index 0000000..5c1a527
--- /dev/null
+++ b/src/corelib/animation/qanimationgroup.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATIONGROUP_H
+#define QANIMATIONGROUP_H
+
+#include <QtCore/qabstractanimation.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QAnimationGroupPrivate;
+class Q_CORE_EXPORT QAnimationGroup : public QAbstractAnimation
+{
+ Q_OBJECT
+
+public:
+ QAnimationGroup(QObject *parent = 0);
+ ~QAnimationGroup();
+
+ QAbstractAnimation *animationAt(int index) const;
+ int animationCount() const;
+ int indexOfAnimation(QAbstractAnimation *animation) const;
+ void addAnimation(QAbstractAnimation *animation);
+ void insertAnimationAt(int index, QAbstractAnimation *animation);
+ void removeAnimation(QAbstractAnimation *animation);
+ QAbstractAnimation *takeAnimationAt(int index);
+ void clearAnimations();
+
+protected:
+ QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent);
+ bool event(QEvent *event);
+
+private:
+ Q_DISABLE_COPY(QAnimationGroup)
+ Q_DECLARE_PRIVATE(QAnimationGroup)
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QANIMATIONGROUP_H
diff --git a/src/corelib/animation/qanimationgroup_p.h b/src/corelib/animation/qanimationgroup_p.h
new file mode 100644
index 0000000..af808e1
--- /dev/null
+++ b/src/corelib/animation/qanimationgroup_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATIONGROUP_P_H
+#define QANIMATIONGROUP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qanimationgroup.h"
+
+#include <QtCore/qlist.h>
+
+#include "private/qabstractanimation_p.h"
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+class QAnimationGroupPrivate : public QAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QAnimationGroup)
+public:
+ QAnimationGroupPrivate()
+ { }
+
+ virtual void animationInsertedAt(int index) { Q_UNUSED(index) };
+ virtual void animationRemovedAt(int index);
+
+ QList<QAbstractAnimation *> animations;
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ANIMATION
+
+#endif //QANIMATIONGROUP_P_H
diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp
new file mode 100644
index 0000000..f9d6c6c
--- /dev/null
+++ b/src/corelib/animation/qparallelanimationgroup.cpp
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QParallelAnimationGroup
+ \brief The QParallelAnimationGroup class provides a parallel group of animations.
+ \since 4.6
+ \ingroup animation
+
+ QParallelAnimationGroup--a \l{QAnimationGroup}{container for
+ animations}--starts all its animations when it is
+ \l{QAbstractAnimation::start()}{started} itself, i.e., runs all
+ animations in parallel. The animation group finishes when the
+ longest lasting animation has finished.
+
+ You can treat QParallelAnimation as any other QAbstractAnimation,
+ e.g., pause, resume, or add it to other animation groups.
+
+ \code
+ QParallelAnimationGroup *group = new QParallelAnimationGroup;
+ group->addAnimation(anim1);
+ group->addAnimation(anim2);
+
+ group->start();
+ \endcode
+
+ In this example, \c anim1 and \c anim2 are two
+ \l{QPropertyAnimation}s that have already been set up.
+
+ \sa QAnimationGroup, QPropertyAnimation, {The Animation Framework}
+*/
+
+
+#include "qparallelanimationgroup.h"
+#include "qparallelanimationgroup_p.h"
+//#define QANIMATION_DEBUG
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Constructs a QParallelAnimationGroup.
+ \a parent is passed to QObject's constructor.
+*/
+QParallelAnimationGroup::QParallelAnimationGroup(QObject *parent)
+ : QAnimationGroup(*new QParallelAnimationGroupPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QParallelAnimationGroup::QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd,
+ QObject *parent)
+ : QAnimationGroup(dd, parent)
+{
+}
+
+/*!
+ Destroys the animation group. It will also destroy all its animations.
+*/
+QParallelAnimationGroup::~QParallelAnimationGroup()
+{
+}
+
+/*!
+ \reimp
+*/
+int QParallelAnimationGroup::duration() const
+{
+ Q_D(const QParallelAnimationGroup);
+ int ret = 0;
+
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ const int currentDuration = animation->totalDuration();
+ if (currentDuration == -1)
+ return -1; // Undetermined length
+
+ ret = qMax(ret, currentDuration);
+ }
+
+ return ret;
+}
+
+/*!
+ \reimp
+*/
+void QParallelAnimationGroup::updateCurrentTime(int)
+{
+ Q_D(QParallelAnimationGroup);
+ if (d->animations.isEmpty())
+ return;
+
+ if (d->currentLoop > d->lastLoop) {
+ // simulate completion of the loop
+ int dura = duration();
+ if (dura > 0) {
+ for (int i = 0; i < d->animations.size(); ++i) {
+ d->animations.at(i)->setCurrentTime(dura); // will stop
+ }
+ }
+ } else if (d->currentLoop < d->lastLoop) {
+ // simulate completion of the loop seeking backwards
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ animation->setCurrentTime(0);
+ animation->stop();
+ }
+ }
+
+ bool timeFwd = ((d->currentLoop == d->lastLoop && d->currentTime >= d->lastCurrentTime)
+ || d->currentLoop > d->lastLoop);
+#ifdef QANIMATION_DEBUG
+ qDebug("QParallellAnimationGroup %5d: setCurrentTime(%d), loop:%d, last:%d, timeFwd:%d, lastcurrent:%d, %d",
+ __LINE__, d->currentTime, d->currentLoop, d->lastLoop, timeFwd, d->lastCurrentTime, state());
+#endif
+ // finally move into the actual time of the current loop
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ const int dura = animation->totalDuration();
+ if (dura == -1 && d->isUncontrolledAnimationFinished(animation))
+ continue;
+ if (dura == -1 || (d->currentTime <= dura && dura != 0)
+ || (dura == 0 && d->currentLoop != d->lastLoop)) {
+ switch (state()) {
+ case Running:
+ animation->start();
+ break;
+ case Paused:
+ animation->pause();
+ break;
+ case Stopped:
+ default:
+ break;
+ }
+ }
+
+ if (dura <= 0) {
+ if (dura == -1)
+ animation->setCurrentTime(d->currentTime);
+ continue;
+ }
+
+ if ((timeFwd && d->lastCurrentTime <= dura)
+ || (!timeFwd && d->currentTime <= dura))
+ animation->setCurrentTime(d->currentTime);
+ if (d->currentTime > dura)
+ animation->stop();
+ }
+ d->lastLoop = d->currentLoop;
+ d->lastCurrentTime = d->currentTime;
+}
+
+/*!
+ \reimp
+*/
+void QParallelAnimationGroup::updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ Q_D(QParallelAnimationGroup);
+ QAnimationGroup::updateState(oldState, newState);
+
+ switch (newState) {
+ case Stopped:
+ for (int i = 0; i < d->animations.size(); ++i)
+ d->animations.at(i)->stop();
+ d->disconnectUncontrolledAnimations();
+ break;
+ case Paused:
+ for (int i = 0; i < d->animations.size(); ++i)
+ d->animations.at(i)->pause();
+ break;
+ case Running:
+ d->connectUncontrolledAnimations();
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ if (oldState == Stopped)
+ animation->stop();
+ animation->setDirection(d->direction);
+ animation->start();
+ }
+ break;
+ }
+}
+
+void QParallelAnimationGroupPrivate::_q_uncontrolledAnimationFinished()
+{
+ Q_Q(QParallelAnimationGroup);
+
+ QAbstractAnimation *animation = qobject_cast<QAbstractAnimation *>(q->sender());
+ Q_ASSERT(animation);
+
+ int uncontrolledRunningCount = 0;
+ if (animation->duration() == -1 || animation->loopCount() < 0) {
+ QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin();
+ while (it != uncontrolledFinishTime.end()) {
+ if (it.key() == animation) {
+ *it = animation->currentTime();
+ }
+ if (it.value() == -1)
+ ++uncontrolledRunningCount;
+ ++it;
+ }
+ }
+
+ if (uncontrolledRunningCount > 0)
+ return;
+
+ int maxDuration = 0;
+ for (int i = 0; i < animations.size(); ++i)
+ maxDuration = qMax(maxDuration, animations.at(i)->totalDuration());
+
+ if (currentTime >= maxDuration)
+ q->stop();
+}
+
+void QParallelAnimationGroupPrivate::disconnectUncontrolledAnimations()
+{
+ Q_Q(QParallelAnimationGroup);
+
+ QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin();
+ while (it != uncontrolledFinishTime.end()) {
+ QObject::disconnect(it.key(), SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished()));
+ ++it;
+ }
+
+ uncontrolledFinishTime.clear();
+}
+
+void QParallelAnimationGroupPrivate::connectUncontrolledAnimations()
+{
+ Q_Q(QParallelAnimationGroup);
+
+ for (int i = 0; i < animations.size(); ++i) {
+ QAbstractAnimation *animation = animations.at(i);
+ if (animation->duration() == -1 || animation->loopCount() < 0) {
+ uncontrolledFinishTime[animation] = -1;
+ QObject::connect(animation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished()));
+ }
+ }
+}
+
+bool QParallelAnimationGroupPrivate::isUncontrolledAnimationFinished(QAbstractAnimation *anim) const
+{
+ return uncontrolledFinishTime.value(anim, -1) >= 0;
+}
+
+/*!
+ \reimp
+*/
+void QParallelAnimationGroup::updateDirection(QAbstractAnimation::Direction direction)
+{
+ Q_D(QParallelAnimationGroup);
+ //we need to update the direction of the current animation
+ if (state() != Stopped) {
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ animation->setDirection(direction);
+ }
+ } else {
+ if (direction == Forward) {
+ d->lastLoop = 0;
+ d->lastCurrentTime = 0;
+ } else {
+ // Looping backwards with loopCount == -1 does not really work well...
+ d->lastLoop = (d->loopCount == -1 ? 0 : d->loopCount - 1);
+ d->lastCurrentTime = duration();
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QParallelAnimationGroup::event(QEvent *event)
+{
+ return QAnimationGroup::event(event);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qparallelanimationgroup.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qparallelanimationgroup.h b/src/corelib/animation/qparallelanimationgroup.h
new file mode 100644
index 0000000..09c34da
--- /dev/null
+++ b/src/corelib/animation/qparallelanimationgroup.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPARALLELANIMATIONGROUP_H
+#define QPARALLELANIMATIONGROUP_H
+
+#include <QtCore/qanimationgroup.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QParallelAnimationGroupPrivate;
+class Q_CORE_EXPORT QParallelAnimationGroup : public QAnimationGroup
+{
+ Q_OBJECT
+
+public:
+ QParallelAnimationGroup(QObject *parent = 0);
+ ~QParallelAnimationGroup();
+
+ int duration() const;
+
+protected:
+ QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd, QObject *parent);
+ bool event(QEvent *event);
+
+ void updateCurrentTime(int msecs);
+ void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+ void updateDirection(QAbstractAnimation::Direction direction);
+
+private:
+ Q_DISABLE_COPY(QParallelAnimationGroup)
+ Q_DECLARE_PRIVATE(QParallelAnimationGroup)
+ Q_PRIVATE_SLOT(d_func(), void _q_uncontrolledAnimationFinished())
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPARALLELANIMATIONGROUP
diff --git a/src/corelib/animation/qparallelanimationgroup_p.h b/src/corelib/animation/qparallelanimationgroup_p.h
new file mode 100644
index 0000000..db804d5
--- /dev/null
+++ b/src/corelib/animation/qparallelanimationgroup_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPARALLELANIMATIONGROUP_P_H
+#define QPARALLELANIMATIONGROUP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qparallelanimationgroup.h"
+#include "private/qanimationgroup_p.h"
+#include <QtCore/qhash.h>
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+class QParallelAnimationGroupPrivate : public QAnimationGroupPrivate
+{
+ Q_DECLARE_PUBLIC(QParallelAnimationGroup)
+public:
+ QParallelAnimationGroupPrivate()
+ : lastLoop(0), lastCurrentTime(0)
+ {
+ }
+
+ QHash<QAbstractAnimation*, int> uncontrolledFinishTime;
+ int lastLoop;
+ int lastCurrentTime;
+
+ bool isUncontrolledAnimationFinished(QAbstractAnimation *anim) const;
+ void connectUncontrolledAnimations();
+ void disconnectUncontrolledAnimations();
+
+ // private slot
+ void _q_uncontrolledAnimationFinished();
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ANIMATION
+
+#endif //QPARALLELANIMATIONGROUP_P_H
diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp
new file mode 100644
index 0000000..f192602
--- /dev/null
+++ b/src/corelib/animation/qpauseanimation.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QPauseAnimation
+ \brief The QPauseAnimation class provides a pause for QSequentialAnimationGroup.
+ \since 4.6
+ \ingroup animation
+
+ If you wish to introduce a delay between animations in a
+ QSequentialAnimationGroup, you can insert a QPauseAnimation. This
+ class does not animate anything, but does not
+ \l{QAbstractAnimation::finished()}{finish} before a specified
+ number of milliseconds have elapsed from when it was started. You
+ specify the duration of the pause in the constructor. It can also
+ be set directly with setDuration().
+
+ It is not necessary to construct a QPauseAnimation yourself.
+ QSequentialAnimationGroup provides the convenience functions
+ \l{QSequentialAnimationGroup::}{addPause()} and
+ \l{QSequentialAnimationGroup::}{insertPauseAt()}. These functions
+ simply take the number of milliseconds the pause should last.
+
+ \sa QSequentialAnimationGroup
+*/
+
+#include "qpauseanimation.h"
+#include "qabstractanimation_p.h"
+
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+class QPauseAnimationPrivate : public QAbstractAnimationPrivate
+{
+public:
+ QPauseAnimationPrivate() : QAbstractAnimationPrivate(), duration(0)
+ {
+ }
+
+ int duration;
+};
+
+/*!
+ Constructs a QPauseAnimation.
+ \a parent is passed to QObject's constructor.
+ The default duration is 0.
+*/
+
+QPauseAnimation::QPauseAnimation(QObject *parent) : QAbstractAnimation(*new QPauseAnimationPrivate, parent)
+{
+}
+
+/*!
+ Constructs a QPauseAnimation.
+ \a msecs is the duration of the pause.
+ \a parent is passed to QObject's constructor.
+*/
+
+QPauseAnimation::QPauseAnimation(int msecs, QObject *parent) : QAbstractAnimation(*new QPauseAnimationPrivate, parent)
+{
+ setDuration(msecs);
+}
+
+/*!
+ Destroys the pause animation.
+*/
+QPauseAnimation::~QPauseAnimation()
+{
+}
+
+/*!
+ \property QPauseAnimation::duration
+ \brief the duration of the pause.
+
+ The duration of the pause. The duration should not be negative.
+*/
+int QPauseAnimation::duration() const
+{
+ Q_D(const QPauseAnimation);
+ return d->duration;
+}
+
+void QPauseAnimation::setDuration(int msecs)
+{
+ if (msecs < 0) {
+ qWarning("QPauseAnimation::setDuration: cannot set a negative duration");
+ return;
+ }
+ Q_D(QPauseAnimation);
+ d->duration = msecs;
+}
+
+/*!
+ \reimp
+ */
+bool QPauseAnimation::event(QEvent *e)
+{
+ return QAbstractAnimation::event(e);
+}
+
+/*!
+ \reimp
+ */
+void QPauseAnimation::updateCurrentTime(int msecs)
+{
+ Q_UNUSED(msecs);
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_qpauseanimation.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qpauseanimation.h b/src/corelib/animation/qpauseanimation.h
new file mode 100644
index 0000000..92a9092
--- /dev/null
+++ b/src/corelib/animation/qpauseanimation.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPAUSEANIMATION_P_H
+#define QPAUSEANIMATION_P_H
+
+#include <QtCore/qanimationgroup.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QPauseAnimationPrivate;
+
+class Q_CORE_EXPORT QPauseAnimation : public QAbstractAnimation
+{
+ Q_OBJECT
+ Q_PROPERTY(int duration READ duration WRITE setDuration)
+public:
+ QPauseAnimation(QObject *parent = 0);
+ QPauseAnimation(int msecs, QObject *parent = 0);
+ ~QPauseAnimation();
+
+ int duration() const;
+ void setDuration(int msecs);
+
+protected:
+ bool event(QEvent *e);
+ void updateCurrentTime(int msecs);
+
+private:
+ Q_DISABLE_COPY(QPauseAnimation)
+ Q_DECLARE_PRIVATE(QPauseAnimation)
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPAUSEANIMATION_P_H
diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp
new file mode 100644
index 0000000..49862d2
--- /dev/null
+++ b/src/corelib/animation/qpropertyanimation.cpp
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QPropertyAnimation
+ \brief The QPropertyAnimation class animates Qt properties
+ \since 4.6
+
+ \ingroup animation
+
+ QPropertyAnimation interpolates over \l{Qt's Property System}{Qt
+ properties}. As property values are stored in \l{QVariant}s, the
+ class inherits QVariantAnimation, and supports animation of the
+ same \l{QVariant::Type}{variant types} as its super class.
+
+ A class declaring properties must be a QObject. To make it
+ possible to animate a property, it must provide a setter (so that
+ QPropertyAnimation can set the property's value). Note that this
+ makes it possible to animate many of Qt's widgets. Let's look at
+ an example:
+
+ \code
+ QPropertyAnimation animation(myWidget, "geometry");
+ animation.setDuration(10000);
+ animation.setStartValue(QRect(0, 0, 100, 30));
+ animation.setEndValue(QRect(250, 250, 100, 30));
+
+ animation.start();
+ \endcode
+
+ The property name and the QObject instance of which property
+ should be animated are passed to the constructor. You can then
+ specify the start and end value of the property. The procedure is
+ equal for properties in classes you have implemented
+ yourself--just check with QVariantAnimation that your QVariant
+ type is supported.
+
+ The QVariantAnimation class description explains how to set up the
+ animation in detail. Note, however, that if a start value is not
+ set, the property will start at the value it had when the
+ QPropertyAnimation instance was created.
+
+ QPropertyAnimation works like a charm on its own. For complex
+ animations that, for instance, contain several objects,
+ QAnimationGroup is provided. An animation group is an animation
+ that can contain other animations, and that can manage when its
+ animations are played. Look at QParallelAnimationGroup for an
+ example.
+
+ \sa QVariantAnimation, QAnimationGroup, {The Animation Framework}
+*/
+
+#include "qpropertyanimation.h"
+#include "qanimationgroup.h"
+#include "qpropertyanimation_p.h"
+
+#include <private/qmutexpool_p.h>
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+void QPropertyAnimationPrivate::updateMetaProperty()
+{
+ if (!target || propertyName.isEmpty()) {
+ propertyType = QVariant::Invalid;
+ propertyIndex = -1;
+ return;
+ }
+
+ propertyType = targetValue->property(propertyName).userType();
+ propertyIndex = targetValue->metaObject()->indexOfProperty(propertyName);
+ if (propertyIndex == -1 && !targetValue->dynamicPropertyNames().contains(propertyName))
+ qWarning("QPropertyAnimation: you're trying to animate a non-existing property %s of your QObject", propertyName.constData());
+
+ if (propertyType != QVariant::Invalid)
+ convertValues(propertyType);
+}
+
+void QPropertyAnimationPrivate::updateProperty(const QVariant &newValue)
+{
+ if (state == QAbstractAnimation::Stopped)
+ return;
+
+ if (!target) {
+ q_func()->stop(); //the target was destroyed we need to stop the animation
+ return;
+ }
+
+ if (propertyIndex != -1 && newValue.userType() == propertyType) {
+ //no conversion is needed, we directly call the QObject::qt_metacall
+ void *data = const_cast<void*>(newValue.constData());
+ targetValue->qt_metacall(QMetaObject::WriteProperty, propertyIndex, &data);
+ } else {
+ targetValue->setProperty(propertyName.constData(), newValue);
+ }
+}
+
+/*!
+ Construct a QPropertyAnimation object. \a parent is passed to QObject's
+ constructor.
+*/
+QPropertyAnimation::QPropertyAnimation(QObject *parent)
+ : QVariantAnimation(*new QPropertyAnimationPrivate, parent)
+{
+}
+
+/*!
+ Construct a QPropertyAnimation object. \a parent is passed to QObject's
+ constructor. The animation changes the property \a propertyName on \a
+ target. The default duration is 250ms.
+
+ \sa targetObject, propertyName
+*/
+QPropertyAnimation::QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent)
+ : QVariantAnimation(*new QPropertyAnimationPrivate, parent)
+{
+ setTargetObject(target);
+ setPropertyName(propertyName);
+}
+
+/*!
+ Destroys the QPropertyAnimation instance.
+ */
+QPropertyAnimation::~QPropertyAnimation()
+{
+ stop();
+}
+
+/*!
+ \property QPropertyAnimation::targetObject
+ \brief the target QObject for this animation.
+
+ This property defines the target QObject for this animation.
+ */
+QObject *QPropertyAnimation::targetObject() const
+{
+ return d_func()->target.data();
+}
+
+void QPropertyAnimation::setTargetObject(QObject *target)
+{
+ Q_D(QPropertyAnimation);
+ if (d->targetValue == target)
+ return;
+
+ if (d->state != QAbstractAnimation::Stopped) {
+ qWarning("QPropertyAnimation::setTargetObject: you can't change the target of a running animation");
+ return;
+ }
+
+ d->target = d->targetValue = target;
+ d->updateMetaProperty();
+}
+
+/*!
+ \property QPropertyAnimation::propertyName
+ \brief the target property name for this animation
+
+ This property defines the target property name for this animation. The
+ property name is required for the animation to operate.
+ */
+QByteArray QPropertyAnimation::propertyName() const
+{
+ Q_D(const QPropertyAnimation);
+ return d->propertyName;
+}
+
+void QPropertyAnimation::setPropertyName(const QByteArray &propertyName)
+{
+ Q_D(QPropertyAnimation);
+ if (d->state != QAbstractAnimation::Stopped) {
+ qWarning("QPropertyAnimation::setPropertyName: you can't change the property name of a running animation");
+ return;
+ }
+
+ d->propertyName = propertyName;
+ d->updateMetaProperty();
+}
+
+
+/*!
+ \reimp
+ */
+bool QPropertyAnimation::event(QEvent *event)
+{
+ return QVariantAnimation::event(event);
+}
+
+/*!
+ This virtual function is called by QVariantAnimation whenever the current value
+ changes. \a value is the new, updated value. It updates the current value
+ of the property on the target object.
+
+ \sa currentValue, currentTime
+ */
+void QPropertyAnimation::updateCurrentValue(const QVariant &value)
+{
+ Q_D(QPropertyAnimation);
+ d->updateProperty(value);
+}
+
+/*!
+ \reimp
+
+ If the startValue is not defined when the state of the animation changes from Stopped to Running,
+ the current property value is used as the initial value for the animation.
+*/
+void QPropertyAnimation::updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ Q_D(QPropertyAnimation);
+
+ if (!d->target && oldState == Stopped) {
+ qWarning("QPropertyAnimation::updateState: Changing state of an animation without target");
+ return;
+ }
+
+ QVariantAnimation::updateState(oldState, newState);
+
+ QPropertyAnimation *animToStop = 0;
+ {
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&staticMetaObject));
+ typedef QPair<QObject *, QByteArray> QPropertyAnimationPair;
+ typedef QHash<QPropertyAnimationPair, QPropertyAnimation*> QPropertyAnimationHash;
+ static QPropertyAnimationHash hash;
+ //here we need to use value because we need to know to which pointer
+ //the animation was referring in case stopped because the target was destroyed
+ QPropertyAnimationPair key(d->targetValue, d->propertyName);
+ if (newState == Running) {
+ d->updateMetaProperty();
+ animToStop = hash.value(key, 0);
+ hash.insert(key, this);
+ // update the default start value
+ if (oldState == Stopped) {
+ d->setDefaultStartEndValue(d->targetValue->property(d->propertyName.constData()));
+ //let's check if we have a start value and an end value
+ if (d->direction == Forward && !startValue().isValid() && !d->defaultStartEndValue.isValid())
+ qWarning("QPropertyAnimation::updateState: starting an animation without start value");
+ if (d->direction == Backward && !endValue().isValid() && !d->defaultStartEndValue.isValid())
+ qWarning("QPropertyAnimation::updateState: starting an animation without end value");
+ }
+ } else if (hash.value(key) == this) {
+ hash.remove(key);
+ }
+ }
+
+ //we need to do that after the mutex was unlocked
+ if (animToStop) {
+ // try to stop the top level group
+ QAbstractAnimation *current = animToStop;
+ while (current->group() && current->state() != Stopped)
+ current = current->group();
+ current->stop();
+ }
+}
+
+#include "moc_qpropertyanimation.cpp"
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qpropertyanimation.h b/src/corelib/animation/qpropertyanimation.h
new file mode 100644
index 0000000..56fb4b1
--- /dev/null
+++ b/src/corelib/animation/qpropertyanimation.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPROPERTYANIMATION_H
+#define QPROPERTYANIMATION_H
+
+#include <QtCore/qvariantanimation.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QPropertyAnimationPrivate;
+class Q_CORE_EXPORT QPropertyAnimation : public QVariantAnimation
+{
+ Q_OBJECT
+ Q_PROPERTY(QByteArray propertyName READ propertyName WRITE setPropertyName)
+ Q_PROPERTY(QObject* targetObject READ targetObject WRITE setTargetObject)
+
+public:
+ QPropertyAnimation(QObject *parent = 0);
+ QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent = 0);
+ ~QPropertyAnimation();
+
+ QObject *targetObject() const;
+ void setTargetObject(QObject *target);
+
+ QByteArray propertyName() const;
+ void setPropertyName(const QByteArray &propertyName);
+
+protected:
+ bool event(QEvent *event);
+ void updateCurrentValue(const QVariant &value);
+ void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+
+private:
+ Q_DISABLE_COPY(QPropertyAnimation)
+ Q_DECLARE_PRIVATE(QPropertyAnimation)
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPROPERTYANIMATION_H
diff --git a/src/corelib/animation/qpropertyanimation_p.h b/src/corelib/animation/qpropertyanimation_p.h
new file mode 100644
index 0000000..3777aa0
--- /dev/null
+++ b/src/corelib/animation/qpropertyanimation_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPROPERTYANIMATION_P_H
+#define QPROPERTYANIMATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qpropertyanimation.h"
+
+#include "private/qvariantanimation_p.h"
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+class QPropertyAnimationPrivate : public QVariantAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QPropertyAnimation)
+public:
+ QPropertyAnimationPrivate()
+ : targetValue(0), propertyType(0), propertyIndex(-1)
+ {
+ }
+
+ QWeakPointer<QObject> target;
+ //we use targetValue to be able to unregister the target from the global hash
+ QObject *targetValue;
+
+ //for the QProperty
+ int propertyType;
+ int propertyIndex;
+
+ QByteArray propertyName;
+ void updateProperty(const QVariant &);
+ void updateMetaProperty();
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ANIMATION
+
+#endif //QPROPERTYANIMATION_P_H
diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp
new file mode 100644
index 0000000..53de09b
--- /dev/null
+++ b/src/corelib/animation/qsequentialanimationgroup.cpp
@@ -0,0 +1,594 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QSequentialAnimationGroup
+ \brief The QSequentialAnimationGroup class provides a sequential group of animations.
+ \since 4.6
+ \ingroup animation
+
+ QSequentialAnimationGroup is a QAnimationGroup that runs its
+ animations in sequence, i.e., it starts one animation after
+ another has finished playing. The animations are played in the
+ order they are added to the group (using
+ \l{QAnimationGroup::}{addAnimation()} or
+ \l{QAnimationGroup::}{insertAnimationAt()}). The animation group
+ finishes when its last animation has finished.
+
+ At each moment there is at most one animation that is active in
+ the group; it is returned by currentAnimation(). An empty group
+ has no current animation.
+
+ A sequential animation group can be treated as any other
+ animation, i.e., it can be started, stopped, and added to other
+ groups. You can also call addPause() or insertPauseAt() to add a
+ pause to a sequential animation group.
+
+ \code
+ QSequentialAnimationGroup group;
+
+ group.addAnimation(anim1);
+ group.addAnimation(anim2);
+
+ group.start();
+ \endcode
+
+ In this example, \c anim1 and \c anim2 are two already set up
+ \l{QPropertyAnimation}s.
+
+ \sa QAnimationGroup, QAbstractAnimation, {The Animation Framework}
+*/
+
+#include "qsequentialanimationgroup.h"
+#include "qsequentialanimationgroup_p.h"
+
+#include "qpauseanimation.h"
+
+#include <QtCore/qdebug.h>
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+bool QSequentialAnimationGroupPrivate::atEnd() const
+{
+ // we try to detect if we're at the end of the group
+ //this is true if the following conditions are true:
+ // 1. we're in the last loop
+ // 2. the direction is forward
+ // 3. the current animation is the last one
+ // 4. the current animation has reached its end
+ const int animTotalCurrentTime = QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime;
+ return (currentLoop == loopCount - 1
+ && direction == QAbstractAnimation::Forward
+ && currentAnimation == animations.last()
+ && animTotalCurrentTime == animationActualTotalDuration(currentAnimationIndex));
+}
+
+int QSequentialAnimationGroupPrivate::animationActualTotalDuration(int index) const
+{
+ QAbstractAnimation *anim = animations.at(index);
+ int ret = anim->totalDuration();
+ if (ret == -1 && actualDuration.size() > index)
+ ret = actualDuration.at(index); //we can try the actual duration there
+ return ret;
+}
+
+QSequentialAnimationGroupPrivate::AnimationIndex QSequentialAnimationGroupPrivate::indexForTime(int msecs) const
+{
+ Q_Q(const QSequentialAnimationGroup);
+ Q_ASSERT(!animations.isEmpty());
+
+ AnimationIndex ret;
+ int duration = 0;
+
+ // in case duration is -1, currentLoop will always be 0
+ ret.timeOffset = currentLoop * q->duration();
+
+ for (int i = 0; i < animations.size(); ++i) {
+ duration = animationActualTotalDuration(i);
+
+ // 'animation' is the current animation if one of these reasons is true:
+ // 1. it's duration is undefined
+ // 2. it ends after msecs
+ // 3. it is the last animation (this can happen in case there is at least 1 uncontrolled animation)
+ // 4. it ends exactly in msecs and the direction is backwards
+ if (duration == -1 || msecs < (ret.timeOffset + duration)
+ || (msecs == (ret.timeOffset + duration) && direction == QAbstractAnimation::Backward)) {
+ ret.index = i;
+ return ret;
+ }
+
+ // 'animation' has a non-null defined duration and is not the one at time 'msecs'.
+ ret.timeOffset += duration;
+ }
+
+ // this can only happen when one of those conditions is true:
+ // 1. the duration of the group is undefined and we passed its actual duration
+ // 2. there are only 0-duration animations in the group
+ ret.timeOffset -= duration;
+ ret.index = animations.size() - 1;
+ return ret;
+}
+
+void QSequentialAnimationGroupPrivate::restart()
+{
+ // restarting the group by making the first/last animation the current one
+ if (direction == QAbstractAnimation::Forward) {
+ lastLoop = 0;
+ if (currentAnimationIndex == 0)
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(0);
+ } else { // direction == QAbstractAnimation::Backward
+ lastLoop = loopCount - 1;
+ int index = animations.size() - 1;
+ if (currentAnimationIndex == index)
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(index);
+ }
+}
+
+/*!
+ \internal
+ This manages advancing the execution of a group running forwards (time has gone forward),
+ which is the same behaviour for rewinding the execution of a group running backwards
+ (time has gone backward).
+*/
+void QSequentialAnimationGroupPrivate::advanceForwards(const AnimationIndex &newAnimationIndex)
+{
+ if (lastLoop < currentLoop) {
+ // we need to fast forward to the end
+ for (int i = currentAnimationIndex; i < animations.size(); ++i) {
+ QAbstractAnimation *anim = animations.at(i);
+ setCurrentAnimation(i, true);
+ anim->setCurrentTime(animationActualTotalDuration(i));
+ }
+ // this will make sure the current animation is reset to the beginning
+ if (animations.size() == 1)
+ // we need to force activation because setCurrentAnimation will have no effect
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(0, true);
+ }
+
+ // and now we need to fast forward from the current position to
+ for (int i = currentAnimationIndex; i < newAnimationIndex.index; ++i) { //### WRONG,
+ QAbstractAnimation *anim = animations.at(i);
+ setCurrentAnimation(i, true);
+ anim->setCurrentTime(animationActualTotalDuration(i));
+ }
+ // setting the new current animation will happen later
+}
+
+/*!
+ \internal
+ This manages rewinding the execution of a group running forwards (time has gone forward),
+ which is the same behaviour for advancing the execution of a group running backwards
+ (time has gone backward).
+*/
+void QSequentialAnimationGroupPrivate::rewindForwards(const AnimationIndex &newAnimationIndex)
+{
+ if (lastLoop > currentLoop) {
+ // we need to fast rewind to the beginning
+ for (int i = currentAnimationIndex; i >= 0 ; --i) {
+ QAbstractAnimation *anim = animations.at(i);
+ setCurrentAnimation(i, true);
+ anim->setCurrentTime(0);
+ }
+ // this will make sure the current animation is reset to the end
+ if (animations.size() == 1)
+ // we need to force activation because setCurrentAnimation will have no effect
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(animations.count() - 1, true);
+ }
+
+ // and now we need to fast rewind from the current position to
+ for (int i = currentAnimationIndex; i > newAnimationIndex.index; --i) {
+ QAbstractAnimation *anim = animations.at(i);
+ setCurrentAnimation(i, true);
+ anim->setCurrentTime(0);
+ }
+ // setting the new current animation will happen later
+}
+
+/*!
+ \fn QSequentialAnimationGroup::currentAnimationChanged(QAbstractAnimation *current)
+
+ QSequentialAnimationGroup emits this signal when currentAnimation
+ has been changed. \a current is the current animation.
+
+ \sa currentAnimation()
+*/
+
+
+/*!
+ Constructs a QSequentialAnimationGroup.
+ \a parent is passed to QObject's constructor.
+*/
+QSequentialAnimationGroup::QSequentialAnimationGroup(QObject *parent)
+ : QAnimationGroup(*new QSequentialAnimationGroupPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QSequentialAnimationGroup::QSequentialAnimationGroup(QSequentialAnimationGroupPrivate &dd,
+ QObject *parent)
+ : QAnimationGroup(dd, parent)
+{
+}
+
+/*!
+ Destroys the animation group. It will also destroy all its animations.
+*/
+QSequentialAnimationGroup::~QSequentialAnimationGroup()
+{
+}
+
+/*!
+ Adds a pause of \a msecs to this animation group.
+ The pause is considered as a special type of animation, thus
+ \l{QAnimationGroup::animationCount()}{animationCount} will be
+ increased by one.
+
+ \sa insertPauseAt(), QAnimationGroup::addAnimation()
+*/
+QPauseAnimation *QSequentialAnimationGroup::addPause(int msecs)
+{
+ QPauseAnimation *pause = new QPauseAnimation(msecs);
+ addAnimation(pause);
+ return pause;
+}
+
+/*!
+ Inserts a pause of \a msecs milliseconds at \a index in this animation
+ group.
+
+ \sa addPause(), QAnimationGroup::insertAnimationAt()
+*/
+QPauseAnimation *QSequentialAnimationGroup::insertPauseAt(int index, int msecs)
+{
+ Q_D(const QSequentialAnimationGroup);
+
+ if (index < 0 || index > d->animations.size()) {
+ qWarning("QSequentialAnimationGroup::insertPauseAt: index is out of bounds");
+ return 0;
+ }
+
+ QPauseAnimation *pause = new QPauseAnimation(msecs);
+ insertAnimationAt(index, pause);
+ return pause;
+}
+
+
+/*!
+ \property QSequentialAnimationGroup::currentAnimation
+ Returns the animation in the current time.
+
+ \sa currentAnimationChanged()
+*/
+QAbstractAnimation *QSequentialAnimationGroup::currentAnimation() const
+{
+ Q_D(const QSequentialAnimationGroup);
+ return d->currentAnimation;
+}
+
+/*!
+ \reimp
+*/
+int QSequentialAnimationGroup::duration() const
+{
+ Q_D(const QSequentialAnimationGroup);
+ int ret = 0;
+
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ const int currentDuration = animation->totalDuration();
+ if (currentDuration == -1)
+ return -1; // Undetermined length
+
+ ret += currentDuration;
+ }
+
+ return ret;
+}
+
+/*!
+ \reimp
+*/
+void QSequentialAnimationGroup::updateCurrentTime(int msecs)
+{
+ Q_D(QSequentialAnimationGroup);
+ if (!d->currentAnimation)
+ return;
+
+ const QSequentialAnimationGroupPrivate::AnimationIndex newAnimationIndex = d->indexForTime(msecs);
+
+ // remove unneeded animations from actualDuration list
+ while (newAnimationIndex.index < d->actualDuration.size())
+ d->actualDuration.removeLast();
+
+ // newAnimationIndex.index is the new current animation
+ if (d->lastLoop < d->currentLoop
+ || (d->lastLoop == d->currentLoop && d->currentAnimationIndex < newAnimationIndex.index)) {
+ // advancing with forward direction is the same as rewinding with backwards direction
+ d->advanceForwards(newAnimationIndex);
+ } else if (d->lastLoop > d->currentLoop
+ || (d->lastLoop == d->currentLoop && d->currentAnimationIndex > newAnimationIndex.index)) {
+ // rewinding with forward direction is the same as advancing with backwards direction
+ d->rewindForwards(newAnimationIndex);
+ }
+
+ d->setCurrentAnimation(newAnimationIndex.index);
+
+ const int newCurrentTime = msecs - newAnimationIndex.timeOffset;
+
+ if (d->currentAnimation) {
+ d->currentAnimation->setCurrentTime(newCurrentTime);
+ if (d->atEnd()) {
+ //we make sure that we don't exceed the duration here
+ d->currentTime += QAbstractAnimationPrivate::get(d->currentAnimation)->totalCurrentTime - newCurrentTime;
+ stop();
+ }
+ } else {
+ //the only case where currentAnimation could be null
+ //is when all animations have been removed
+ Q_ASSERT(d->animations.isEmpty());
+ d->currentTime = 0;
+ stop();
+ }
+
+ d->lastLoop = d->currentLoop;
+}
+
+/*!
+ \reimp
+*/
+void QSequentialAnimationGroup::updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ Q_D(QSequentialAnimationGroup);
+ QAnimationGroup::updateState(oldState, newState);
+
+ if (!d->currentAnimation)
+ return;
+
+ switch (newState) {
+ case Stopped:
+ d->currentAnimation->stop();
+ break;
+ case Paused:
+ if (oldState == d->currentAnimation->state()
+ && oldState == QSequentialAnimationGroup::Running) {
+ d->currentAnimation->pause();
+ }
+ else
+ d->restart();
+ break;
+ case Running:
+ if (oldState == d->currentAnimation->state()
+ && oldState == QSequentialAnimationGroup::Paused)
+ d->currentAnimation->start();
+ else
+ d->restart();
+ break;
+ }
+}
+
+/*!
+ \reimp
+*/
+void QSequentialAnimationGroup::updateDirection(QAbstractAnimation::Direction direction)
+{
+ Q_D(QSequentialAnimationGroup);
+ // we need to update the direction of the current animation
+ if (state() != Stopped && d->currentAnimation)
+ d->currentAnimation->setDirection(direction);
+}
+
+/*!
+ \reimp
+*/
+bool QSequentialAnimationGroup::event(QEvent *event)
+{
+ return QAnimationGroup::event(event);
+}
+
+void QSequentialAnimationGroupPrivate::setCurrentAnimation(int index, bool intermediate)
+{
+ Q_Q(QSequentialAnimationGroup);
+
+ index = qMin(index, animations.count() - 1);
+
+ if (index == -1) {
+ Q_ASSERT(animations.isEmpty());
+ currentAnimationIndex = -1;
+ currentAnimation = 0;
+ return;
+ }
+
+ // need these two checks below because this func can be called after the current animation
+ // has been removed
+ if (index == currentAnimationIndex && animations.at(index) == currentAnimation)
+ return;
+
+ // stop the old current animation
+ if (currentAnimation)
+ currentAnimation->stop();
+
+ currentAnimation = animations.at(index);
+ currentAnimationIndex = index;
+
+ emit q->currentAnimationChanged(currentAnimation);
+
+ activateCurrentAnimation(intermediate);
+}
+
+void QSequentialAnimationGroupPrivate::activateCurrentAnimation(bool intermediate)
+{
+ Q_Q(QSequentialAnimationGroup);
+
+ if (!currentAnimation)
+ return;
+
+ if (state == QSequentialAnimationGroup::Stopped)
+ return;
+
+ currentAnimation->stop();
+
+ // we ensure the direction is consistent with the group's direction
+ currentAnimation->setDirection(direction);
+
+ // connects to the finish signal of uncontrolled animations
+ if (currentAnimation->totalDuration() == -1)
+ QObject::connect(currentAnimation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished()));
+
+ currentAnimation->start();
+ if (!intermediate && state == QSequentialAnimationGroup::Paused)
+ currentAnimation->pause();
+}
+
+void QSequentialAnimationGroupPrivate::_q_uncontrolledAnimationFinished()
+{
+ Q_Q(QSequentialAnimationGroup);
+ Q_ASSERT(qobject_cast<QAbstractAnimation *>(q->sender()) == currentAnimation);
+
+ // we trust the duration returned by the animation
+ while (actualDuration.size() < (currentAnimationIndex + 1))
+ actualDuration.append(-1);
+ actualDuration[currentAnimationIndex] = currentAnimation->currentTime();
+
+ QObject::disconnect(currentAnimation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished()));
+
+ if ((direction == QAbstractAnimation::Forward && currentAnimation == animations.last())
+ || (direction == QAbstractAnimation::Backward && currentAnimationIndex == 0)) {
+ // we don't handle looping of a group with undefined duration
+ q->stop();
+ } else if (direction == QAbstractAnimation::Forward) {
+ // set the current animation to be the next one
+ setCurrentAnimation(currentAnimationIndex + 1);
+ } else {
+ // set the current animation to be the previous one
+ setCurrentAnimation(currentAnimationIndex - 1);
+ }
+}
+
+/*!
+ \internal
+ This method is called whenever an animation is added to
+ the group at index \a index.
+ Note: We only support insertion after the current animation
+*/
+void QSequentialAnimationGroupPrivate::animationInsertedAt(int index)
+{
+ if (currentAnimation == 0)
+ setCurrentAnimation(0); // initialize the current animation
+
+ if (currentAnimationIndex == index
+ && currentAnimation->currentTime() == 0 && currentAnimation->currentLoop() == 0) {
+ //in this case we simply insert an animation before the current one has actually started
+ setCurrentAnimation(index);
+ }
+
+ //we update currentAnimationIndex in case it has changed (the animation pointer is still valid)
+ currentAnimationIndex = animations.indexOf(currentAnimation);
+
+ if (index < currentAnimationIndex || currentLoop != 0) {
+ qWarning("QSequentialGroup::insertAnimationAt only supports to add animations after the current one.");
+ return; //we're not affected because it is added after the current one
+ }
+}
+
+/*!
+ \internal
+ This method is called whenever an animation is removed from
+ the group at index \a index. The animation is no more listed when this
+ method is called.
+*/
+void QSequentialAnimationGroupPrivate::animationRemovedAt(int index)
+{
+ Q_Q(QSequentialAnimationGroup);
+ QAnimationGroupPrivate::animationRemovedAt(index);
+
+ Q_ASSERT(currentAnimation); // currentAnimation should always be set
+
+ if (actualDuration.size() > index)
+ actualDuration.removeAt(index);
+
+ const int currentIndex = animations.indexOf(currentAnimation);
+ if (currentIndex == -1) {
+ //we're removing the current animation, let's update it to another one
+ if (index < animations.count())
+ setCurrentAnimation(index); //let's try to take the next one
+ else if (index > 0)
+ setCurrentAnimation(index - 1);
+ else// case all animations were removed
+ setCurrentAnimation(-1);
+ } else if (currentAnimationIndex > index) {
+ currentAnimationIndex--;
+ }
+
+ // duration of the previous animations up to the current animation
+ currentTime = 0;
+ for (int i = 0; i < currentAnimationIndex; ++i) {
+ const int current = animationActualTotalDuration(i);
+ currentTime += current;
+ }
+
+ if (currentIndex != -1) {
+ //the current animation is not the one being removed
+ //so we add its current time to the current time of this group
+ currentTime += QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime;
+ }
+
+ //let's also update the total current time
+ totalCurrentTime = currentTime + loopCount * q->duration();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qsequentialanimationgroup.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qsequentialanimationgroup.h b/src/corelib/animation/qsequentialanimationgroup.h
new file mode 100644
index 0000000..920c36c
--- /dev/null
+++ b/src/corelib/animation/qsequentialanimationgroup.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSEQUENTIALANIMATIONGROUP_H
+#define QSEQUENTIALANIMATIONGROUP_H
+
+#include <QtCore/qanimationgroup.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QPauseAnimation;
+class QSequentialAnimationGroupPrivate;
+
+class Q_CORE_EXPORT QSequentialAnimationGroup : public QAnimationGroup
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractAnimation* currentAnimation READ currentAnimation NOTIFY currentAnimationChanged)
+
+public:
+ QSequentialAnimationGroup(QObject *parent = 0);
+ ~QSequentialAnimationGroup();
+
+ QPauseAnimation *addPause(int msecs);
+ QPauseAnimation *insertPauseAt(int index, int msecs);
+
+ QAbstractAnimation *currentAnimation() const;
+ int duration() const;
+
+Q_SIGNALS:
+ void currentAnimationChanged(QAbstractAnimation *current);
+
+protected:
+ QSequentialAnimationGroup(QSequentialAnimationGroupPrivate &dd, QObject *parent);
+ bool event(QEvent *event);
+
+ void updateCurrentTime(int msecs);
+ void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+ void updateDirection(QAbstractAnimation::Direction direction);
+
+private:
+ Q_DISABLE_COPY(QSequentialAnimationGroup)
+ Q_DECLARE_PRIVATE(QSequentialAnimationGroup)
+ Q_PRIVATE_SLOT(d_func(), void _q_uncontrolledAnimationFinished())
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QSEQUENTIALANIMATIONGROUP_H
diff --git a/src/corelib/animation/qsequentialanimationgroup_p.h b/src/corelib/animation/qsequentialanimationgroup_p.h
new file mode 100644
index 0000000..2b80742
--- /dev/null
+++ b/src/corelib/animation/qsequentialanimationgroup_p.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSEQUENTIALANIMATIONGROUP_P_H
+#define QSEQUENTIALANIMATIONGROUP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qsequentialanimationgroup.h"
+#include "private/qanimationgroup_p.h"
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+class QSequentialAnimationGroupPrivate : public QAnimationGroupPrivate
+{
+ Q_DECLARE_PUBLIC(QSequentialAnimationGroup)
+public:
+ QSequentialAnimationGroupPrivate()
+ : currentAnimation(0), currentAnimationIndex(-1), lastLoop(0)
+ { }
+
+
+ struct AnimationIndex
+ {
+ AnimationIndex() : index(0), timeOffset(0) {}
+ // index points to the animation at timeOffset, skipping 0 duration animations.
+ // Note that the index semantic is slightly different depending on the direction.
+ int index; // the index of the animation in timeOffset
+ int timeOffset; // time offset when the animation at index starts.
+ };
+
+ int animationActualTotalDuration(int index) const;
+ AnimationIndex indexForTime(int msecs) const;
+
+ void setCurrentAnimation(int index, bool intermediate = false);
+ void activateCurrentAnimation(bool intermediate = false);
+
+ void animationInsertedAt(int index);
+ void animationRemovedAt(int index);
+
+ bool atEnd() const;
+
+ QAbstractAnimation *currentAnimation;
+ int currentAnimationIndex;
+
+ // this is the actual duration of uncontrolled animations
+ // it helps seeking and even going forward
+ QList<int> actualDuration;
+
+ void restart();
+ int lastLoop;
+
+ // handle time changes
+ void rewindForwards(const AnimationIndex &newAnimationIndex);
+ void advanceForwards(const AnimationIndex &newAnimationIndex);
+
+ // private slot
+ void _q_uncontrolledAnimationFinished();
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ANIMATION
+
+#endif //QSEQUENTIALANIMATIONGROUP_P_H
diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp
new file mode 100644
index 0000000..696a95a
--- /dev/null
+++ b/src/corelib/animation/qvariantanimation.cpp
@@ -0,0 +1,669 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvariantanimation.h"
+#include "qvariantanimation_p.h"
+
+#include <QtCore/qrect.h>
+#include <QtCore/qline.h>
+#include <QtCore/qmutex.h>
+#include <private/qmutexpool_p.h>
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QVariantAnimation
+ \ingroup animation
+ \brief The QVariantAnimation class provides an abstract base class for animations.
+ \since 4.6
+
+ This class is part of \l{The Animation Framework}. It serves as a
+ base class for property and item animations, with functions for
+ shared functionality.
+
+ QVariantAnimation cannot be used directly as it is an abstract
+ class; it has a pure virtual method called updateCurrentValue().
+ The class performs interpolation over
+ \l{QVariant}s, but leaves using the interpolated values to its
+ subclasses. Currently, Qt provides QPropertyAnimation, which
+ animates Qt \l{Qt's Property System}{properties}. See the
+ QPropertyAnimation class description if you wish to animate such
+ properties.
+
+ You can then set start and end values for the property by calling
+ setStartValue() and setEndValue(), and finally call start() to
+ start the animation. QVariantAnimation will interpolate the
+ property of the target object and emit valueChanged(). To react to
+ a change in the current value you have to reimplement the
+ updateCurrentValue() virtual function.
+
+ It is also possible to set values at specified steps situated
+ between the start and end value. The interpolation will then
+ touch these points at the specified steps. Note that the start and
+ end values are defined as the key values at 0.0 and 1.0.
+
+ There are two ways to affect how QVariantAnimation interpolates
+ the values. You can set an easing curve by calling
+ setEasingCurve(), and configure the duration by calling
+ setDuration(). You can change how the QVariants are interpolated
+ by creating a subclass of QVariantAnimation, and reimplementing
+ the virtual interpolated() function.
+
+ Subclassing QVariantAnimation can be an alternative if you have
+ \l{QVariant}s that you do not wish to declare as Qt properties.
+ Note, however, that you in most cases will be better off declaring
+ your QVariant as a property.
+
+ Not all QVariant types are supported. Below is a list of currently
+ supported QVariant types:
+
+ \list
+ \o \l{QMetaType::}{Int}
+ \o \l{QMetaType::}{Double}
+ \o \l{QMetaType::}{Float}
+ \o \l{QMetaType::}{QLine}
+ \o \l{QMetaType::}{QLineF}
+ \o \l{QMetaType::}{QPoint}
+ \o \l{QMetaType::}{QSize}
+ \o \l{QMetaType::}{QSizeF}
+ \o \l{QMetaType::}{QRect}
+ \o \l{QMetaType::}{QRectF}
+ \endlist
+
+ If you need to interpolate other variant types, including custom
+ types, you have to implement interpolation for these yourself.
+ You do this by reimplementing interpolated(), which returns
+ interpolation values for the value being interpolated.
+
+ \omit We need some snippets around here. \endomit
+
+ \sa QPropertyAnimation, QAbstractAnimation, {The Animation Framework}
+*/
+
+/*!
+ \fn void QVariantAnimation::valueChanged(const QVariant &value)
+
+ QVariantAnimation emits this signal whenever the current \a value changes.
+
+ \sa currentValue, startValue, endValue
+*/
+
+/*!
+ \fn void QVariantAnimation::updateCurrentValue(const QVariant &value) = 0;
+
+ This pure virtual function is called every time the animation's current
+ value changes. The \a value argument is the new current value.
+
+ \sa currentValue
+*/
+
+static bool animationValueLessThan(const QVariantAnimation::KeyValue &p1, const QVariantAnimation::KeyValue &p2)
+{
+ return p1.first < p2.first;
+}
+
+static QVariant defaultInterpolator(const void *, const void *, qreal)
+{
+ return QVariant();
+}
+
+template<> Q_INLINE_TEMPLATE QRect _q_interpolate(const QRect &f, const QRect &t, qreal progress)
+{
+ QRect ret;
+ ret.setCoords(_q_interpolate(f.left(), t.left(), progress),
+ _q_interpolate(f.top(), t.top(), progress),
+ _q_interpolate(f.right(), t.right(), progress),
+ _q_interpolate(f.bottom(), t.bottom(), progress));
+ return ret;
+}
+
+template<> Q_INLINE_TEMPLATE QRectF _q_interpolate(const QRectF &f, const QRectF &t, qreal progress)
+{
+ qreal x1, y1, w1, h1;
+ f.getRect(&x1, &y1, &w1, &h1);
+ qreal x2, y2, w2, h2;
+ t.getRect(&x2, &y2, &w2, &h2);
+ return QRectF(_q_interpolate(x1, x2, progress), _q_interpolate(y1, y2, progress),
+ _q_interpolate(w1, w2, progress), _q_interpolate(h1, h2, progress));
+}
+
+template<> Q_INLINE_TEMPLATE QLine _q_interpolate(const QLine &f, const QLine &t, qreal progress)
+{
+ return QLine( _q_interpolate(f.p1(), t.p1(), progress), _q_interpolate(f.p2(), t.p2(), progress));
+}
+
+template<> Q_INLINE_TEMPLATE QLineF _q_interpolate(const QLineF &f, const QLineF &t, qreal progress)
+{
+ return QLineF( _q_interpolate(f.p1(), t.p1(), progress), _q_interpolate(f.p2(), t.p2(), progress));
+}
+
+QVariantAnimationPrivate::QVariantAnimationPrivate() : duration(250), interpolator(&defaultInterpolator)
+{ }
+
+void QVariantAnimationPrivate::convertValues(int t)
+{
+ //this ensures that all the keyValues are of type t
+ for (int i = 0; i < keyValues.count(); ++i) {
+ QVariantAnimation::KeyValue &pair = keyValues[i];
+ pair.second.convert(static_cast<QVariant::Type>(t));
+ }
+ //we also need update to the current interval if needed
+ currentInterval.start.second.convert(static_cast<QVariant::Type>(t));
+ currentInterval.end.second.convert(static_cast<QVariant::Type>(t));
+
+ //... and the interpolator
+ updateInterpolator();
+}
+
+void QVariantAnimationPrivate::updateInterpolator()
+{
+ int type = currentInterval.start.second.userType();
+ if (type == currentInterval.end.second.userType())
+ interpolator = getInterpolator(type);
+ else
+ interpolator = 0;
+
+ //we make sure that the interpolator is always set to something
+ if (!interpolator)
+ interpolator = &defaultInterpolator;
+}
+
+/*!
+ \internal
+ The goal of this function is to update the currentInterval member. As a consequence, we also
+ need to update the currentValue.
+ Set \a force to true to always recalculate the interval.
+*/
+void QVariantAnimationPrivate::recalculateCurrentInterval(bool force/*=false*/)
+{
+ // can't interpolate if we don't have at least 2 values
+ if ((keyValues.count() + (defaultStartEndValue.isValid() ? 1 : 0)) < 2)
+ return;
+
+ const qreal progress = easing.valueForProgress(((duration == 0) ? qreal(1) : qreal(currentTime) / qreal(duration)));
+
+ //0 and 1 are still the boundaries
+ if (force || (currentInterval.start.first > 0 && progress < currentInterval.start.first)
+ || (currentInterval.end.first < 1 && progress > currentInterval.end.first)) {
+ //let's update currentInterval
+ QVariantAnimation::KeyValues::const_iterator it = qLowerBound(keyValues.constBegin(),
+ keyValues.constEnd(),
+ qMakePair(progress, QVariant()),
+ animationValueLessThan);
+ if (it == keyValues.constBegin()) {
+ //the item pointed to by it is the start element in the range
+ if (it->first == 0 && keyValues.count() > 1) {
+ currentInterval.start = *it;
+ currentInterval.end = *(it+1);
+ } else {
+ currentInterval.start = qMakePair(qreal(0), defaultStartEndValue);
+ currentInterval.end = *it;
+ }
+ } else if (it == keyValues.constEnd()) {
+ --it; //position the iterator on the last item
+ if (it->first == 1 && keyValues.count() > 1) {
+ //we have an end value (item with progress = 1)
+ currentInterval.start = *(it-1);
+ currentInterval.end = *it;
+ } else {
+ //we use the default end value here
+ currentInterval.start = *it;
+ currentInterval.end = qMakePair(qreal(1), defaultStartEndValue);
+ }
+ } else {
+ currentInterval.start = *(it-1);
+ currentInterval.end = *it;
+ }
+
+ // update all the values of the currentInterval
+ updateInterpolator();
+ }
+ setCurrentValueForProgress(progress);
+}
+
+void QVariantAnimationPrivate::setCurrentValueForProgress(const qreal progress)
+{
+ Q_Q(QVariantAnimation);
+
+ const qreal startProgress = currentInterval.start.first;
+ const qreal endProgress = currentInterval.end.first;
+ const qreal localProgress = (progress - startProgress) / (endProgress - startProgress);
+
+ QVariant ret = q->interpolated(currentInterval.start.second,
+ currentInterval.end.second,
+ localProgress);
+ qSwap(currentValue, ret);
+ q->updateCurrentValue(currentValue);
+ static QBasicAtomicInt changedSignalIndex = Q_BASIC_ATOMIC_INITIALIZER(0);
+ if (!changedSignalIndex) {
+ //we keep the mask so that we emit valueChanged only when needed (for performance reasons)
+ changedSignalIndex.testAndSetRelaxed(0, signalIndex("valueChanged(QVariant)"));
+ }
+ if (isSignalConnected(changedSignalIndex) && currentValue != ret) {
+ //the value has changed
+ emit q->valueChanged(currentValue);
+ }
+}
+
+QVariant QVariantAnimationPrivate::valueAt(qreal step) const
+{
+ QVariantAnimation::KeyValues::const_iterator result =
+ qBinaryFind(keyValues.begin(), keyValues.end(), qMakePair(step, QVariant()), animationValueLessThan);
+ if (result != keyValues.constEnd())
+ return result->second;
+
+ return QVariant();
+}
+
+void QVariantAnimationPrivate::setValueAt(qreal step, const QVariant &value)
+{
+ if (step < qreal(0.0) || step > qreal(1.0)) {
+ qWarning("QVariantAnimation::setValueAt: invalid step = %f", step);
+ return;
+ }
+
+ QVariantAnimation::KeyValue pair(step, value);
+
+ QVariantAnimation::KeyValues::iterator result = qLowerBound(keyValues.begin(), keyValues.end(), pair, animationValueLessThan);
+ if (result == keyValues.end() || result->first != step) {
+ keyValues.insert(result, pair);
+ } else {
+ if (value.isValid())
+ result->second = value; // replaces the previous value
+ else
+ keyValues.erase(result); // removes the previous value
+ }
+
+ recalculateCurrentInterval(/*force=*/true);
+}
+
+void QVariantAnimationPrivate::setDefaultStartEndValue(const QVariant &value)
+{
+ defaultStartEndValue = value;
+ recalculateCurrentInterval(/*force=*/true);
+}
+
+/*!
+ Construct a QVariantAnimation object. \a parent is passed to QAbstractAnimation's
+ constructor.
+*/
+QVariantAnimation::QVariantAnimation(QObject *parent) : QAbstractAnimation(*new QVariantAnimationPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QVariantAnimation::QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent) : QAbstractAnimation(dd, parent)
+{
+}
+
+/*!
+ Destroys the animation.
+*/
+QVariantAnimation::~QVariantAnimation()
+{
+}
+
+/*!
+ \property QVariantAnimation::easingCurve
+ \brief the easing curve of the animation
+
+ This property defines the easing curve of the animation. By
+ default, a linear easing curve is used, resulting in linear
+ interpolation. Other curves are provided, for instance,
+ QEasingCurve::InCirc, which provides a circular entry curve.
+ Another example is QEasingCurve::InOutElastic, which provides an
+ elastic effect on the values of the interpolated variant.
+
+ The easing curve is used with the interpolator, the interpolated()
+ virtual function, the animation's duration, and iterationCount, to
+ control how the current value changes as the animation progresses.
+*/
+QEasingCurve QVariantAnimation::easingCurve() const
+{
+ Q_D(const QVariantAnimation);
+ return d->easing;
+}
+
+void QVariantAnimation::setEasingCurve(const QEasingCurve &easing)
+{
+ Q_D(QVariantAnimation);
+ d->easing = easing;
+ d->recalculateCurrentInterval();
+}
+
+typedef QVector<QVariantAnimation::Interpolator> QInterpolatorVector;
+Q_GLOBAL_STATIC(QInterpolatorVector, registeredInterpolators)
+
+/*!
+ \fn void qRegisterAnimationInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress))
+ \relates QVariantAnimation
+ \threadsafe
+
+ Registers a custom interpolator \a func for the template type \c{T}.
+ The interpolator has to be registered before the animation is constructed.
+ To unregister (and use the default interpolator) set \a func to 0.
+ */
+
+/*!
+ \internal
+ \typedef QVariantAnimation::Interpolator
+
+ This is a typedef for a pointer to a function with the following
+ signature:
+ \code
+ QVariant myInterpolator(const QVariant &from, const QVariant &to, qreal progress);
+ \endcode
+
+*/
+
+/*! \internal
+ * Registers a custom interpolator \a func for the specific \a interpolationType.
+ * The interpolator has to be registered before the animation is constructed.
+ * To unregister (and use the default interpolator) set \a func to 0.
+ */
+void QVariantAnimation::registerInterpolator(QVariantAnimation::Interpolator func, int interpolationType)
+{
+ // will override any existing interpolators
+ QInterpolatorVector *interpolators = registeredInterpolators();
+ QMutexLocker locker(QMutexPool::globalInstanceGet(interpolators));
+ if (int(interpolationType) >= interpolators->count())
+ interpolators->resize(int(interpolationType) + 1);
+ interpolators->replace(interpolationType, func);
+}
+
+
+template<typename T> static inline QVariantAnimation::Interpolator castToInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress))
+{
+ return reinterpret_cast<QVariantAnimation::Interpolator>(func);
+}
+
+QVariantAnimation::Interpolator QVariantAnimationPrivate::getInterpolator(int interpolationType)
+{
+ QInterpolatorVector *interpolators = registeredInterpolators();
+ QMutexLocker locker(QMutexPool::globalInstanceGet(interpolators));
+ QVariantAnimation::Interpolator ret = 0;
+ if (interpolationType < interpolators->count()) {
+ ret = interpolators->at(interpolationType);
+ if (ret) return ret;
+ }
+
+ switch(interpolationType)
+ {
+ case QMetaType::Int:
+ return castToInterpolator(_q_interpolateVariant<int>);
+ case QMetaType::Double:
+ return castToInterpolator(_q_interpolateVariant<double>);
+ case QMetaType::Float:
+ return castToInterpolator(_q_interpolateVariant<float>);
+ case QMetaType::QLine:
+ return castToInterpolator(_q_interpolateVariant<QLine>);
+ case QMetaType::QLineF:
+ return castToInterpolator(_q_interpolateVariant<QLineF>);
+ case QMetaType::QPoint:
+ return castToInterpolator(_q_interpolateVariant<QPoint>);
+ case QMetaType::QPointF:
+ return castToInterpolator(_q_interpolateVariant<QPointF>);
+ case QMetaType::QSize:
+ return castToInterpolator(_q_interpolateVariant<QSize>);
+ case QMetaType::QSizeF:
+ return castToInterpolator(_q_interpolateVariant<QSizeF>);
+ case QMetaType::QRect:
+ return castToInterpolator(_q_interpolateVariant<QRect>);
+ case QMetaType::QRectF:
+ return castToInterpolator(_q_interpolateVariant<QRectF>);
+ default:
+ return 0; //this type is not handled
+ }
+}
+
+/*!
+ \property QVariantAnimation::duration
+ \brief the duration of the animation
+
+ This property describes the duration in milliseconds of the
+ animation. The default duration is 250 milliseconds.
+
+ \sa QAbstractAnimation::duration()
+ */
+int QVariantAnimation::duration() const
+{
+ Q_D(const QVariantAnimation);
+ return d->duration;
+}
+
+void QVariantAnimation::setDuration(int msecs)
+{
+ Q_D(QVariantAnimation);
+ if (msecs < 0) {
+ qWarning("QVariantAnimation::setDuration: cannot set a negative duration");
+ return;
+ }
+ if (d->duration == msecs)
+ return;
+ d->duration = msecs;
+ d->recalculateCurrentInterval();
+}
+
+/*!
+ \property QVariantAnimation::startValue
+ \brief the optional start value of the animation
+
+ This property describes the optional start value of the animation. If
+ omitted, or if a null QVariant is assigned as the start value, the
+ animation will use the current position of the end when the animation
+ is started.
+
+ \sa endValue
+*/
+QVariant QVariantAnimation::startValue() const
+{
+ return keyValueAt(0);
+}
+
+void QVariantAnimation::setStartValue(const QVariant &value)
+{
+ setKeyValueAt(0, value);
+}
+
+/*!
+ \property QVariantAnimation::endValue
+ \brief the end value of the animation
+
+ This property describes the end value of the animation.
+
+ \sa startValue
+ */
+QVariant QVariantAnimation::endValue() const
+{
+ return keyValueAt(1);
+}
+
+void QVariantAnimation::setEndValue(const QVariant &value)
+{
+ setKeyValueAt(1, value);
+}
+
+
+/*!
+ Returns the key frame value for the given \a step. The given \a step
+ must be in the range 0 to 1. If there is no KeyValue for \a step,
+ it returns an invalid QVariant.
+
+ \sa keyValues(), setKeyValueAt()
+*/
+QVariant QVariantAnimation::keyValueAt(qreal step) const
+{
+ return d_func()->valueAt(step);
+}
+
+/*!
+ \typedef QVariantAnimation::KeyValue
+
+ This is a typedef for QPair<qreal, QVariant>.
+*/
+/*!
+ \typedef QVariantAnimation::KeyValues
+
+ This is a typedef for QVector<KeyValue>
+*/
+
+/*!
+ Creates a key frame at the given \a step with the given \a value.
+ The given \a step must be in the range 0 to 1.
+
+ \sa setKeyValues(), keyValueAt()
+*/
+void QVariantAnimation::setKeyValueAt(qreal step, const QVariant &value)
+{
+ d_func()->setValueAt(step, value);
+}
+
+/*!
+ Returns the key frames of this animation.
+
+ \sa keyValueAt(), setKeyValues()
+*/
+QVariantAnimation::KeyValues QVariantAnimation::keyValues() const
+{
+ return d_func()->keyValues;
+}
+
+/*!
+ Replaces the current set of key frames with the given \a keyValues.
+ the step of the key frames must be in the range 0 to 1.
+
+ \sa keyValues(), keyValueAt()
+*/
+void QVariantAnimation::setKeyValues(const KeyValues &keyValues)
+{
+ Q_D(QVariantAnimation);
+ d->keyValues = keyValues;
+ qSort(d->keyValues.begin(), d->keyValues.end(), animationValueLessThan);
+ d->recalculateCurrentInterval(/*force=*/true);
+}
+
+/*!
+ \property QVariantAnimation::currentValue
+ \brief the current value of the animation.
+
+ This property describes the current value; an interpolated value
+ between the \l{startValue}{start value} and the \l{endValue}{end
+ value}, using the current time for progress. The value itself is
+ obtained from interpolated(), which is called repeatedly as the
+ animation is running.
+
+ QVariantAnimation calls the virtual updateCurrentValue() function
+ when the current value changes. This is particularly useful for
+ subclasses that need to track updates. For example,
+ QPropertyAnimation uses this function to animate Qt \l{Qt's
+ Property System}{properties}.
+
+ \sa startValue, endValue
+*/
+QVariant QVariantAnimation::currentValue() const
+{
+ Q_D(const QVariantAnimation);
+ if (!d->currentValue.isValid())
+ const_cast<QVariantAnimationPrivate*>(d)->recalculateCurrentInterval();
+ return d->currentValue;
+}
+
+/*!
+ \reimp
+ */
+bool QVariantAnimation::event(QEvent *event)
+{
+ return QAbstractAnimation::event(event);
+}
+
+/*!
+ \reimp
+*/
+void QVariantAnimation::updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ Q_UNUSED(oldState);
+ Q_UNUSED(newState);
+}
+
+/*!
+
+ This virtual function returns the linear interpolation between
+ variants \a from and \a to, at \a progress, usually a value
+ between 0 and 1. You can reimplement this function in a subclass
+ of QVariantAnimation to provide your own interpolation algorithm.
+
+ Note that in order for the interpolation to work with a
+ QEasingCurve that return a value smaller than 0 or larger than 1
+ (such as QEasingCurve::InBack) you should make sure that it can
+ extrapolate. If the semantic of the datatype does not allow
+ extrapolation this function should handle that gracefully.
+
+ You should call the QVariantAnimation implementation of this
+ function if you want your class to handle the types already
+ supported by Qt (see class QVariantAnimation description for a
+ list of supported types).
+
+ \sa QEasingCurve
+ */
+QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const
+{
+ return d_func()->interpolator(from.constData(), to.constData(), progress);
+}
+
+/*!
+ \reimp
+ */
+void QVariantAnimation::updateCurrentTime(int msecs)
+{
+ Q_UNUSED(msecs);
+ d_func()->recalculateCurrentInterval();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qvariantanimation.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qvariantanimation.h b/src/corelib/animation/qvariantanimation.h
new file mode 100644
index 0000000..3c979a9
--- /dev/null
+++ b/src/corelib/animation/qvariantanimation.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATION_H
+#define QANIMATION_H
+
+#include <QtCore/qeasingcurve.h>
+#include <QtCore/qabstractanimation.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qpair.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QVariantAnimationPrivate;
+class Q_CORE_EXPORT QVariantAnimation : public QAbstractAnimation
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant startValue READ startValue WRITE setStartValue)
+ Q_PROPERTY(QVariant endValue READ endValue WRITE setEndValue)
+ Q_PROPERTY(QVariant currentValue READ currentValue NOTIFY valueChanged)
+ Q_PROPERTY(int duration READ duration WRITE setDuration)
+ Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve)
+
+public:
+ typedef QPair<qreal, QVariant> KeyValue;
+ typedef QVector<KeyValue> KeyValues;
+
+ QVariantAnimation(QObject *parent = 0);
+ ~QVariantAnimation();
+
+ QVariant startValue() const;
+ void setStartValue(const QVariant &value);
+
+ QVariant endValue() const;
+ void setEndValue(const QVariant &value);
+
+ QVariant keyValueAt(qreal step) const;
+ void setKeyValueAt(qreal step, const QVariant &value);
+
+ KeyValues keyValues() const;
+ void setKeyValues(const KeyValues &values);
+
+ QVariant currentValue() const;
+
+ int duration() const;
+ void setDuration(int msecs);
+
+ QEasingCurve easingCurve() const;
+ void setEasingCurve(const QEasingCurve &easing);
+
+ typedef QVariant (*Interpolator)(const void *from, const void *to, qreal progress);
+
+Q_SIGNALS:
+ void valueChanged(const QVariant &value);
+
+protected:
+ QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent = 0);
+ bool event(QEvent *event);
+
+ void updateCurrentTime(int msecs);
+ void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+
+ virtual void updateCurrentValue(const QVariant &value) = 0;
+ virtual QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) const;
+
+private:
+ template <typename T> friend void qRegisterAnimationInterpolator(QVariant (*func)(const T &, const T &, qreal));
+ static void registerInterpolator(Interpolator func, int interpolationType);
+
+ Q_DISABLE_COPY(QVariantAnimation)
+ Q_DECLARE_PRIVATE(QVariantAnimation)
+};
+
+template <typename T>
+void qRegisterAnimationInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) {
+ QVariantAnimation::registerInterpolator(reinterpret_cast<QVariantAnimation::Interpolator>(func), qMetaTypeId<T>());
+}
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QANIMATION_H
diff --git a/src/corelib/animation/qvariantanimation_p.h b/src/corelib/animation/qvariantanimation_p.h
new file mode 100644
index 0000000..da120df
--- /dev/null
+++ b/src/corelib/animation/qvariantanimation_p.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATION_P_H
+#define QANIMATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qvariantanimation.h"
+#include <QtCore/qeasingcurve.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qvector.h>
+
+#include "private/qabstractanimation_p.h"
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+class QVariantAnimationPrivate : public QAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QVariantAnimation)
+public:
+
+ QVariantAnimationPrivate();
+
+ static QVariantAnimationPrivate *get(QVariantAnimation *q)
+ {
+ return q->d_func();
+ }
+
+ void setDefaultStartEndValue(const QVariant &value);
+
+
+ QVariant currentValue;
+ QVariant defaultStartEndValue;
+
+ //this is used to keep track of the KeyValue interval in which we currently are
+ struct
+ {
+ QVariantAnimation::KeyValue start, end;
+ } currentInterval;
+
+ QEasingCurve easing;
+ int duration;
+ QVariantAnimation::KeyValues keyValues;
+ QVariantAnimation::Interpolator interpolator;
+
+ void setCurrentValueForProgress(const qreal progress);
+ void recalculateCurrentInterval(bool force=false);
+ void setValueAt(qreal, const QVariant &);
+ QVariant valueAt(qreal step) const;
+ void convertValues(int t);
+
+ void updateInterpolator();
+
+ //XXX this is needed by dui
+ static Q_CORE_EXPORT QVariantAnimation::Interpolator getInterpolator(int interpolationType);
+};
+
+//this should make the interpolation faster
+template<typename T> inline T _q_interpolate(const T &f, const T &t, qreal progress)
+{
+ return T(f + (t - f) * progress);
+}
+
+template<typename T > inline QVariant _q_interpolateVariant(const T &from, const T &to, qreal progress)
+{
+ return _q_interpolate(from, to, progress);
+}
+
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ANIMATION
+
+#endif //QANIMATION_P_H
diff --git a/src/corelib/arch/arch.pri b/src/corelib/arch/arch.pri
index 20b9227..a25027b 100644
--- a/src/corelib/arch/arch.pri
+++ b/src/corelib/arch/arch.pri
@@ -4,7 +4,12 @@ win32:HEADERS += arch/qatomic_windows.h \
mac:HEADERS += arch/qatomic_macosx.h \
arch/qatomic_generic.h
-!wince*:!win32:!mac:HEADERS += arch/qatomic_alpha.h \
+symbian:HEADERS += arch/qatomic_symbian.h \
+ arch/qatomic_generic.h
+
+vxworks:HEADERS += arch/qatomic_vxworks.h
+
+!wince*:!win32:!mac:!symbian:HEADERS += arch/qatomic_alpha.h \
arch/qatomic_avr32.h \
arch/qatomic_ia64.h \
arch/qatomic_parisc.h \
@@ -23,4 +28,4 @@ mac:HEADERS += arch/qatomic_macosx.h \
QT_ARCH_CPP = $$QT_SOURCE_TREE/src/corelib/arch/$$QT_ARCH
DEPENDPATH += $$QT_ARCH_CPP
-include($$QT_ARCH_CPP/arch.pri)
+include($$QT_ARCH_CPP/arch.pri, "", true)
diff --git a/src/corelib/arch/generic/qatomic_generic_unix.cpp b/src/corelib/arch/generic/qatomic_generic_unix.cpp
index f7f7e63..205455b 100644
--- a/src/corelib/arch/generic/qatomic_generic_unix.cpp
+++ b/src/corelib/arch/generic/qatomic_generic_unix.cpp
@@ -39,10 +39,13 @@
**
****************************************************************************/
+#if !defined(Q_OS_SYMBIAN) || (defined(Q_OS_SYMBIAN) && !defined(Q_CC_RVCT))
+
#include "qplatformdefs.h"
#include <QtCore/qatomic.h>
+QT_BEGIN_NAMESPACE
static pthread_mutex_t qAtomicMutex = PTHREAD_MUTEX_INITIALIZER;
Q_CORE_EXPORT
@@ -116,3 +119,5 @@ void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *_q_value, qptrdiff
pthread_mutex_unlock(&qAtomicMutex);
return returnValue;
}
+QT_END_NAMESPACE
+#endif //!defined(Q_OS_SYMBIAN) && !defined(Q_CC_RVCT)
diff --git a/src/corelib/arch/qatomic_arch.h b/src/corelib/arch/qatomic_arch.h
index 0f7f379..f7e79e7 100644
--- a/src/corelib/arch/qatomic_arch.h
+++ b/src/corelib/arch/qatomic_arch.h
@@ -46,7 +46,9 @@ QT_BEGIN_HEADER
#include "QtCore/qglobal.h"
-#if defined(QT_ARCH_ALPHA)
+#if defined(QT_ARCH_VXWORKS)
+# include "QtCore/qatomic_vxworks.h"
+#elif defined(QT_ARCH_ALPHA)
# include "QtCore/qatomic_alpha.h"
#elif defined(QT_ARCH_ARM)
# include "QtCore/qatomic_arm.h"
@@ -80,6 +82,8 @@ QT_BEGIN_HEADER
# include "QtCore/qatomic_windowsce.h"
#elif defined(QT_ARCH_X86_64)
# include "QtCore/qatomic_x86_64.h"
+#elif defined(QT_ARCH_SYMBIAN)
+# include "QtCore/qatomic_symbian.h"
#elif defined(QT_ARCH_SH)
# include "QtCore/qatomic_sh.h"
#elif defined(QT_ARCH_SH4A)
diff --git a/src/corelib/arch/qatomic_arm.h b/src/corelib/arch/qatomic_arm.h
index e3978be..65f4140 100644
--- a/src/corelib/arch/qatomic_arm.h
+++ b/src/corelib/arch/qatomic_arm.h
@@ -116,6 +116,12 @@ extern "C" typedef int (qt_atomic_eabi_cmpxchg_ptr_t)(void *oldval, void *newval
extern Q_CORE_EXPORT char q_atomic_lock;
Q_CORE_EXPORT void qt_atomic_yield(int *);
+#ifdef Q_CC_RVCT
+
+Q_CORE_EXPORT __asm char q_atomic_swp(volatile char *ptr, char newval);
+
+#else
+
inline char q_atomic_swp(volatile char *ptr, char newval)
{
register char ret;
@@ -126,7 +132,9 @@ inline char q_atomic_swp(volatile char *ptr, char newval)
return ret;
}
-#endif
+#endif // Q_CC_RVCT
+
+#endif // QT_NO_ARM_EABI
// Reference counting
@@ -213,6 +221,8 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue)
// Fetch and store for integers
+#ifndef Q_CC_RVCT
+
inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue)
{
int originalValue;
@@ -223,6 +233,8 @@ inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue)
return originalValue;
}
+#endif
+
inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue)
{
return fetchAndStoreOrdered(newValue);
@@ -323,6 +335,22 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValu
// Fetch and store for pointers
+#ifdef Q_CC_RVCT
+
+template <typename T>
+__asm T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
+{
+ add r2, pc, #0
+ bx r2
+ arm
+ swp r2,r1,[r0]
+ mov r0, r2
+ bx lr
+ thumb
+}
+
+#else
+
template <typename T>
Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
{
@@ -334,6 +362,8 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
return originalValue;
}
+#endif // Q_CC_RVCT
+
template <typename T>
Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue)
{
diff --git a/src/corelib/arch/qatomic_symbian.h b/src/corelib/arch/qatomic_symbian.h
new file mode 100644
index 0000000..211c5f5
--- /dev/null
+++ b/src/corelib/arch/qatomic_symbian.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QATOMIC_SYMBIAN_H
+#define QATOMIC_SYMBIAN_H
+
+QT_BEGIN_HEADER
+
+#if defined(Q_CC_RVCT)
+# define QT_NO_ARM_EABI
+# include <QtCore/qatomic_arm.h>
+#elif defined(Q_CC_NOKIAX86) || defined(Q_CC_GCCE)
+# include <QtCore/qatomic_generic.h>
+#endif
+
+QT_END_HEADER
+
+#endif // QATOMIC_SYMBIAN_H
diff --git a/src/corelib/arch/qatomic_vxworks.h b/src/corelib/arch/qatomic_vxworks.h
new file mode 100644
index 0000000..964d1fa
--- /dev/null
+++ b/src/corelib/arch/qatomic_vxworks.h
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake spec 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QATOMIC_VXWORKS_H
+#define QATOMIC_VXWORKS_H
+
+QT_BEGIN_HEADER
+
+#if defined(__ppc)
+# include <QtCore/qatomic_powerpc.h>
+#else // generic implementation with taskLock()
+
+#if 0
+// we don't want to include the system header here for two function prototypes,
+// because it pulls in a _lot_ of stuff that pollutes the global namespace
+# include <vxWorksCommon.h>
+# include <taskLib.h>
+#else
+extern "C" int taskLock();
+extern "C" int taskUnlock();
+#endif
+
+
+
+QT_BEGIN_NAMESPACE
+
+#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE
+
+inline bool QBasicAtomicInt::isReferenceCountingNative()
+{ return false; }
+inline bool QBasicAtomicInt::isReferenceCountingWaitFree()
+{ return false; }
+
+#define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE
+
+inline bool QBasicAtomicInt::isTestAndSetNative()
+{ return false; }
+inline bool QBasicAtomicInt::isTestAndSetWaitFree()
+{ return false; }
+
+#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE
+
+inline bool QBasicAtomicInt::isFetchAndStoreNative()
+{ return false; }
+inline bool QBasicAtomicInt::isFetchAndStoreWaitFree()
+{ return false; }
+
+#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE
+
+inline bool QBasicAtomicInt::isFetchAndAddNative()
+{ return false; }
+inline bool QBasicAtomicInt::isFetchAndAddWaitFree()
+{ return false; }
+
+#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE
+
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetNative()
+{ return false; }
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetWaitFree()
+{ return false; }
+
+#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE
+
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreNative()
+{ return false; }
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreWaitFree()
+{ return false; }
+
+#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE
+
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddNative()
+{ return false; }
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree()
+{ return false; }
+
+// Reference counting
+
+inline bool QBasicAtomicInt::ref()
+{
+ taskLock();
+ bool ret = (++_q_value != 0);
+ taskUnlock();
+ return ret;
+}
+
+inline bool QBasicAtomicInt::deref()
+{
+ taskLock();
+ bool ret = (--_q_value != 0);
+ taskUnlock();
+ return ret;
+}
+
+// Test-and-set for integers
+
+inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue)
+{
+ taskLock();
+ if (_q_value == expectedValue) {
+ _q_value = newValue;
+ taskUnlock();
+ return true;
+ }
+ taskUnlock();
+ return false;
+}
+
+inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue)
+{
+ return testAndSetOrdered(expectedValue, newValue);
+}
+
+inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue)
+{
+ return testAndSetOrdered(expectedValue, newValue);
+}
+
+inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue)
+{
+ return testAndSetOrdered(expectedValue, newValue);
+}
+
+// Fetch-and-store for integers
+
+inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue)
+{
+ taskLock();
+ int returnValue = _q_value;
+ _q_value = newValue;
+ taskUnlock();
+ return returnValue;
+}
+
+inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue)
+{
+ return fetchAndStoreOrdered(newValue);
+}
+
+inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue)
+{
+ return fetchAndStoreOrdered(newValue);
+}
+
+inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue)
+{
+ return fetchAndStoreOrdered(newValue);
+}
+
+// Fetch-and-add for integers
+
+inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd)
+{
+ taskLock();
+ int originalValue = _q_value;
+ _q_value += valueToAdd;
+ taskUnlock();
+ return originalValue;
+}
+
+inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd)
+{
+ return fetchAndAddOrdered(valueToAdd);
+}
+
+inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd)
+{
+ return fetchAndAddOrdered(valueToAdd);
+}
+
+inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd)
+{
+ return fetchAndAddOrdered(valueToAdd);
+}
+
+// Test and set for pointers
+
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue)
+{
+ taskLock();
+ if (_q_value == expectedValue) {
+ _q_value = newValue;
+ taskUnlock();
+ return true;
+ }
+ taskUnlock();
+ return false;
+}
+
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValue, T *newValue)
+{
+ return testAndSetOrdered(expectedValue, newValue);
+}
+
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValue, T *newValue)
+{
+ return testAndSetOrdered(expectedValue, newValue);
+}
+
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValue, T *newValue)
+{
+ return testAndSetOrdered(expectedValue, newValue);
+}
+
+// Fetch and store for pointers
+
+template <typename T>
+Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
+{
+ taskLock();
+ T *returnValue = (_q_value);
+ _q_value = newValue;
+ taskUnlock();
+ return returnValue;
+}
+
+template <typename T>
+Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue)
+{
+ return fetchAndStoreOrdered(newValue);
+}
+
+template <typename T>
+Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreAcquire(T *newValue)
+{
+ return fetchAndStoreOrdered(newValue);
+}
+
+template <typename T>
+Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelease(T *newValue)
+{
+ return fetchAndStoreOrdered(newValue);
+}
+
+// Fetch and add for pointers
+
+template <typename T>
+Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueToAdd)
+{
+ taskLock();
+ T *returnValue = (_q_value);
+ _q_value += valueToAdd;
+ taskUnlock();
+ return returnValue;
+}
+
+template <typename T>
+Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelaxed(qptrdiff valueToAdd)
+{
+ return fetchAndAddOrdered(valueToAdd);
+}
+
+template <typename T>
+Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddAcquire(qptrdiff valueToAdd)
+{
+ return fetchAndAddOrdered(valueToAdd);
+}
+
+template <typename T>
+Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelease(qptrdiff valueToAdd)
+{
+ return fetchAndAddOrdered(valueToAdd);
+}
+
+QT_END_NAMESPACE
+
+#endif // generic implementation with taskLock()
+
+QT_END_HEADER
+
+#endif // QATOMIC_VXWORKS_H
diff --git a/src/corelib/arch/qatomic_windows.h b/src/corelib/arch/qatomic_windows.h
index c56530c..a826bd3 100644
--- a/src/corelib/arch/qatomic_windows.h
+++ b/src/corelib/arch/qatomic_windows.h
@@ -107,7 +107,7 @@ template <typename T>
Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree()
{ return true; }
-#if defined(Q_CC_MSVC)
+#if defined(Q_CC_MSVC) || defined(Q_CC_MWERKS)
// MSVC++ 6.0 doesn't generate correct code when optimizations are turned on!
#if _MSC_VER < 1300 && defined (_M_IX86)
@@ -218,7 +218,7 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueTo
#else
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_CC_MWERKS)
// use compiler intrinsics for all atomic functions
//those functions need to be define in the global namespace
QT_END_NAMESPACE
@@ -319,7 +319,7 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueTo
#else // Q_OS_WINCE
-#if _WIN32_WCE < 0x600 && defined(_X86_)
+#if (_WIN32_WCE < 0x600 && defined(_X86_)) || defined(Q_CC_MWERKS)
// For X86 Windows CE build we need to include winbase.h to be able
// to catch the inline functions which overwrite the regular
// definitions inside of coredll.dll. Though one could use the
@@ -327,8 +327,7 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueTo
// exported at all.
#include <winbase.h>
#else
-
-#if _WIN32_WCE >= 0x600
+#if _WIN32_WCE >= 0x600 || defined(Q_CC_MWERKS)
#define Q_ARGUMENT_TYPE volatile
# if defined(_X86_)
# define InterlockedIncrement _InterlockedIncrement
diff --git a/src/corelib/arch/symbian/arch.pri b/src/corelib/arch/symbian/arch.pri
new file mode 100644
index 0000000..deb94b1
--- /dev/null
+++ b/src/corelib/arch/symbian/arch.pri
@@ -0,0 +1,5 @@
+#
+# Symbian architecture
+#
+SOURCES += $$QT_ARCH_CPP/qatomic_symbian.cpp \
+ $$QT_ARCH_CPP/../generic/qatomic_generic_unix.cpp
diff --git a/src/corelib/arch/symbian/qatomic_symbian.cpp b/src/corelib/arch/symbian/qatomic_symbian.cpp
new file mode 100644
index 0000000..57d0754
--- /dev/null
+++ b/src/corelib/arch/symbian/qatomic_symbian.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qatomic.h>
+
+#include <e32debug.h>
+
+QT_BEGIN_NAMESPACE
+
+// Heap and handle info printer.
+// This way we can report on heap cells and handles that are really not owned by anything which still exists.
+// This information can be used to detect whether memory leaks are happening, particularly if these numbers grow as the app is used more.
+// This code is placed here as it happens to make it the very last static to be destroyed in a Qt app. The
+// reason assumed is that this file appears before any other file declaring static data in the generated
+// Symbian MMP file. This particular file was chosen as it is the earliest symbian specific file.
+struct QSymbianPrintExitInfo
+{
+ QSymbianPrintExitInfo()
+ {
+ RThread().HandleCount(initProcessHandleCount, initThreadHandleCount);
+ initCells = User::CountAllocCells();
+ }
+ ~QSymbianPrintExitInfo()
+ {
+ RProcess myProc;
+ TFullName fullName = myProc.FileName();
+ TInt cells = User::CountAllocCells();
+ TInt processHandleCount=0;
+ TInt threadHandleCount=0;
+ RThread().HandleCount(processHandleCount, threadHandleCount);
+ RDebug::Print(_L("%S exiting with %d allocated cells, %d handles"),
+ &fullName,
+ cells - initCells,
+ (processHandleCount + threadHandleCount) - (initProcessHandleCount + initThreadHandleCount));
+ }
+ TInt initCells;
+ TInt initProcessHandleCount;
+ TInt initThreadHandleCount;
+} symbian_printExitInfo;
+
+QT_END_NAMESPACE
+
+
+#if defined(Q_CC_RVCT)
+
+#include "../arm/qatomic_arm.cpp"
+
+QT_BEGIN_NAMESPACE
+
+// This declspec needs to be explicit. RVCT has a bug which prevents embedded
+// assembler functions from being exported (normally all functions are
+// exported, and Q_CORE_EXPORT resolves to nothing).
+__declspec(dllexport) __asm char q_atomic_swp(volatile char *ptr, char newval)
+{
+ add r2, pc, #0
+ bx r2
+ arm
+ swpb r2,r1,[r0]
+ mov r0, r2
+ bx lr
+ thumb
+}
+
+__declspec(dllexport) __asm int QBasicAtomicInt::fetchAndStoreOrdered(int newValue)
+{
+ add r2, pc, #0
+ bx r2
+ arm
+ swp r2,r1,[r0]
+ mov r0, r2
+ bx lr
+ thumb
+}
+
+QT_END_NAMESPACE
+
+#endif // Q_CC_RVCT
diff --git a/src/corelib/arch/vxworks/arch.pri b/src/corelib/arch/vxworks/arch.pri
new file mode 100644
index 0000000..a768618
--- /dev/null
+++ b/src/corelib/arch/vxworks/arch.pri
@@ -0,0 +1,6 @@
+#
+# VxWorks generic
+#
+*-ppc-* {
+ SOURCES += qatomic_ppc.s
+}
diff --git a/src/corelib/arch/vxworks/qatomic_ppc.s b/src/corelib/arch/vxworks/qatomic_ppc.s
new file mode 100644
index 0000000..03971e8
--- /dev/null
+++ b/src/corelib/arch/vxworks/qatomic_ppc.s
@@ -0,0 +1,415 @@
+
+ .align 2
+ .globl q_atomic_test_and_set_int
+ .globl .q_atomic_test_and_set_int
+q_atomic_test_and_set_int:
+.q_atomic_test_and_set_int:
+ lwarx 6,0,3
+ xor. 6,6,4
+ bne $+12
+ stwcx. 5,0,3
+ bne- $-16
+ subfic 3,6,0
+ adde 3,3,6
+ blr
+LT..q_atomic_test_and_set_int:
+ .long 0
+ .byte 0,9,32,64,0,0,3,0
+ .long 0
+ .long LT..q_atomic_test_and_set_int-.q_atomic_test_and_set_int
+ .short 25
+ .byte "q_atomic_test_and_set_int"
+ .align 2
+
+ .align 2
+ .globl q_atomic_test_and_set_acquire_int
+ .globl .q_atomic_test_and_set_acquire_int
+q_atomic_test_and_set_acquire_int:
+.q_atomic_test_and_set_acquire_int:
+ lwarx 6,0,3
+ xor. 6,6,4
+ bne $+16
+ stwcx. 5,0,3
+ bne- $-16
+ isync
+ subfic 3,6,0
+ adde 3,3,6
+ blr
+LT..q_atomic_test_and_set_acquire_int:
+ .long 0
+ .byte 0,9,32,64,0,0,3,0
+ .long 0
+ .long LT..q_atomic_test_and_set_acquire_int-.q_atomic_test_and_set_acquire_int
+ .short 33
+ .byte "q_atomic_test_and_set_acquire_int"
+ .align 2
+
+ .align 2
+ .globl q_atomic_test_and_set_release_int
+ .globl .q_atomic_test_and_set_release_int
+q_atomic_test_and_set_release_int:
+.q_atomic_test_and_set_release_int:
+ lwarx 6,0,3
+ xor. 6,6,4
+ bne $+12
+ stwcx. 5,0,3
+ bne- $-16
+ subfic 3,6,0
+ adde 3,3,6
+ blr
+LT..q_atomic_test_and_set_release_int:
+ .long 0
+ .byte 0,9,32,64,0,0,3,0
+ .long 0
+ .long LT..q_atomic_test_and_set_release_int-.q_atomic_test_and_set_release_int
+ .short 33
+ .byte "q_atomic_test_and_set_release_int"
+ .align 2
+
+ .align 2
+ .globl q_atomic_test_and_set_ptr
+ .globl .q_atomic_test_and_set_ptr
+q_atomic_test_and_set_ptr:
+.q_atomic_test_and_set_ptr:
+ lwarx 6,0,3
+ xor. 6,6,4
+ bne $+12
+ stwcx. 5,0,3
+ bne- $-16
+ subfic 3,6,0
+ adde 3,3,6
+ blr
+LT..q_atomic_test_and_set_ptr:
+ .long 0
+ .byte 0,9,32,64,0,0,3,0
+ .long 0
+ .long LT..q_atomic_test_and_set_ptr-.q_atomic_test_and_set_ptr
+ .short 25
+ .byte "q_atomic_test_and_set_ptr"
+ .align 2
+
+ .align 2
+ .globl q_atomic_test_and_set_acquire_ptr
+ .globl .q_atomic_test_and_set_acquire_ptr
+q_atomic_test_and_set_acquire_ptr:
+.q_atomic_test_and_set_acquire_ptr:
+ lwarx 6,0,3
+ xor. 6,6,4
+ bne $+16
+ stwcx. 5,0,3
+ bne- $-16
+ isync
+ subfic 3,6,0
+ adde 3,3,6
+ blr
+LT..q_atomic_test_and_set_acquire_ptr:
+ .long 0
+ .byte 0,9,32,64,0,0,3,0
+ .long 0
+ .long LT..q_atomic_test_and_set_acquire_ptr-.q_atomic_test_and_set_acquire_ptr
+ .short 25
+ .byte "q_atomic_test_and_set_acquire_ptr"
+ .align 2
+
+ .align 2
+ .globl q_atomic_test_and_set_release_ptr
+ .globl .q_atomic_test_and_set_release_ptr
+q_atomic_test_and_set_release_ptr:
+.q_atomic_test_and_set_release_ptr:
+ lwarx 6,0,3
+ xor. 6,6,4
+ bne $+12
+ stwcx. 5,0,3
+ bne- $-16
+ subfic 3,6,0
+ adde 3,3,6
+ blr
+LT..q_atomic_test_and_set_release_ptr:
+ .long 0
+ .byte 0,9,32,64,0,0,3,0
+ .long 0
+ .long LT..q_atomic_test_and_set_release_ptr-.q_atomic_test_and_set_release_ptr
+ .short 33
+ .byte "q_atomic_test_and_set_release_ptr"
+ .align 2
+
+ .align 2
+ .globl q_atomic_increment
+ .globl .q_atomic_increment
+q_atomic_increment:
+.q_atomic_increment:
+ lwarx 4,0,3
+ addi 4,4,1
+ stwcx. 4,0,3
+ bne- $-12
+ mr 3,4
+ blr
+LT..q_atomic_increment:
+ .long 0
+ .byte 0,9,32,64,0,0,1,0
+ .long 0
+ .long LT..q_atomic_increment-.q_atomic_increment
+ .short 18
+ .byte "q_atomic_increment"
+ .align 2
+
+ .align 2
+ .globl q_atomic_decrement
+ .globl .q_atomic_decrement
+q_atomic_decrement:
+.q_atomic_decrement:
+ lwarx 4,0,3
+ subi 4,4,1
+ stwcx. 4,0,3
+ bne- $-12
+ mr 3,4
+ blr
+LT..q_atomic_decrement:
+ .long 0
+ .byte 0,9,32,64,0,0,1,0
+ .long 0
+ .long LT..q_atomic_decrement-.q_atomic_decrement
+ .short 18
+ .byte "q_atomic_decrement"
+ .align 2
+
+ .align 2
+ .globl q_atomic_set_int
+ .globl .q_atomic_set_int
+q_atomic_set_int:
+.q_atomic_set_int:
+ lwarx 5,0,3
+ stwcx. 4,0,3
+ bne- $-8
+ mr 3,5
+ blr
+LT..q_atomic_set_int:
+ .long 0
+ .byte 0,9,32,64,0,0,2,0
+ .long 0
+ .long LT..q_atomic_set_int-.q_atomic_set_int
+ .short 16
+ .byte "q_atomic_set_int"
+ .align 2
+
+ .align 2
+ .globl q_atomic_fetch_and_store_acquire_int
+ .globl .q_atomic_fetch_and_store_acquire_int
+q_atomic_fetch_and_store_acquire_int:
+.q_atomic_fetch_and_store_acquire_int:
+ lwarx 5,0,3
+ stwcx. 4,0,3
+ bne- $-8
+ isync
+ mr 3,5
+ blr
+LT..q_atomic_fetch_and_store_acquire_int:
+ .long 0
+ .byte 0,9,32,64,0,0,2,0
+ .long 0
+ .long LT..q_atomic_fetch_and_store_acquire_int-.q_atomic_fetch_and_store_acquire_int
+ .short 16
+ .byte "q_atomic_fetch_and_store_acquire_int"
+ .align 2
+
+ .align 2
+ .globl q_atomic_fetch_and_store_release_int
+ .globl .q_atomic_fetch_and_store_release_int
+q_atomic_fetch_and_store_release_int:
+.q_atomic_fetch_and_store_release_int:
+ lwarx 5,0,3
+ stwcx. 4,0,3
+ bne- $-8
+ mr 3,5
+ blr
+LT..q_atomic_fetch_and_store_release_int:
+ .long 0
+ .byte 0,9,32,64,0,0,2,0
+ .long 0
+ .long LT..q_atomic_fetch_and_store_release_int-.q_atomic_fetch_and_store_release_int
+ .short 16
+ .byte "q_atomic_fetch_and_store_release_int"
+ .align 2
+
+ .align 2
+ .globl q_atomic_set_ptr
+ .globl .q_atomic_set_ptr
+q_atomic_set_ptr:
+.q_atomic_set_ptr:
+ lwarx 5,0,3
+ stwcx. 4,0,3
+ bne- $-8
+ mr 3,5
+ blr
+LT..q_atomic_set_ptr:
+ .long 0
+ .byte 0,9,32,64,0,0,2,0
+ .long 0
+ .long LT..q_atomic_set_ptr-.q_atomic_set_ptr
+ .short 16
+ .byte "q_atomic_set_ptr"
+ .align 2
+
+ .align 2
+ .globl q_atomic_fetch_and_store_acquire_ptr
+ .globl .q_atomic_fetch_and_store_acquire_ptr
+q_atomic_fetch_and_store_acquire_ptr:
+.q_atomic_fetch_and_store_acquire_ptr:
+ lwarx 5,0,3
+ stwcx. 4,0,3
+ bne- $-8
+ isync
+ mr 3,5
+ blr
+LT..q_atomic_fetch_and_store_acquire_ptr:
+ .long 0
+ .byte 0,9,32,64,0,0,2,0
+ .long 0
+ .long LT..q_atomic_fetch_and_store_acquire_ptr-.q_atomic_fetch_and_store_acquire_ptr
+ .short 16
+ .byte "q_atomic_fetch_and_store_acquire_ptr"
+ .align 2
+
+ .align 2
+ .globl q_atomic_fetch_and_store_release_ptr
+ .globl .q_atomic_fetch_and_store_release_ptr
+q_atomic_fetch_and_store_release_ptr:
+.q_atomic_fetch_and_store_release_ptr:
+ lwarx 5,0,3
+ stwcx. 4,0,3
+ bne- $-8
+ mr 3,5
+ blr
+LT..q_atomic_fetch_and_store_release_ptr:
+ .long 0
+ .byte 0,9,32,64,0,0,2,0
+ .long 0
+ .long LT..q_atomic_fetch_and_store_release_ptr-.q_atomic_fetch_and_store_release_ptr
+ .short 16
+ .byte "q_atomic_fetch_and_store_release_ptr"
+ .align 2
+
+ .align 2
+ .globl q_atomic_fetch_and_add_int
+ .globl .q_atomic_fetch_and_add_int
+q_atomic_fetch_and_add_int:
+.q_atomic_fetch_and_add_int:
+ lwarx 5,0,3
+ add 6,4,5
+ stwcx. 6,0,3
+ bne- $-12
+ mr 3,5
+ blr
+LT..q_atomic_fetch_and_add_int:
+ .long 0
+ .byte 0,9,32,64,0,0,1,0
+ .long 0
+ .long LT..q_atomic_fetch_and_add_int-.q_atomic_fetch_and_add_int
+ .short 18
+ .byte "q_atomic_fetch_and_add_int"
+ .align 2
+
+ .align 2
+ .globl q_atomic_fetch_and_add_acquire_int
+ .globl .q_atomic_fetch_and_add_acquire_int
+q_atomic_fetch_and_add_acquire_int:
+.q_atomic_fetch_and_add_acquire_int:
+ lwarx 5,0,3
+ add 6,4,5
+ stwcx. 6,0,3
+ bne- $-12
+ isync
+ mr 3,5
+ blr
+LT..q_atomic_fetch_and_add_acquire_int:
+ .long 0
+ .byte 0,9,32,64,0,0,1,0
+ .long 0
+ .long LT..q_atomic_fetch_and_add_acquire_int-.q_atomic_fetch_and_add_acquire_int
+ .short 18
+ .byte "q_atomic_fetch_and_add_acquire_int"
+ .align 2
+
+ .align 2
+ .globl q_atomic_fetch_and_add_release_int
+ .globl .q_atomic_fetch_and_add_release_int
+q_atomic_fetch_and_add_release_int:
+.q_atomic_fetch_and_add_release_int:
+ lwarx 5,0,3
+ add 6,4,5
+ stwcx. 6,0,3
+ bne- $-12
+ mr 3,5
+ blr
+LT..q_atomic_fetch_and_add_release_int:
+ .long 0
+ .byte 0,9,32,64,0,0,1,0
+ .long 0
+ .long LT..q_atomic_fetch_and_add_release_int-.q_atomic_fetch_and_add_release_int
+ .short 34
+ .byte "q_atomic_fetch_and_add_release_int"
+ .align 2
+
+ .align 2
+ .globl q_atomic_fetch_and_add_ptr
+ .globl .q_atomic_fetch_and_add_ptr
+q_atomic_fetch_and_add_ptr:
+.q_atomic_fetch_and_add_ptr:
+ lwarx 5,0,3
+ add 6,4,5
+ stwcx. 6,0,3
+ bne- $-12
+ mr 3,5
+ blr
+LT..q_atomic_fetch_and_add_ptr:
+ .long 0
+ .byte 0,9,32,64,0,0,1,0
+ .long 0
+ .long LT..q_atomic_fetch_and_add_ptr-.q_atomic_fetch_and_add_ptr
+ .short 26
+ .byte "q_atomic_fetch_and_add_ptr"
+ .align 2
+
+ .align 2
+ .globl q_atomic_fetch_and_add_acquire_ptr
+ .globl .q_atomic_fetch_and_add_acquire_ptr
+q_atomic_fetch_and_add_acquire_ptr:
+.q_atomic_fetch_and_add_acquire_ptr:
+ lwarx 5,0,3
+ add 6,4,5
+ stwcx. 6,0,3
+ bne- $-12
+ isync
+ mr 3,5
+ blr
+LT..q_atomic_fetch_and_add_acquire_ptr:
+ .long 0
+ .byte 0,9,32,64,0,0,1,0
+ .long 0
+ .long LT..q_atomic_fetch_and_add_acquire_ptr-.q_atomic_fetch_and_add_acquire_ptr
+ .short 34
+ .byte "q_atomic_fetch_and_add_acquire_ptr"
+ .align 2
+
+ .align 2
+ .globl q_atomic_fetch_and_add_release_ptr
+ .globl .q_atomic_fetch_and_add_release_ptr
+q_atomic_fetch_and_add_release_ptr:
+.q_atomic_fetch_and_add_release_ptr:
+ lwarx 5,0,3
+ add 6,4,5
+ stwcx. 6,0,3
+ bne- $-12
+ mr 3,5
+ blr
+LT..q_atomic_fetch_and_add_release_ptr:
+ .long 0
+ .byte 0,9,32,64,0,0,1,0
+ .long 0
+ .long LT..q_atomic_fetch_and_add_release_ptr-.q_atomic_fetch_and_add_release_ptr
+ .short 34
+ .byte "q_atomic_fetch_and_add_release_ptr"
+ .align 2
+
+_section_.text:
+ .long _section_.text
diff --git a/src/corelib/codecs/codecs.pri b/src/corelib/codecs/codecs.pri
index 2e247e5..724b18d 100644
--- a/src/corelib/codecs/codecs.pri
+++ b/src/corelib/codecs/codecs.pri
@@ -29,7 +29,7 @@ unix {
SOURCES += codecs/qiconvcodec.cpp
DEFINES += GNU_LIBICONV
- !mac:LIBS *= -liconv
+ !mac:LIBS_PRIVATE *= -liconv
} else {
# no iconv, so we put all plugins in the library
HEADERS += \
diff --git a/src/corelib/codecs/codecs.qdoc b/src/corelib/codecs/codecs.qdoc
new file mode 100644
index 0000000..efe7912
--- /dev/null
+++ b/src/corelib/codecs/codecs.qdoc
@@ -0,0 +1,546 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \group codecs
+ \title Codecs
+ \ingroup groups
+ \brief Codec support in Qt.
+
+ These codecs provide facilities for conversion between Unicode and
+ specific text encodings.
+
+ \generatelist{related}
+*/
+
+/*!
+ \page codec-big5.html
+ \title Big5 Text Codec
+ \ingroup codecs
+
+ The Big5 codec provides conversion to and from the Big5 encoding.
+ The code was originally contributed by Ming-Che Chuang
+ \<mingche@cobra.ee.ntu.edu.tw\> for the Big-5+ encoding, and was
+ included in Qt with the author's permission, and the grateful
+ thanks of the Qt team. (Note: Ming-Che's code is QPL'd, as
+ per an mail to qt-info@nokia.com.)
+
+ However, since Big-5+ was never formally approved, and was never
+ used by anyone, the Taiwan Free Software community and the Li18nux
+ Big5 Standard Subgroup agree that the de-facto standard Big5-ETen
+ (zh_TW.Big5 or zh_TW.TW-Big5) be used instead.
+
+ The Big5 is currently implemented as a pure subset of the
+ Big5-HKSCS codec, so more fine-tuning is needed to make it
+ identical to the standard Big5 mapping as determined by
+ Li18nux-Big5. See \l{http://www.autrijus.org/xml/} for the draft
+ Big5 (2002) standard.
+
+ James Su \<suzhe@turbolinux.com.cn\> \<suzhe@gnuchina.org\>
+ generated the Big5-HKSCS-to-Unicode tables with a very
+ space-efficient algorithm. He generously donated his code to glibc
+ in May 2002. Subsequently, James has kindly allowed Anthony Fok
+ \<anthony@thizlinux.com\> \<foka@debian.org\> to adapt the code
+ for Qt.
+
+ \legalese
+ Copyright (C) 2000 Ming-Che Chuang \BR
+ Copyright (C) 2002 James Su, Turbolinux Inc. \BR
+ Copyright (C) 2002 Anthony Fok, ThizLinux Laboratory Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ \list 1
+ \o Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ \o Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ \endlist
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ \endlegalese
+*/
+
+/*!
+ \page codec-big5hkscs.html
+ \title Big5-HKSCS Text Codec
+ \ingroup codecs
+
+ The Big5-HKSCS codec provides conversion to and from the
+ Big5-HKSCS encoding.
+
+ The codec grew out of the QBig5Codec originally contributed by
+ Ming-Che Chuang \<mingche@cobra.ee.ntu.edu.tw\>. James Su
+ \<suzhe@turbolinux.com.cn\> \<suzhe@gnuchina.org\> and Anthony Fok
+ \<anthony@thizlinux.com\> \<foka@debian.org\> implemented HKSCS-1999
+ QBig5hkscsCodec for Qt-2.3.x, but it was too late in Qt development
+ schedule to be officially included in the Qt-2.3.x series.
+
+ Wu Yi \<wuyi@hancom.com\> ported the HKSCS-1999 QBig5hkscsCodec to
+ Qt-3.0.1 in March 2002.
+
+ With the advent of the new HKSCS-2001 standard, James Su
+ \<suzhe@turbolinux.com.cn\> \<suzhe@gnuchina.org\> generated the
+ Big5-HKSCS<->Unicode tables with a very space-efficient algorithm.
+ He generously donated his code to glibc in May 2002. Subsequently,
+ James has generously allowed Anthony Fok to adapt the code for
+ Qt-3.0.5.
+
+ Currently, the Big5-HKSCS tables are generated from the following
+ sources, and with the Euro character added:
+ \list 1
+ \o \l{http://www.microsoft.com/typography/unicode/950.txt}
+ \o \l{http://www.info.gov.hk/digital21/chi/hkscs/download/big5-iso.txt}
+ \o \l{http://www.info.gov.hk/digital21/chi/hkscs/download/big5cmp.txt}
+ \endlist
+
+ There may be more fine-tuning to the QBig5hkscsCodec to maximize its
+ compatibility with the standard Big5 (2002) mapping as determined by
+ Li18nux Big5 Standard Subgroup. See \l{http://www.autrijus.org/xml/}
+ for the various Big5 CharMapML tables.
+
+ \legalese
+ Copyright (C) 2000 Ming-Che Chuang \BR
+ Copyright (C) 2001, 2002 James Su, Turbolinux Inc. \BR
+ Copyright (C) 2002 WU Yi, HancomLinux Inc. \BR
+ Copyright (C) 2001, 2002 Anthony Fok, ThizLinux Laboratory Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ \list 1
+ \o Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ \o Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ \endlist
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ \endlegalese
+*/
+
+/*!
+ \page codec-eucjp.html
+ \title EUC-JP Text Codec
+ \ingroup codecs
+
+ The EUC-JP codec provides conversion to and from EUC-JP, the main
+ legacy encoding for Unix machines in Japan.
+
+ The environment variable \c UNICODEMAP_JP can be used to
+ fine-tune the JIS, Shift-JIS, and EUC-JP codecs. The \l{ISO
+ 2022-JP (JIS) Text Codec} documentation describes how to use this
+ variable.
+
+ Most of the code here was written by Serika Kurusugawa,
+ a.k.a. Junji Takagi, and is included in Qt with the author's
+ permission and the grateful thanks of the Qt team. Here is
+ the copyright statement for that code:
+
+ \legalese
+
+ Copyright (C) 1999 Serika Kurusugawa. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ \list 1
+ \o Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ \o Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ \endlist
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS".
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ \endlegalese
+*/
+
+/*!
+ \page codec-euckr.html
+ \title EUC-KR Text Codec
+ \ingroup codecs
+
+ The EUC-KR codec provides conversion to and from EUC-KR, KR, the
+ main legacy encoding for Unix machines in Korea.
+
+ It was largely written by Mizi Research Inc. Here is the
+ copyright statement for the code as it was at the point of
+ contribution. The subsequent modifications are covered by
+ the usual copyright for Qt.
+
+ \legalese
+
+ Copyright (C) 1999-2000 Mizi Research Inc. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ \list 1
+ \o Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ \o Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ \endlist
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ \endlegalese
+*/
+
+/*!
+ \page codec-gbk.html
+ \title GBK Text Codec
+ \ingroup codecs
+
+ The GBK codec provides conversion to and from the Chinese
+ GB18030/GBK/GB2312 encoding.
+
+ GBK, formally the Chinese Internal Code Specification, is a commonly
+ used extension of GB 2312-80. Microsoft Windows uses it under the
+ name codepage 936.
+
+ GBK has been superseded by the new Chinese national standard
+ GB 18030-2000, which added a 4-byte encoding while remaining
+ compatible with GB2312 and GBK. The new GB 18030-2000 may be described
+ as a special encoding of Unicode 3.x and ISO-10646-1.
+
+ Special thanks to charset gurus Markus Scherer (IBM),
+ Dirk Meyer (Adobe Systems) and Ken Lunde (Adobe Systems) for publishing
+ an excellent GB 18030-2000 summary and specification on the Internet.
+ Some must-read documents are:
+
+ \list
+ \o \l{ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/pdf/GB18030_Summary.pdf}
+ \o \l{http://oss.software.ibm.com/cvs/icu/~checkout~/charset/source/gb18030/gb18030.html}
+ \o \l{http://oss.software.ibm.com/cvs/icu/~checkout~/charset/data/xml/gb-18030-2000.xml}
+ \endlist
+
+ The GBK codec was contributed to Qt by
+ Justin Yu \<justiny@turbolinux.com.cn\> and
+ Sean Chen \<seanc@turbolinux.com.cn\>. They may also be reached at
+ Yu Mingjian \<yumj@sun.ihep.ac.cn\>, \<yumingjian@china.com\>
+ Chen Xiangyang \<chenxy@sun.ihep.ac.cn\>
+
+ The GB18030 codec Qt functions were contributed to Qt by
+ James Su \<suzhe@gnuchina.org\>, \<suzhe@turbolinux.com.cn\>
+ who pioneered much of GB18030 development on GNU/Linux systems.
+
+ The GB18030 codec was contributed to Qt by
+ Anthony Fok \<anthony@thizlinux.com\>, \<foka@debian.org\>
+ using a Perl script to generate C++ tables from gb-18030-2000.xml
+ while merging contributions from James Su, Justin Yu and Sean Chen.
+ A copy of the source Perl script is available at
+ \l{http://people.debian.org/~foka/gb18030/gen-qgb18030codec.pl}
+
+ The copyright notice for their code follows:
+
+ \legalese
+ Copyright (C) 2000 TurboLinux, Inc. Written by Justin Yu and Sean Chen. \BR
+ Copyright (C) 2001, 2002 Turbolinux, Inc. Written by James Su. \BR
+ Copyright (C) 2001, 2002 ThizLinux Laboratory Ltd. Written by Anthony Fok.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ \list 1
+ \o Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ \o Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ \endlist
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ \endlegalese
+*/
+
+/*!
+ \page codecs-jis.html
+ \title ISO 2022-JP (JIS) Text Codec
+ \ingroup codecs
+
+ The JIS codec provides conversion to and from ISO 2022-JP.
+
+ The environment variable \c UNICODEMAP_JP can be used to
+ fine-tune the JIS, Shift-JIS, and EUC-JP codecs. The mapping
+ names are as for the Japanese XML working group's \link
+ http://www.y-adagio.com/public/standards/tr_xml_jpf/toc.htm XML
+ Japanese Profile\endlink, because it names and explains all the
+ widely used mappings. Here are brief descriptions, written by
+ Serika Kurusugawa:
+
+ \list
+
+ \o "unicode-0.9" or "unicode-0201" for Unicode style. This assumes
+ JISX0201 for 0x00-0x7f. (0.9 is a table version of jisx02xx mapping
+ used for Unicode 1.1.)
+
+ \o "unicode-ascii" This assumes US-ASCII for 0x00-0x7f; some
+ chars (JISX0208 0x2140 and JISX0212 0x2237) are different from
+ Unicode 1.1 to avoid conflict.
+
+ \o "open-19970715-0201" ("open-0201" for convenience) or
+ "jisx0221-1995" for JISX0221-JISX0201 style. JIS X 0221 is JIS
+ version of Unicode, but a few chars (0x5c, 0x7e, 0x2140, 0x216f,
+ 0x2131) are different from Unicode 1.1. This is used when 0x5c is
+ treated as YEN SIGN.
+
+ \o "open-19970715-ascii" ("open-ascii" for convenience) for
+ JISX0221-ASCII style. This is used when 0x5c is treated as REVERSE
+ SOLIDUS.
+
+ \o "open-19970715-ms" ("open-ms" for convenience) or "cp932" for
+ Microsoft Windows style. Windows Code Page 932. Some chars (0x2140,
+ 0x2141, 0x2142, 0x215d, 0x2171, 0x2172) are different from Unicode
+ 1.1.
+
+ \o "jdk1.1.7" for Sun's JDK style. Same as Unicode 1.1, except that
+ JIS 0x2140 is mapped to UFF3C. Either ASCII or JISX0201 can be used
+ for 0x00-0x7f.
+
+ \endlist
+
+ In addition, the extensions "nec-vdc", "ibm-vdc" and "udc" are
+ supported.
+
+ For example, if you want to use Unicode style conversion but with
+ NEC's extension, set \c UNICODEMAP_JP to \c {unicode-0.9,
+ nec-vdc}. (You will probably need to quote that in a shell
+ command.)
+
+ Most of the code here was written by Serika Kurusugawa,
+ a.k.a. Junji Takagi, and is included in Qt with the author's
+ permission and the grateful thanks of the Qt team. Here is
+ the copyright statement for that code:
+
+ \legalese
+
+ Copyright (C) 1999 Serika Kurusugawa. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ \list 1
+ \o Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ \o Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ \endlist
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS".
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ \endlegalese
+*/
+
+/*!
+ \page codec-sjis.html
+ \title Shift-JIS Text Codec
+ \ingroup codecs
+
+ The Shift-JIS codec provides conversion to and from Shift-JIS, an
+ encoding of JIS X 0201 Latin, JIS X 0201 Kana and JIS X 0208.
+
+ The environment variable \c UNICODEMAP_JP can be used to
+ fine-tune the codec. The \l{ISO 2022-JP (JIS) Text Codec}
+ documentation describes how to use this variable.
+
+ Most of the code here was written by Serika Kurusugawa, a.k.a.
+ Junji Takagi, and is included in Qt with the author's permission
+ and the grateful thanks of the Qt team. Here is the
+ copyright statement for the code as it was at the point of
+ contribution. The subsequent modifications are covered by
+ the usual copyright for Qt.
+
+ \legalese
+
+ Copyright (C) 1999 Serika Kurusugawa. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ \list 1
+ \o Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ \o Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ \endlist
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS".
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ \endlegalese
+*/
+
+/*!
+ \page codec-tscii.html
+ \title TSCII Text Codec
+ \ingroup codecs
+
+ The TSCII codec provides conversion to and from the Tamil TSCII
+ encoding.
+
+ TSCII, formally the Tamil Standard Code Information Interchange
+ specification, is a commonly used charset for Tamils. The
+ official page for the standard is at
+ \link http://www.tamil.net/tscii/ http://www.tamil.net/tscii/\endlink
+
+ This codec uses the mapping table found at
+ \link http://www.geocities.com/Athens/5180/tsciiset.html
+ http://www.geocities.com/Athens/5180/tsciiset.html\endlink.
+ Tamil uses composed Unicode which might cause some
+ problems if you are using Unicode fonts instead of TSCII fonts.
+
+ Most of the code was written by Hans Petter Bieker and is
+ included in Qt with the author's permission and the grateful
+ thanks of the Qt team. Here is the copyright statement for
+ the code as it was at the point of contribution. The
+ subsequent modifications are covered by the usual copyright for
+ Qt:
+
+ \legalese
+
+ Copyright (c) 2000 Hans Petter Bieker. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ \list 1
+ \o Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ \o Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ \endlist
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ \endlegalese
+*/
diff --git a/src/corelib/codecs/qfontlaocodec.cpp b/src/corelib/codecs/qfontlaocodec.cpp
index 4acba18..38c3e36 100644
--- a/src/corelib/codecs/qfontlaocodec.cpp
+++ b/src/corelib/codecs/qfontlaocodec.cpp
@@ -97,8 +97,7 @@ QString QFontLaoCodec::convertToUnicode(const char *, int, ConverterState *) con
QByteArray QFontLaoCodec::convertFromUnicode(const QChar *uc, int len, ConverterState *) const
{
- QByteArray rstring;
- rstring.resize(len);
+ QByteArray rstring(len, Qt::Uninitialized);
uchar *rdata = (uchar *) rstring.data();
const QChar *sdata = uc;
int i = 0;
diff --git a/src/corelib/codecs/qiconvcodec.cpp b/src/corelib/codecs/qiconvcodec.cpp
index 395fc1f..9c8ae9a 100644
--- a/src/corelib/codecs/qiconvcodec.cpp
+++ b/src/corelib/codecs/qiconvcodec.cpp
@@ -52,7 +52,7 @@
// unistd.h is needed for the _XOPEN_UNIX macro
#include <unistd.h>
-#if defined(_XOPEN_UNIX) && !defined(Q_OS_QNX6) && !defined(Q_OS_OSF)
+#if defined(_XOPEN_UNIX) && !defined(Q_OS_QNX) && !defined(Q_OS_OSF)
# include <langinfo.h>
#endif
@@ -238,9 +238,8 @@ QString QIconvCodec::convertToUnicode(const char* chars, int len, ConverterState
remainingCount = 0;
}
- QByteArray ba;
size_t outBytesLeft = len * 2 + 2;
- ba.resize(outBytesLeft);
+ QByteArray ba(outBytesLeft, Qt::Uninitialized);
char *outBytes = ba.data();
do {
size_t ret = iconv(state->cd, &inBytes, &inBytesLeft, &outBytes, &outBytesLeft);
@@ -328,8 +327,7 @@ QByteArray QIconvCodec::convertFromUnicode(const QChar *uc, int len, ConverterSt
state = new IconvState(QIconvCodec::createIconv_t(0, UTF16));
if (state->cd != reinterpret_cast<iconv_t>(-1)) {
size_t outBytesLeft = len + 3; // +3 for the BOM
- QByteArray ba;
- ba.resize(outBytesLeft);
+ QByteArray ba(outBytesLeft, Qt::Uninitialized);
outBytes = ba.data();
#if !defined(NO_BOM)
@@ -358,8 +356,7 @@ QByteArray QIconvCodec::convertFromUnicode(const QChar *uc, int len, ConverterSt
}
size_t outBytesLeft = len;
- QByteArray ba;
- ba.resize(outBytesLeft);
+ QByteArray ba(outBytesLeft, Qt::Uninitialized);
outBytes = ba.data();
// now feed iconv() the real data
@@ -458,7 +455,7 @@ iconv_t QIconvCodec::createIconv_t(const char *to, const char *from)
char *codeset = 0;
#endif
-#if defined(_XOPEN_UNIX) && !defined(Q_OS_QNX6) && !defined(Q_OS_OSF)
+#if defined(_XOPEN_UNIX) && !defined(Q_OS_QNX) && !defined(Q_OS_OSF)
if (cd == (iconv_t) -1) {
codeset = nl_langinfo(CODESET);
if (codeset)
diff --git a/src/corelib/codecs/qisciicodec.cpp b/src/corelib/codecs/qisciicodec.cpp
index eccce8b..87905ca 100644
--- a/src/corelib/codecs/qisciicodec.cpp
+++ b/src/corelib/codecs/qisciicodec.cpp
@@ -38,7 +38,6 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-
#include "qisciicodec_p.h"
#include "qlist.h"
@@ -55,7 +54,7 @@ QT_BEGIN_NAMESPACE
struct Codecs {
- const char *name;
+ const char name[10];
ushort base;
};
@@ -187,8 +186,7 @@ QByteArray QIsciiCodec::convertFromUnicode(const QChar *uc, int len, ConverterSt
}
int invalid = 0;
- QByteArray result;
- result.resize(2*len); //worst case
+ QByteArray result(2 * len, Qt::Uninitialized); //worst case
uchar *ch = reinterpret_cast<uchar *>(result.data());
@@ -250,8 +248,7 @@ QString QIsciiCodec::convertToUnicode(const char* chars, int len, ConverterState
halant = state->state_data[0];
}
- QString result;
- result.resize(len);
+ QString result(len, Qt::Uninitialized);
QChar *uc = result.data();
const int base = codecs[idx].base;
diff --git a/src/corelib/codecs/qlatincodec.cpp b/src/corelib/codecs/qlatincodec.cpp
index f5ac3f7..8e1e30e 100644
--- a/src/corelib/codecs/qlatincodec.cpp
+++ b/src/corelib/codecs/qlatincodec.cpp
@@ -62,8 +62,7 @@ QString QLatin1Codec::convertToUnicode(const char *chars, int len, ConverterStat
QByteArray QLatin1Codec::convertFromUnicode(const QChar *ch, int len, ConverterState *state) const
{
const char replacement = (state && state->flags & ConvertInvalidToNull) ? 0 : '?';
- QByteArray r;
- r.resize(len);
+ QByteArray r(len, Qt::Uninitialized);
char *d = r.data();
int invalid = 0;
for (int i = 0; i < len; ++i) {
@@ -151,8 +150,7 @@ QString QLatin15Codec::convertToUnicode(const char* chars, int len, ConverterSta
QByteArray QLatin15Codec::convertFromUnicode(const QChar *in, int length, ConverterState *state) const
{
const char replacement = (state && state->flags & ConvertInvalidToNull) ? 0 : '?';
- QByteArray r;
- r.resize(length);
+ QByteArray r(length, Qt::Uninitialized);
char *d = r.data();
int invalid = 0;
for (int i = 0; i < length; ++i) {
diff --git a/src/corelib/codecs/qsimplecodec.cpp b/src/corelib/codecs/qsimplecodec.cpp
index 985d946..b6984e8 100644
--- a/src/corelib/codecs/qsimplecodec.cpp
+++ b/src/corelib/codecs/qsimplecodec.cpp
@@ -653,8 +653,7 @@ QString QSimpleTextCodec::convertToUnicode(const char* chars, int len, Converter
const unsigned char * c = (const unsigned char *)chars;
- QString r;
- r.resize(len);
+ QString r(len, Qt::Uninitialized);
QChar* uc = r.data();
for (int i = 0; i < len; i++) {
@@ -677,8 +676,7 @@ QByteArray QSimpleTextCodec::convertFromUnicode(const QChar *in, int length, Con
delete tmp;
}
- QByteArray r;
- r.resize(length);
+ QByteArray r(length, Qt::Uninitialized);
int i = length;
int u;
const QChar* ucp = in;
diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp
index 841c3a3..0e21ee1 100644
--- a/src/corelib/codecs/qtextcodec.cpp
+++ b/src/corelib/codecs/qtextcodec.cpp
@@ -84,7 +84,7 @@
#include <stdlib.h>
#include <ctype.h>
#include <locale.h>
-#if defined (_XOPEN_UNIX) && !defined(Q_OS_QNX6) && !defined(Q_OS_OSF)
+#if defined (_XOPEN_UNIX) && !defined(Q_OS_QNX) && !defined(Q_OS_OSF)
#include <langinfo.h>
#endif
@@ -92,6 +92,9 @@
# define QT_NO_SETLOCALE
#endif
+// enabling this is not exception safe!
+// #define Q_DEBUG_TEXTCODEC
+
QT_BEGIN_NAMESPACE
#ifndef QT_NO_TEXTCODECPLUGIN
@@ -169,7 +172,9 @@ static QTextCodec *createForMib(int mib)
}
static QList<QTextCodec*> *all = 0;
+#ifdef Q_DEBUG_TEXTCODEC
static bool destroying_is_ok = false;
+#endif
static QTextCodec *localeMapper = 0;
QTextCodec *QTextCodec::cftr = 0;
@@ -191,15 +196,21 @@ QTextCodecCleanup::~QTextCodecCleanup()
if (!all)
return;
+#ifdef Q_DEBUG_TEXTCODEC
destroying_is_ok = true;
+#endif
- while (all->size())
- delete all->takeFirst();
+ for (QList<QTextCodec *>::const_iterator it = all->constBegin()
+ ; it != all->constEnd(); ++it) {
+ delete *it;
+ }
delete all;
all = 0;
localeMapper = 0;
+#ifdef Q_DEBUG_TEXTCODEC
destroying_is_ok = false;
+#endif
}
Q_GLOBAL_STATIC(QTextCodecCleanup, createQTextCodecCleanup)
@@ -237,9 +248,9 @@ QString QWindowsLocalCodec::convertToUnicode(const char *chars, int length, Conv
return QString();
const int wclen_auto = 4096;
- WCHAR wc_auto[wclen_auto];
+ wchar_t wc_auto[wclen_auto];
int wclen = wclen_auto;
- WCHAR *wc = wc_auto;
+ wchar_t *wc = wc_auto;
int len;
QString sp;
bool prepend = false;
@@ -279,7 +290,7 @@ QString QWindowsLocalCodec::convertToUnicode(const char *chars, int length, Conv
} else {
wclen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
mb, mblen, 0, 0);
- wc = new WCHAR[wclen];
+ wc = new wchar_t[wclen];
// and try again...
}
} else if (r == ERROR_NO_UNICODE_TRANSLATION) {
@@ -345,7 +356,7 @@ QString QWindowsLocalCodec::convertToUnicodeCharByChar(const char *chars, int le
const char *next = 0;
QString s;
while((next = CharNextExA(CP_ACP, mb, 0)) != mb) {
- WCHAR wc[2] ={0};
+ wchar_t wc[2] ={0};
int charlength = next - mb;
int len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, mb, charlength, wc, 2);
if (len>0) {
@@ -452,10 +463,10 @@ static const char * const tis_620locales[] = {
// static const char * const tcvnlocales[] = {
// "vi", "vi_VN", 0 };
-static bool try_locale_list(const char * const locale[], const char * lang)
+static bool try_locale_list(const char * const locale[], const QByteArray &lang)
{
int i;
- for(i=0; locale[i] && *locale[i] && strcmp(locale[i], lang); i++)
+ for(i=0; locale[i] && lang != locale[i]; i++)
;
return locale[i] != 0;
}
@@ -507,13 +518,12 @@ static QTextCodec * ru_RU_hack(const char * i) {
#endif
#if !defined(Q_OS_WIN32) && !defined(Q_OS_WINCE)
-static QTextCodec *checkForCodec(const char *name) {
+static QTextCodec *checkForCodec(const QByteArray &name) {
QTextCodec *c = QTextCodec::codecForName(name);
if (!c) {
- const char *at = strchr(name, '@');
- if (at) {
- QByteArray n(name, at - name);
- c = QTextCodec::codecForName(n.data());
+ const int index = name.indexOf('@');
+ if (index != -1) {
+ c = QTextCodec::codecForName(name.left(index));
}
}
return c;
@@ -533,7 +543,7 @@ static void setupLocaleMapper()
localeMapper = QTextCodec::codecForName("System");
#endif
-#if defined (_XOPEN_UNIX) && !defined(Q_OS_QNX6) && !defined(Q_OS_OSF)
+#if defined (_XOPEN_UNIX) && !defined(Q_OS_QNX) && !defined(Q_OS_OSF)
if (!localeMapper) {
char *charset = nl_langinfo (CODESET);
if (charset)
@@ -554,21 +564,19 @@ static void setupLocaleMapper()
// definitely knows it, but since we cannot fully trust it, get ready
// to fall back to environment variables.
#if !defined(QT_NO_SETLOCALE)
- char * ctype = qstrdup(setlocale(LC_CTYPE, 0));
+ const QByteArray ctype = setlocale(LC_CTYPE, 0);
#else
- char * ctype = qstrdup("");
+ const QByteArray ctype;
#endif
// Get the first nonempty value from $LC_ALL, $LC_CTYPE, and $LANG
// environment variables.
- char * lang = qstrdup(qgetenv("LC_ALL").constData());
- if (!lang || lang[0] == 0 || strcmp(lang, "C") == 0) {
- if (lang) delete [] lang;
- lang = qstrdup(qgetenv("LC_CTYPE").constData());
+ QByteArray lang = qgetenv("LC_ALL");
+ if (lang.isEmpty() || lang == "C") {
+ lang = qgetenv("LC_CTYPE");
}
- if (!lang || lang[0] == 0 || strcmp(lang, "C") == 0) {
- if (lang) delete [] lang;
- lang = qstrdup(qgetenv("LANG").constData());
+ if (lang.isEmpty() || lang == "C") {
+ lang = qgetenv("LANG");
}
// Now try these in order:
@@ -581,35 +589,35 @@ static void setupLocaleMapper()
// 7. guess locale from lang
// 1. CODESET from ctype if it contains a .CODESET part (e.g. en_US.ISO8859-15)
- char * codeset = ctype ? strchr(ctype, '.') : 0;
- if (codeset && *codeset == '.')
- localeMapper = checkForCodec(codeset + 1);
+ int indexOfDot = ctype.indexOf('.');
+ if (indexOfDot != -1)
+ localeMapper = checkForCodec( ctype.mid(indexOfDot + 1) );
// 2. CODESET from lang if it contains a .CODESET part
- codeset = lang ? strchr(lang, '.') : 0;
- if (!localeMapper && codeset && *codeset == '.')
- localeMapper = checkForCodec(codeset + 1);
+ if (!localeMapper) {
+ indexOfDot = lang.indexOf('.');
+ if (indexOfDot != -1)
+ localeMapper = checkForCodec( lang.mid(indexOfDot + 1) );
+ }
// 3. ctype (maybe the locale is named "ISO-8859-1" or something)
- if (!localeMapper && ctype && *ctype != 0 && strcmp (ctype, "C") != 0)
+ if (!localeMapper && !ctype.isEmpty() && ctype != "C")
localeMapper = checkForCodec(ctype);
// 4. locale (ditto)
- if (!localeMapper && lang && *lang != 0)
+ if (!localeMapper && !lang.isEmpty())
localeMapper = checkForCodec(lang);
// 5. "@euro"
- if ((!localeMapper && ctype && strstr(ctype, "@euro")) || (lang && strstr(lang, "@euro")))
+ if ((!localeMapper && ctype.contains("@euro")) || lang.contains("@euro"))
localeMapper = checkForCodec("ISO 8859-15");
// 6. guess locale from ctype unless ctype is "C"
// 7. guess locale from lang
- char * try_by_name = ctype;
- if (ctype && *ctype != 0 && strcmp (ctype, "C") != 0)
- try_by_name = lang;
+ const QByteArray &try_by_name = (!ctype.isEmpty() && ctype != "C") ? lang : ctype;
// Now do the guessing.
- if (lang && *lang && !localeMapper && try_by_name && *try_by_name) {
+ if (!lang.isEmpty() && !localeMapper && !try_by_name.isEmpty()) {
if (try_locale_list(iso8859_15locales, lang))
localeMapper = QTextCodec::codecForName("ISO 8859-15");
else if (try_locale_list(iso8859_2locales, lang))
@@ -642,8 +650,6 @@ static void setupLocaleMapper()
localeMapper = ru_RU_hack(lang);
}
- delete [] ctype;
- delete [] lang;
}
// If everything failed, we default to 8859-1
@@ -663,8 +669,10 @@ static void setup()
if (all)
return;
+#ifdef Q_DEBUG_TEXTCODEC
if (destroying_is_ok)
qWarning("QTextCodec: Creating new codec during codec cleanup");
+#endif
all = new QList<QTextCodec*>;
// create the cleanup object to cleanup all codecs on exit
(void) createQTextCodecCleanup();
@@ -701,6 +709,7 @@ static void setup()
(void)new QJisCodec;
(void)new QSjisCodec;
(void)new QEucKrCodec;
+ (void)new QCP949Codec;
(void)new QBig5Codec;
(void)new QBig5hkscsCodec;
# endif // QT_NO_ICONV && !QT_BOOTSTRAPPED
@@ -919,8 +928,10 @@ QTextCodec::QTextCodec()
*/
QTextCodec::~QTextCodec()
{
+#ifdef Q_DEBUG_TEXTCODEC
if (!destroying_is_ok)
qWarning("QTextCodec::~QTextCodec: Called by application");
+#endif
if (all)
all->removeAll(this);
}
@@ -1051,16 +1062,10 @@ QList<int> QTextCodec::availableMibs()
This might be needed for some applications that want to use their
own mechanism for setting the locale.
- Setting this codec is not supported on DOS based Windows.
-
\sa codecForLocale()
*/
void QTextCodec::setCodecForLocale(QTextCodec *c)
{
-#ifdef Q_WS_WIN
- if (QSysInfo::WindowsVersion& QSysInfo::WV_DOS_based)
- return;
-#endif
localeMapper = c;
if (!localeMapper)
setupLocaleMapper();
@@ -1512,9 +1517,14 @@ QString QTextDecoder::toUnicode(const QByteArray &ba)
/*!
\since 4.4
- Tries to detect the encoding of the provided snippet of HTML in the given byte array, \a ba,
- and returns a QTextCodec instance that is capable of decoding the html to unicode.
- If the codec cannot be detected from the content provided, \a defaultCodec is returned.
+ Tries to detect the encoding of the provided snippet of HTML in
+ the given byte array, \a ba, by checking the BOM (Byte Order Mark)
+ and the content-type meta header and returns a QTextCodec instance
+ that is capable of decoding the html to unicode. If the codec
+ cannot be detected from the content provided, \a defaultCodec is
+ returned.
+
+ \sa codecForUtfText()
*/
QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba, QTextCodec *defaultCodec)
{
@@ -1522,15 +1532,8 @@ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba, QTextCodec *defaultCo
int pos;
QTextCodec *c = 0;
- if (ba.size() > 1 && (((uchar)ba[0] == 0xfe && (uchar)ba[1] == 0xff)
- || ((uchar)ba[0] == 0xff && (uchar)ba[1] == 0xfe))) {
- c = QTextCodec::codecForMib(1015); // utf16
- } else if (ba.size() > 2
- && (uchar)ba[0] == 0xef
- && (uchar)ba[1] == 0xbb
- && (uchar)ba[2] == 0xbf) {
- c = QTextCodec::codecForMib(106); // utf-8
- } else {
+ c = QTextCodec::codecForUtfText(ba, c);
+ if (!c) {
QByteArray header = ba.left(512).toLower();
if ((pos = header.indexOf("http-equiv=")) != -1) {
pos = header.indexOf("charset=", pos) + int(strlen("charset="));
@@ -1549,15 +1552,85 @@ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba, QTextCodec *defaultCo
}
/*!
- \overload
+ \overload
- If the codec cannot be detected, this overload returns a Latin-1 QTextCodec.
+ Tries to detect the encoding of the provided snippet of HTML in
+ the given byte array, \a ba, by checking the BOM (Byte Order Mark)
+ and the content-type meta header and returns a QTextCodec instance
+ that is capable of decoding the html to unicode. If the codec cannot
+ be detected, this overload returns a Latin-1 QTextCodec.
*/
QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba)
{
return codecForHtml(ba, QTextCodec::codecForMib(/*Latin 1*/ 4));
}
+/*!
+ \since 4.6
+
+ Tries to detect the encoding of the provided snippet \a ba by
+ using the BOM (Byte Order Mark) and returns a QTextCodec instance
+ that is capable of decoding the text to unicode. If the codec
+ cannot be detected from the content provided, \a defaultCodec is
+ returned.
+
+ The behavior of this function is undefined if \a ba is not
+ encoded in unicode.
+
+ \sa codecForHtml()
+*/
+QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba, QTextCodec *defaultCodec)
+{
+ const int arraySize = ba.size();
+
+ if (arraySize > 3) {
+ if ((uchar)ba[0] == 0x00
+ && (uchar)ba[1] == 0x00
+ && (uchar)ba[2] == 0xFE
+ && (uchar)ba[3] == 0xFF)
+ return QTextCodec::codecForMib(1018); // utf-32 be
+ else if ((uchar)ba[0] == 0xFF
+ && (uchar)ba[1] == 0xFE
+ && (uchar)ba[2] == 0x00
+ && (uchar)ba[3] == 0x00)
+ return QTextCodec::codecForMib(1019); // utf-32 le
+ }
+
+ if (arraySize < 2)
+ return defaultCodec;
+ if ((uchar)ba[0] == 0xfe && (uchar)ba[1] == 0xff)
+ return QTextCodec::codecForMib(1013); // utf16 be
+ else if ((uchar)ba[0] == 0xff && (uchar)ba[1] == 0xfe)
+ return QTextCodec::codecForMib(1014); // utf16 le
+
+ if (arraySize < 3)
+ return defaultCodec;
+ if ((uchar)ba[0] == 0xef
+ && (uchar)ba[1] == 0xbb
+ && (uchar)ba[2] == 0xbf)
+ return QTextCodec::codecForMib(106); // utf-8
+
+ return defaultCodec;
+}
+
+/*!
+ \overload
+
+ Tries to detect the encoding of the provided snippet \a ba by
+ using the BOM (Byte Order Mark) and returns a QTextCodec instance
+ that is capable of decoding the text to unicode. If the codec
+ cannot be detected, this overload returns a Latin-1 QTextCodec.
+
+ The behavior of this function is undefined if \a ba is not
+ encoded in unicode.
+
+ \sa codecForHtml()
+*/
+QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba)
+{
+ return codecForUtfText(ba, QTextCodec::codecForMib(/*Latin 1*/ 4));
+}
+
/*! \internal
\since 4.3
diff --git a/src/corelib/codecs/qtextcodec.h b/src/corelib/codecs/qtextcodec.h
index b9ba1f8..8e700ba 100644
--- a/src/corelib/codecs/qtextcodec.h
+++ b/src/corelib/codecs/qtextcodec.h
@@ -82,6 +82,9 @@ public:
static QTextCodec *codecForHtml(const QByteArray &ba);
static QTextCodec *codecForHtml(const QByteArray &ba, QTextCodec *defaultCodec);
+ static QTextCodec *codecForUtfText(const QByteArray &ba);
+ static QTextCodec *codecForUtfText(const QByteArray &ba, QTextCodec *defaultCodec);
+
QTextDecoder* makeDecoder() const;
QTextEncoder* makeEncoder() const;
diff --git a/src/corelib/codecs/qtextcodec_p.h b/src/corelib/codecs/qtextcodec_p.h
index 5886ea0..a426c2e 100644
--- a/src/corelib/codecs/qtextcodec_p.h
+++ b/src/corelib/codecs/qtextcodec_p.h
@@ -77,6 +77,33 @@ struct QTextCodecUnalignedPointer
}
};
+#else
+
+class QTextCodec
+{
+public:
+ enum ConversionFlag {
+ DefaultConversion,
+ ConvertInvalidToNull = 0x80000000,
+ IgnoreHeader = 0x1,
+ FreeFunction = 0x2
+ };
+ Q_DECLARE_FLAGS(ConversionFlags, ConversionFlag)
+
+ struct ConverterState {
+ ConverterState(ConversionFlags f = DefaultConversion)
+ : flags(f), remainingChars(0), invalidChars(0), d(0) { state_data[0] = state_data[1] = state_data[2] = 0; }
+ ~ConverterState() { }
+ ConversionFlags flags;
+ int remainingChars;
+ int invalidChars;
+ uint state_data[3];
+ void *d;
+ private:
+ Q_DISABLE_COPY(ConverterState)
+ };
+};
+
#endif //QT_NO_TEXTCODEC
QT_END_NAMESPACE
diff --git a/src/corelib/codecs/qtsciicodec.cpp b/src/corelib/codecs/qtsciicodec.cpp
index 7cbd2af..7dd4701 100644
--- a/src/corelib/codecs/qtsciicodec.cpp
+++ b/src/corelib/codecs/qtsciicodec.cpp
@@ -82,8 +82,7 @@ QByteArray QTsciiCodec::convertFromUnicode(const QChar *uc, int len, ConverterSt
}
int invalid = 0;
- QByteArray rstr;
- rstr.resize(len);
+ QByteArray rstr(len, Qt::Uninitialized);
uchar* cursor = (uchar*)rstr.data();
for (int i = 0; i < len; i++) {
QChar ch = uc[i];
diff --git a/src/corelib/codecs/qtsciicodec_p.h b/src/corelib/codecs/qtsciicodec_p.h
index 188741a..ec8f057 100644
--- a/src/corelib/codecs/qtsciicodec_p.h
+++ b/src/corelib/codecs/qtsciicodec_p.h
@@ -88,7 +88,7 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_CODECS
-class Q_CORE_EXPORT QTsciiCodec : public QTextCodec {
+class QTsciiCodec : public QTextCodec {
public:
~QTsciiCodec();
diff --git a/src/corelib/codecs/qutfcodec.cpp b/src/corelib/codecs/qutfcodec.cpp
index d86e16b..ef538c8 100644
--- a/src/corelib/codecs/qutfcodec.cpp
+++ b/src/corelib/codecs/qutfcodec.cpp
@@ -44,23 +44,19 @@
#include "qendian.h"
#include "qchar.h"
-#ifndef QT_NO_TEXTCODEC
-
QT_BEGIN_NAMESPACE
-QUtf8Codec::~QUtf8Codec()
-{
-}
+enum { Endian = 0, Data = 1 };
-QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const
+QByteArray QUtf8::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state)
{
uchar replacement = '?';
int rlen = 3*len;
int surrogate_high = -1;
if (state) {
- if (state->flags & ConvertInvalidToNull)
+ if (state->flags & QTextCodec::ConvertInvalidToNull)
replacement = 0;
- if (!(state->flags & IgnoreHeader))
+ if (!(state->flags & QTextCodec::IgnoreHeader))
rlen += 3;
if (state->remainingChars)
surrogate_high = state->state_data[0];
@@ -71,7 +67,7 @@ QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterSta
uchar* cursor = (uchar*)rstr.data();
const QChar *ch = uc;
int invalid = 0;
- if (state && !(state->flags & IgnoreHeader)) {
+ if (state && !(state->flags & QTextCodec::IgnoreHeader)) {
*cursor++ = 0xef;
*cursor++ = 0xbb;
*cursor++ = 0xbf;
@@ -133,7 +129,7 @@ QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterSta
rstr.resize(cursor - (const uchar*)rstr.constData());
if (state) {
state->invalidChars += invalid;
- state->flags |= IgnoreHeader;
+ state->flags |= QTextCodec::IgnoreHeader;
state->remainingChars = 0;
if (surrogate_high >= 0) {
state->remainingChars = 1;
@@ -143,18 +139,18 @@ QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterSta
return rstr;
}
-void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, ConverterState *state) const
+QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state)
{
bool headerdone = false;
- QChar replacement = QChar::ReplacementCharacter;
+ ushort replacement = QChar::ReplacementCharacter;
int need = 0;
int error = -1;
uint uc = 0;
uint min_uc = 0;
if (state) {
- if (state->flags & IgnoreHeader)
+ if (state->flags & QTextCodec::IgnoreHeader)
headerdone = true;
- if (state->flags & ConvertInvalidToNull)
+ if (state->flags & QTextCodec::ConvertInvalidToNull)
replacement = QChar::Null;
need = state->remainingChars;
if (need) {
@@ -170,42 +166,34 @@ void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, C
headerdone = true;
}
- int originalLength = target->length();
- QString &result = *target;
- result.resize(originalLength + len + 1); // worst case
- QChar *qch = result.data() + originalLength;
+ QString result(need + len + 1, Qt::Uninitialized); // worst case
+ ushort *qch = (ushort *)result.unicode();
uchar ch;
int invalid = 0;
- for (int i=0; i<len; i++) {
+ for (int i = 0; i < len; ++i) {
ch = chars[i];
if (need) {
if ((ch&0xc0) == 0x80) {
uc = (uc << 6) | (ch & 0x3f);
- need--;
+ --need;
if (!need) {
- if (uc > 0xffff && uc < 0x110000) {
+ // utf-8 bom composes into 0xfeff code point
+ if (!headerdone && uc == 0xfeff) {
+ // dont do anything, just skip the BOM
+ } else if (uc > 0xffff && uc < 0x110000) {
// surrogate pair
- uc -= 0x10000;
- unsigned short high = uc/0x400 + 0xd800;
- unsigned short low = uc%0x400 + 0xdc00;
-
- // resize if necessary
- long where = qch - result.unicode();
- if (where + 2 >= result.length()) {
- result.resize(where + 2);
- qch = result.data() + where;
- }
-
- *qch++ = QChar(high);
- *qch++ = QChar(low);
+ Q_ASSERT((qch - (ushort*)result.unicode()) + 2 < result.length());
+ *qch++ = QChar::highSurrogate(uc);
+ *qch++ = QChar::lowSurrogate(uc);
} else if ((uc < min_uc) || (uc >= 0xd800 && uc <= 0xdfff) || (uc >= 0xfffe)) {
- // error
+ // error: overlong sequence, UTF16 surrogate or BOM
*qch++ = replacement;
++invalid;
} else {
*qch++ = uc;
}
+ headerdone = true;
}
} else {
// error
@@ -213,15 +201,18 @@ void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, C
*qch++ = replacement;
++invalid;
need = 0;
+ headerdone = true;
}
} else {
if (ch < 128) {
- *qch++ = QLatin1Char(ch);
+ *qch++ = ushort(ch);
+ headerdone = true;
} else if ((ch & 0xe0) == 0xc0) {
uc = ch & 0x1f;
need = 1;
error = i;
min_uc = 0x80;
+ headerdone = true;
} else if ((ch & 0xf0) == 0xe0) {
uc = ch & 0x0f;
need = 2;
@@ -232,10 +223,12 @@ void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, C
need = 3;
error = i;
min_uc = 0x10000;
+ headerdone = true;
} else {
// error
*qch++ = replacement;
++invalid;
+ headerdone = true;
}
}
}
@@ -246,57 +239,35 @@ void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, C
++invalid;
}
}
- result.truncate(qch - result.unicode());
+ result.truncate(qch - (ushort *)result.unicode());
if (state) {
state->invalidChars += invalid;
state->remainingChars = need;
if (headerdone)
- state->flags |= IgnoreHeader;
+ state->flags |= QTextCodec::IgnoreHeader;
state->state_data[0] = need ? uc : 0;
state->state_data[1] = need ? min_uc : 0;
}
-}
-
-QString QUtf8Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const
-{
- QString result;
- convertToUnicode(&result, chars, len, state);
return result;
}
-QByteArray QUtf8Codec::name() const
+QByteArray QUtf16::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state, DataEndianness e)
{
- return "UTF-8";
-}
-
-int QUtf8Codec::mibEnum() const
-{
- return 106;
-}
-
-enum { Endian = 0, Data = 1 };
-
-QUtf16Codec::~QUtf16Codec()
-{
-}
-
-QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const
-{
- Endianness endian = e;
+ DataEndianness endian = e;
int length = 2*len;
- if (!state || (!(state->flags & IgnoreHeader))) {
+ if (!state || (!(state->flags & QTextCodec::IgnoreHeader))) {
length += 2;
}
- if (e == Detect) {
- endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE;
+ if (e == DetectEndianness) {
+ endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness;
}
QByteArray d;
d.resize(length);
char *data = d.data();
- if (!state || !(state->flags & IgnoreHeader)) {
+ if (!state || !(state->flags & QTextCodec::IgnoreHeader)) {
QChar bom(QChar::ByteOrderMark);
- if (endian == BE) {
+ if (endian == BigEndianness) {
data[0] = bom.row();
data[1] = bom.cell();
} else {
@@ -305,7 +276,7 @@ QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt
}
data += 2;
}
- if (endian == BE) {
+ if (endian == BigEndianness) {
for (int i = 0; i < len; ++i) {
*(data++) = uc[i].row();
*(data++) = uc[i].cell();
@@ -319,36 +290,35 @@ QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt
if (state) {
state->remainingChars = 0;
- state->flags |= IgnoreHeader;
+ state->flags |= QTextCodec::IgnoreHeader;
}
return d;
}
-QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const
+QString QUtf16::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state, DataEndianness e)
{
- Endianness endian = e;
+ DataEndianness endian = e;
bool half = false;
uchar buf = 0;
bool headerdone = false;
if (state) {
- headerdone = state->flags & IgnoreHeader;
- if (endian == Detect)
- endian = (Endianness)state->state_data[Endian];
+ headerdone = state->flags & QTextCodec::IgnoreHeader;
+ if (endian == DetectEndianness)
+ endian = (DataEndianness)state->state_data[Endian];
if (state->remainingChars) {
half = true;
buf = state->state_data[Data];
}
}
- if (headerdone && endian == Detect)
- endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE;
+ if (headerdone && endian == DetectEndianness)
+ endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness;
- QString result;
- result.resize(len); // worst case
+ QString result(len, Qt::Uninitialized); // worst case
QChar *qch = (QChar *)result.unicode();
while (len--) {
if (half) {
QChar ch;
- if (endian == LE) {
+ if (endian == LittleEndianness) {
ch.setRow(*chars++);
ch.setCell(buf);
} else {
@@ -356,17 +326,17 @@ QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState
ch.setCell(*chars++);
}
if (!headerdone) {
- if (endian == Detect) {
- if (ch == QChar::ByteOrderSwapped && endian != BE) {
- endian = LE;
- } else if (ch == QChar::ByteOrderMark && endian != LE) {
+ if (endian == DetectEndianness) {
+ if (ch == QChar::ByteOrderSwapped && endian != BigEndianness) {
+ endian = LittleEndianness;
+ } else if (ch == QChar::ByteOrderMark && endian != LittleEndianness) {
// ignore BOM
- endian = BE;
+ endian = BigEndianness;
} else {
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- endian = BE;
+ endian = BigEndianness;
} else {
- endian = LE;
+ endian = LittleEndianness;
ch = QChar((ch.unicode() >> 8) | ((ch.unicode() & 0xff) << 8));
}
*qch++ = ch;
@@ -387,8 +357,8 @@ QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState
result.truncate(qch - result.unicode());
if (state) {
- if (endian != Detect)
- state->flags |= IgnoreHeader;
+ if (headerdone)
+ state->flags |= QTextCodec::IgnoreHeader;
state->state_data[Endian] = endian;
if (half) {
state->remainingChars = 1;
@@ -401,73 +371,21 @@ QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState
return result;
}
-int QUtf16Codec::mibEnum() const
-{
- return 1015;
-}
-
-QByteArray QUtf16Codec::name() const
+QByteArray QUtf32::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state, DataEndianness e)
{
- return "UTF-16";
-}
-
-QList<QByteArray> QUtf16Codec::aliases() const
-{
- return QList<QByteArray>();
-}
-
-int QUtf16BECodec::mibEnum() const
-{
- return 1013;
-}
-
-QByteArray QUtf16BECodec::name() const
-{
- return "UTF-16BE";
-}
-
-QList<QByteArray> QUtf16BECodec::aliases() const
-{
- QList<QByteArray> list;
- return list;
-}
-
-int QUtf16LECodec::mibEnum() const
-{
- return 1014;
-}
-
-QByteArray QUtf16LECodec::name() const
-{
- return "UTF-16LE";
-}
-
-QList<QByteArray> QUtf16LECodec::aliases() const
-{
- QList<QByteArray> list;
- return list;
-}
-
-QUtf32Codec::~QUtf32Codec()
-{
-}
-
-QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const
-{
- Endianness endian = e;
+ DataEndianness endian = e;
int length = 4*len;
- if (!state || (!(state->flags & IgnoreHeader))) {
+ if (!state || (!(state->flags & QTextCodec::IgnoreHeader))) {
length += 4;
}
- if (e == Detect) {
- endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE;
+ if (e == DetectEndianness) {
+ endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness;
}
- QByteArray d;
- d.resize(length);
+ QByteArray d(length, Qt::Uninitialized);
char *data = d.data();
- if (!state || !(state->flags & IgnoreHeader)) {
- if (endian == BE) {
+ if (!state || !(state->flags & QTextCodec::IgnoreHeader)) {
+ if (endian == BigEndianness) {
data[0] = 0;
data[1] = 0;
data[2] = (char)0xfe;
@@ -480,7 +398,7 @@ QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt
}
data += 4;
}
- if (endian == BE) {
+ if (endian == BigEndianness) {
for (int i = 0; i < len; ++i) {
uint cp = uc[i].unicode();
if (uc[i].isHighSurrogate() && i < len - 1)
@@ -504,59 +422,59 @@ QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt
if (state) {
state->remainingChars = 0;
- state->flags |= IgnoreHeader;
+ state->flags |= QTextCodec::IgnoreHeader;
}
return d;
}
-QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const
+QString QUtf32::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state, DataEndianness e)
{
- Endianness endian = e;
+ DataEndianness endian = e;
uchar tuple[4];
int num = 0;
bool headerdone = false;
if (state) {
- headerdone = state->flags & IgnoreHeader;
- if (endian == Detect) {
- endian = (Endianness)state->state_data[Endian];
+ headerdone = state->flags & QTextCodec::IgnoreHeader;
+ if (endian == DetectEndianness) {
+ endian = (DataEndianness)state->state_data[Endian];
}
num = state->remainingChars;
memcpy(tuple, &state->state_data[Data], 4);
}
- if (headerdone && endian == Detect)
- endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE;
+ if (headerdone && endian == DetectEndianness)
+ endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness;
QString result;
result.resize((num + len) >> 2 << 1); // worst case
QChar *qch = (QChar *)result.unicode();
-
+
const char *end = chars + len;
while (chars < end) {
tuple[num++] = *chars++;
if (num == 4) {
if (!headerdone) {
- if (endian == Detect) {
- if (endian == Detect) {
- if (tuple[0] == 0xff && tuple[1] == 0xfe && tuple[2] == 0 && tuple[3] == 0 && endian != BE) {
- endian = LE;
+ if (endian == DetectEndianness) {
+ if (endian == DetectEndianness) {
+ if (tuple[0] == 0xff && tuple[1] == 0xfe && tuple[2] == 0 && tuple[3] == 0 && endian != BigEndianness) {
+ endian = LittleEndianness;
num = 0;
continue;
- } else if (tuple[0] == 0 && tuple[1] == 0 && tuple[2] == 0xfe && tuple[3] == 0xff && endian != LE) {
- endian = BE;
+ } else if (tuple[0] == 0 && tuple[1] == 0 && tuple[2] == 0xfe && tuple[3] == 0xff && endian != LittleEndianness) {
+ endian = BigEndianness;
num = 0;
continue;
} else if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- endian = BE;
+ endian = BigEndianness;
} else {
- endian = LE;
+ endian = LittleEndianness;
}
}
- } else if (((endian == BE) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple)) == QChar::ByteOrderMark) {
+ } else if (((endian == BigEndianness) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple)) == QChar::ByteOrderMark) {
num = 0;
continue;
}
}
- uint code = (endian == BE) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple);
+ uint code = (endian == BigEndianness) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple);
if (code >= 0x10000) {
*qch++ = QChar::highSurrogate(code);
*qch++ = QChar::lowSurrogate(code);
@@ -567,10 +485,10 @@ QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState
}
}
result.truncate(qch - result.unicode());
-
+
if (state) {
- if (endian != Detect)
- state->flags |= IgnoreHeader;
+ if (headerdone)
+ state->flags |= QTextCodec::IgnoreHeader;
state->state_data[Endian] = endian;
state->remainingChars = num;
memcpy(&state->state_data[Data], tuple, 4);
@@ -578,6 +496,113 @@ QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState
return result;
}
+
+#ifndef QT_NO_TEXTCODEC
+
+QUtf8Codec::~QUtf8Codec()
+{
+}
+
+QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const
+{
+ return QUtf8::convertFromUnicode(uc, len, state);
+}
+
+void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, ConverterState *state) const
+{
+ *target += QUtf8::convertToUnicode(chars, len, state);
+}
+
+QString QUtf8Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const
+{
+ return QUtf8::convertToUnicode(chars, len, state);
+}
+
+QByteArray QUtf8Codec::name() const
+{
+ return "UTF-8";
+}
+
+int QUtf8Codec::mibEnum() const
+{
+ return 106;
+}
+
+QUtf16Codec::~QUtf16Codec()
+{
+}
+
+QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const
+{
+ return QUtf16::convertFromUnicode(uc, len, state, e);
+}
+
+QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const
+{
+ return QUtf16::convertToUnicode(chars, len, state, e);
+}
+
+int QUtf16Codec::mibEnum() const
+{
+ return 1015;
+}
+
+QByteArray QUtf16Codec::name() const
+{
+ return "UTF-16";
+}
+
+QList<QByteArray> QUtf16Codec::aliases() const
+{
+ return QList<QByteArray>();
+}
+
+int QUtf16BECodec::mibEnum() const
+{
+ return 1013;
+}
+
+QByteArray QUtf16BECodec::name() const
+{
+ return "UTF-16BE";
+}
+
+QList<QByteArray> QUtf16BECodec::aliases() const
+{
+ QList<QByteArray> list;
+ return list;
+}
+
+int QUtf16LECodec::mibEnum() const
+{
+ return 1014;
+}
+
+QByteArray QUtf16LECodec::name() const
+{
+ return "UTF-16LE";
+}
+
+QList<QByteArray> QUtf16LECodec::aliases() const
+{
+ QList<QByteArray> list;
+ return list;
+}
+
+QUtf32Codec::~QUtf32Codec()
+{
+}
+
+QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const
+{
+ return QUtf32::convertFromUnicode(uc, len, state, e);
+}
+
+QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const
+{
+ return QUtf32::convertToUnicode(chars, len, state, e);
+}
+
int QUtf32Codec::mibEnum() const
{
return 1017;
@@ -626,7 +651,6 @@ QList<QByteArray> QUtf32LECodec::aliases() const
return list;
}
+#endif //QT_NO_TEXTCODEC
QT_END_NAMESPACE
-
-#endif //QT_NO_TEXTCODEC
diff --git a/src/corelib/codecs/qutfcodec_p.h b/src/corelib/codecs/qutfcodec_p.h
index 3642696..60c8284 100644
--- a/src/corelib/codecs/qutfcodec_p.h
+++ b/src/corelib/codecs/qutfcodec_p.h
@@ -54,9 +54,35 @@
//
#include "QtCore/qtextcodec.h"
+#include "private/qtextcodec_p.h"
QT_BEGIN_NAMESPACE
+enum DataEndianness
+{
+ DetectEndianness,
+ BigEndianness,
+ LittleEndianness
+};
+
+struct QUtf8
+{
+ static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *);
+ static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *);
+};
+
+struct QUtf16
+{
+ static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness);
+ static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness);
+};
+
+struct QUtf32
+{
+ static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness);
+ static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness);
+};
+
#ifndef QT_NO_TEXTCODEC
class QUtf8Codec : public QTextCodec {
@@ -73,13 +99,8 @@ public:
class QUtf16Codec : public QTextCodec {
protected:
- enum Endianness {
- Detect,
- BE,
- LE
- };
public:
- QUtf16Codec() { e = Detect; }
+ QUtf16Codec() { e = DetectEndianness; }
~QUtf16Codec();
QByteArray name() const;
@@ -90,12 +111,12 @@ public:
QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const;
protected:
- Endianness e;
+ DataEndianness e;
};
class QUtf16BECodec : public QUtf16Codec {
public:
- QUtf16BECodec() : QUtf16Codec() { e = BE; }
+ QUtf16BECodec() : QUtf16Codec() { e = BigEndianness; }
QByteArray name() const;
QList<QByteArray> aliases() const;
int mibEnum() const;
@@ -103,21 +124,15 @@ public:
class QUtf16LECodec : public QUtf16Codec {
public:
- QUtf16LECodec() : QUtf16Codec() { e = LE; }
+ QUtf16LECodec() : QUtf16Codec() { e = LittleEndianness; }
QByteArray name() const;
QList<QByteArray> aliases() const;
int mibEnum() const;
};
class QUtf32Codec : public QTextCodec {
-protected:
- enum Endianness {
- Detect,
- BE,
- LE
- };
public:
- QUtf32Codec() { e = Detect; }
+ QUtf32Codec() { e = DetectEndianness; }
~QUtf32Codec();
QByteArray name() const;
@@ -128,12 +143,12 @@ public:
QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const;
protected:
- Endianness e;
+ DataEndianness e;
};
class QUtf32BECodec : public QUtf32Codec {
public:
- QUtf32BECodec() : QUtf32Codec() { e = BE; }
+ QUtf32BECodec() : QUtf32Codec() { e = BigEndianness; }
QByteArray name() const;
QList<QByteArray> aliases() const;
int mibEnum() const;
@@ -141,7 +156,7 @@ public:
class QUtf32LECodec : public QUtf32Codec {
public:
- QUtf32LECodec() : QUtf32Codec() { e = LE; }
+ QUtf32LECodec() : QUtf32Codec() { e = LittleEndianness; }
QByteArray name() const;
QList<QByteArray> aliases() const;
int mibEnum() const;
diff --git a/src/corelib/concurrent/qfuture.cpp b/src/corelib/concurrent/qfuture.cpp
index 2e35a85..90a4179 100644
--- a/src/corelib/concurrent/qfuture.cpp
+++ b/src/corelib/concurrent/qfuture.cpp
@@ -44,8 +44,10 @@
\brief The QFuture class represents the result of an asynchronous computation.
\since 4.4
+ \ingroup thread
+
To start a computation, use one of the APIs in the
- \l {threads.html#qtconcurrent-intro}{Qt Concurrent} framework.
+ \l {Concurrent Programming}{Qt Concurrent} framework.
QFuture allows threads to be synchronized against one or more results
which will be ready at a later point in time. The result can be of any type
@@ -90,7 +92,7 @@
To interact with running tasks using signals and slots, use QFutureWatcher.
- \sa QFutureWatcher, {threads.html#qtconcurrent-intro}{Qt Concurrent}
+ \sa QFutureWatcher, {Concurrent Programming}{Qt Concurrent}
*/
/*! \fn QFuture::QFuture()
diff --git a/src/corelib/concurrent/qfuturesynchronizer.cpp b/src/corelib/concurrent/qfuturesynchronizer.cpp
index cd67a4b..c05d278 100644
--- a/src/corelib/concurrent/qfuturesynchronizer.cpp
+++ b/src/corelib/concurrent/qfuturesynchronizer.cpp
@@ -44,7 +44,9 @@
\brief The QFutureSynchronizer class is a convenience class that simplifies
QFuture synchronization.
-
+
+ \ingroup thread
+
QFutureSynchronizer is a template class that simplifies synchronization of
one or more QFuture objects. Futures are added using the addFuture() or
setFuture() functions. The futures() function returns a list of futures.
@@ -63,7 +65,7 @@
You can query the status of the cancel-on-wait feature using the
cancelOnWait() function.
- \sa QFuture, QFutureWatcher, {threads.html#qtconcurrent-intro}{Qt Concurrent}
+ \sa QFuture, QFutureWatcher, {Concurrent Programming}{Qt Concurrent}
*/
/*!
diff --git a/src/corelib/concurrent/qfuturewatcher.cpp b/src/corelib/concurrent/qfuturewatcher.cpp
index 68df40f..4205177 100644
--- a/src/corelib/concurrent/qfuturewatcher.cpp
+++ b/src/corelib/concurrent/qfuturewatcher.cpp
@@ -43,9 +43,9 @@
#ifndef QT_NO_QFUTURE
-#include <QEvent>
-#include <QCoreApplication>
-#include <QThread>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qthread.h>
#include "qfuturewatcher_p.h"
@@ -55,6 +55,8 @@ QT_BEGIN_NAMESPACE
\reentrant
\since 4.4
+ \ingroup thread
+
\brief The QFutureWatcher class allows monitoring a QFuture using signals
and slots.
@@ -94,7 +96,7 @@ QT_BEGIN_NAMESPACE
QFutureWatcher<void> as well. This is useful if only status or progress
information is needed; not the actual result data.
- \sa QFuture, {threads.html#qtconcurrent-intro}{Qt Concurrent}
+ \sa QFuture, {Concurrent Programming}{Qt Concurrent}
*/
/*! \fn QFutureWatcher::QFutureWatcher(QObject *parent)
diff --git a/src/corelib/concurrent/qfuturewatcher_p.h b/src/corelib/concurrent/qfuturewatcher_p.h
index 7b136ca..761a571 100644
--- a/src/corelib/concurrent/qfuturewatcher_p.h
+++ b/src/corelib/concurrent/qfuturewatcher_p.h
@@ -54,7 +54,7 @@
//
#include "qfutureinterface_p.h"
-#include <QList>
+#include <qlist.h>
#ifndef QT_NO_QFUTURE
@@ -63,8 +63,8 @@
QT_BEGIN_NAMESPACE
class QFutureWatcherBase;
-class Q_CORE_EXPORT QFutureWatcherBasePrivate : public QObjectPrivate,
- public QFutureCallOutInterface
+class QFutureWatcherBasePrivate : public QObjectPrivate,
+ public QFutureCallOutInterface
{
Q_DECLARE_PUBLIC(QFutureWatcherBase)
diff --git a/src/corelib/concurrent/qrunnable.cpp b/src/corelib/concurrent/qrunnable.cpp
index 1945af9..3c9c1ea 100644
--- a/src/corelib/concurrent/qrunnable.cpp
+++ b/src/corelib/concurrent/qrunnable.cpp
@@ -44,6 +44,8 @@
\since 4.4
\brief The QRunnable class is the base class for all runnable objects.
+ \ingroup thread
+
The QRunnable class is an interface for representing a task or
piece of code that needs to be executed, represented by your
reimplementation of the run() function.
diff --git a/src/corelib/concurrent/qtconcurrentfilter.cpp b/src/corelib/concurrent/qtconcurrentfilter.cpp
index 802c617..15e9905 100644
--- a/src/corelib/concurrent/qtconcurrentfilter.cpp
+++ b/src/corelib/concurrent/qtconcurrentfilter.cpp
@@ -42,12 +42,12 @@
/*!
\headerfile <QtConcurrentFilter>
\title Concurrent Filter and Filter-Reduce
- \ingroup threading
+ \ingroup thread
\brief The <QtConcurrentFilter> header provides concurrent Filter and
Filter-Reduce.
- These functions are a part of the \l {threads.html#qtconcurrent-intro}{Qt Concurrent} framework.
+ These functions are a part of the \l {Concurrent Programming}{Qt Concurrent} framework.
The QtConcurrent::filter(), QtConcurrent::filtered() and
QtConcurrent::filteredReduced() functions filter items in a sequence such
diff --git a/src/corelib/concurrent/qtconcurrentiteratekernel.cpp b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp
index 1ccbf20..74032b1 100644
--- a/src/corelib/concurrent/qtconcurrentiteratekernel.cpp
+++ b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp
@@ -42,22 +42,18 @@
#include "qtconcurrentiteratekernel.h"
#if defined(Q_OS_MAC)
-
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <unistd.h>
-
#elif defined(Q_OS_UNIX)
-
#include <time.h>
#include <unistd.h>
-
#elif defined(Q_OS_WIN)
-
-#include <windows.h>
-
+#include <qt_windows.h>
#endif
+#include "private/qfunctions_p.h"
+
#ifndef QT_NO_CONCURRENT
@@ -108,11 +104,17 @@ static qint64 getticks()
return 0;
return (ts.tv_sec * 1000000000) + ts.tv_nsec;
#else
+
+#ifdef Q_OS_SYMBIAN
+ return clock();
+#else
// no clock_gettime(), fall back to wall time
struct timeval tv;
gettimeofday(&tv, 0);
return (tv.tv_sec * 1000000) + tv.tv_usec;
#endif
+
+#endif
}
#elif defined(Q_OS_WIN)
diff --git a/src/corelib/concurrent/qtconcurrentiteratekernel.h b/src/corelib/concurrent/qtconcurrentiteratekernel.h
index 052d7d5..430d4f8 100644
--- a/src/corelib/concurrent/qtconcurrentiteratekernel.h
+++ b/src/corelib/concurrent/qtconcurrentiteratekernel.h
@@ -49,8 +49,10 @@
#include <QtCore/qatomic.h>
#include <QtCore/qtconcurrentmedian.h>
#include <QtCore/qtconcurrentthreadengine.h>
-#include <iterator>
+#ifndef QT_NO_STL
+# include <iterator>
+#endif
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -148,6 +150,7 @@ public:
inline void * getPointer() { return 0; }
};
+#ifndef QT_NO_STL
inline bool selectIteration(std::bidirectional_iterator_tag)
{
return false; // while
@@ -162,6 +165,14 @@ inline bool selectIteration(std::random_access_iterator_tag)
{
return true; // for
}
+#else
+// no stl support, always use while iteration
+template <typename T>
+inline bool selectIteration(T)
+{
+ return false; // while
+}
+#endif
template <typename Iterator, typename T>
class IterateKernel : public ThreadEngine<T>
@@ -170,7 +181,10 @@ public:
typedef T ResultType;
IterateKernel(Iterator _begin, Iterator _end)
-#ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION
+#if defined (QT_NO_STL)
+ : begin(_begin), end(_end), current(_begin), currentIndex(0),
+ forIteration(false), progressReportingEnabled(true)
+#elif !defined(QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION)
: begin(_begin), end(_end), current(_begin), currentIndex(0),
forIteration(selectIteration(typename std::iterator_traits<Iterator>::iterator_category())), progressReportingEnabled(true)
#else
@@ -178,7 +192,12 @@ public:
forIteration(selectIteration(std::iterator_category(_begin))), progressReportingEnabled(true)
#endif
{
+#if defined (QT_NO_STL)
+ iterationCount = 0;
+#else
iterationCount = forIteration ? std::distance(_begin, _end) : 0;
+
+#endif
}
virtual ~IterateKernel() { }
diff --git a/src/corelib/concurrent/qtconcurrentmap.cpp b/src/corelib/concurrent/qtconcurrentmap.cpp
index f141bb2..df2a6cd 100644
--- a/src/corelib/concurrent/qtconcurrentmap.cpp
+++ b/src/corelib/concurrent/qtconcurrentmap.cpp
@@ -1,4 +1,4 @@
- /****************************************************************************
+/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
@@ -41,13 +41,16 @@
/*!
\namespace QtConcurrent
+ \inmodule QtCore
\since 4.4
\brief The QtConcurrent namespace provides high-level APIs that make it
possible to write multi-threaded programs without using low-level
threading primitives.
- See the \l {threads.html#qtconcurrent-intro}{Qt Concurrent} section in the \l{threads.html}{threading} documentation.
-
+ See the \l {Concurrent Programming}{Qt Concurrent} chapter in
+ the \l{threads.html}{threading} documentation.
+
+ \inheaderfile QtCore
\ingroup thread
*/
@@ -57,8 +60,6 @@
\brief The QtConcurrent::internal namespace contains QtConcurrent
implementation details.
-
- \ingroup thread
*/
/*!
@@ -77,11 +78,11 @@
/*!
\headerfile <QtConcurrentMap>
\title Concurrent Map and Map-Reduce
- \ingroup threading
+ \ingroup thread
\brief The <QtConcurrentMap> header provides concurrent Map and MapReduce.
- These functions are a part of the \l {threads.html#qtconcurrent-intro}{Qt Concurrent} framework.
+ These functions are a part of the \l {Concurrent Programming}{Qt Concurrent} framework.
The QtConcurrent::map(), QtConcurrent::mapped() and
QtConcurrent::mappedReduced() functions run computations in parallel on
diff --git a/src/corelib/concurrent/qtconcurrentrun.cpp b/src/corelib/concurrent/qtconcurrentrun.cpp
index bca56b1..2a43fcb 100644
--- a/src/corelib/concurrent/qtconcurrentrun.cpp
+++ b/src/corelib/concurrent/qtconcurrentrun.cpp
@@ -42,11 +42,13 @@
/*!
\headerfile <QtConcurrentRun>
\title Asynchronous Run
-
+
\brief The <QtConcurrentRun> header provides a way to run a function in a
separate thread.
+
+ \ingroup thread
- This function is a part of the \l {threads.html#qtconcurrent-intro}{Qt Concurrent} framework.
+ This function is a part of the \l {Concurrent Programming}{Qt Concurrent} framework.
The QtConcurrent::run() function runs a function in a separate thread.
The return value of the function is made available through the QFuture API.
diff --git a/src/corelib/concurrent/qtconcurrentthreadengine.cpp b/src/corelib/concurrent/qtconcurrentthreadengine.cpp
index 97d4bb8..b32e760 100644
--- a/src/corelib/concurrent/qtconcurrentthreadengine.cpp
+++ b/src/corelib/concurrent/qtconcurrentthreadengine.cpp
@@ -47,6 +47,81 @@ QT_BEGIN_NAMESPACE
namespace QtConcurrent {
+ThreadEngineBarrier::ThreadEngineBarrier()
+:count(0) { }
+
+void ThreadEngineBarrier::acquire()
+{
+ forever {
+ int localCount = int(count);
+ if (localCount < 0) {
+ if (count.testAndSetOrdered(localCount, localCount -1))
+ return;
+ } else {
+ if (count.testAndSetOrdered(localCount, localCount + 1))
+ return;
+ }
+ }
+}
+
+int ThreadEngineBarrier::release()
+{
+ forever {
+ int localCount = int(count);
+ if (localCount == -1) {
+ if (count.testAndSetOrdered(-1, 0)) {
+ semaphore.release();
+ return 0;
+ }
+ } else if (localCount < 0) {
+ if (count.testAndSetOrdered(localCount, localCount + 1))
+ return qAbs(localCount + 1);
+ } else {
+ if (count.testAndSetOrdered(localCount, localCount - 1))
+ return localCount - 1;
+ }
+ }
+}
+
+// Wait until all threads have been released
+void ThreadEngineBarrier::wait()
+{
+ forever {
+ int localCount = int(count);
+ if (localCount == 0)
+ return;
+
+ Q_ASSERT(localCount > 0); // multiple waiters are not allowed.
+ if (count.testAndSetOrdered(localCount, -localCount)) {
+ semaphore.acquire();
+ return;
+ }
+ }
+}
+
+int ThreadEngineBarrier::currentCount()
+{
+ return int(count);
+}
+
+// releases a thread, unless this is the last thread.
+// returns true if the thread was released.
+bool ThreadEngineBarrier::releaseUnlessLast()
+{
+ forever {
+ int localCount = int(count);
+ if (qAbs(localCount) == 1) {
+ return false;
+ } else if (localCount < 0) {
+ if (count.testAndSetOrdered(localCount, localCount + 1))
+ return true;
+ } else {
+ if (count.testAndSetOrdered(localCount, localCount - 1))
+ return true;
+ }
+ }
+}
+
ThreadEngineBase::ThreadEngineBase()
:futureInterface(0), threadPool(QThreadPool::globalInstance())
{
@@ -66,7 +141,7 @@ void ThreadEngineBase::startSingleThreaded()
void ThreadEngineBase::startBlocking()
{
start();
- semaphore.acquire();
+ barrier.acquire();
startThreads();
bool throttled = false;
@@ -88,10 +163,10 @@ void ThreadEngineBase::startBlocking()
#endif
if (throttled == false) {
- semaphore.release();
+ barrier.release();
}
- semaphore.wait();
+ barrier.wait();
finish();
exceptionStore.throwPossibleException();
}
@@ -101,6 +176,11 @@ void ThreadEngineBase::startThread()
startThreadInternal();
}
+void ThreadEngineBase::acquireBarrierSemaphore()
+{
+ barrier.acquire();
+}
+
bool ThreadEngineBase::isCanceled()
{
if (futureInterface)
@@ -138,9 +218,9 @@ bool ThreadEngineBase::startThreadInternal()
if (this->isCanceled())
return false;
- semaphore.acquire();
+ barrier.acquire();
if (!threadPool->tryStart(this)) {
- semaphore.release();
+ barrier.release();
return false;
}
return true;
@@ -155,7 +235,7 @@ void ThreadEngineBase::startThreads()
void ThreadEngineBase::threadExit()
{
const bool asynchronous = futureInterface != 0;
- const int lastThread = (semaphore.release() == 0);
+ const int lastThread = (barrier.release() == 0);
if (lastThread && asynchronous)
this->asynchronousFinish();
@@ -166,7 +246,7 @@ void ThreadEngineBase::threadExit()
// this function returns one.
bool ThreadEngineBase::threadThrottleExit()
{
- return semaphore.releaseUnlessLast();
+ return barrier.releaseUnlessLast();
}
void ThreadEngineBase::run() // implements QRunnable.
diff --git a/src/corelib/concurrent/qtconcurrentthreadengine.h b/src/corelib/concurrent/qtconcurrentthreadengine.h
index 06aeef1..adab567 100644
--- a/src/corelib/concurrent/qtconcurrentthreadengine.h
+++ b/src/corelib/concurrent/qtconcurrentthreadengine.h
@@ -51,6 +51,8 @@
#include <QtCore/qdebug.h>
#include <QtCore/qtconcurrentexception.h>
#include <QtCore/qwaitcondition.h>
+#include <QtCore/qatomic.h>
+#include <QtCore/qsemaphore.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -61,55 +63,29 @@ QT_MODULE(Core)
namespace QtConcurrent {
-// A Semaphore that can wait until all resources are returned.
-class ThreadEngineSemaphore
+// The ThreadEngineBarrier counts worker threads, and allows one
+// thread to wait for all others to finish. Tested for its use in
+// QtConcurrent, requires more testing for use as a general class.
+class ThreadEngineBarrier
{
-public:
- ThreadEngineSemaphore()
- :count(0) { }
-
- void acquire()
- {
- QMutexLocker lock(&mutex);
- ++count;
- }
-
- int release()
- {
- QMutexLocker lock(&mutex);
- if (--count == 0)
- waitCondition.wakeAll();
- return count;
- }
-
- // Wait until all resources are released.
- void wait()
- {
- QMutexLocker lock(&mutex);
- if (count != 0)
- waitCondition.wait(&mutex);
- }
-
- int currentCount()
- {
- return count;
- }
-
- // releases a resource, unless this is the last resource.
- // returns true if a resource was released.
- bool releaseUnlessLast()
- {
- QMutexLocker lock(&mutex);
- if (count == 1)
- return false;
- --count;
- return true;
- }
-
private:
+ // The thread count is maintained as an integer in the count atomic
+ // variable. The count can be either positive or negative - a negative
+ // count signals that a thread is waiting on the barrier.
+
+ // BC note: inlined code from Qt < 4.6 will expect to find the QMutex
+ // and QAtomicInt here. ### Qt 5: remove.
QMutex mutex;
- int count;
- QWaitCondition waitCondition;
+ QAtomicInt count;
+
+ QSemaphore semaphore;
+public:
+ ThreadEngineBarrier();
+ void acquire();
+ int release();
+ void wait();
+ int currentCount();
+ bool releaseUnlessLast();
};
enum ThreadFunctionResult { ThrottleThread, ThreadFinished };
@@ -132,6 +108,7 @@ public:
bool isProgressReportingEnabled();
void setProgressValue(int progress);
void setProgressRange(int minimum, int maximum);
+ void acquireBarrierSemaphore();
protected: // The user overrides these:
virtual void start() {}
@@ -152,7 +129,7 @@ private:
protected:
QFutureInterfaceBase *futureInterface;
QThreadPool *threadPool;
- ThreadEngineSemaphore semaphore;
+ ThreadEngineBarrier barrier;
QtConcurrent::internal::ExceptionStore exceptionStore;
};
@@ -199,7 +176,7 @@ public:
QFuture<T> future = QFuture<T>(futureInterfaceTyped());
start();
- semaphore.acquire();
+ acquireBarrierSemaphore();
threadPool->start(this);
return future;
}
@@ -261,9 +238,11 @@ protected:
template <typename T>
class ThreadEngineStarter : public ThreadEngineStarterBase<T>
{
+ typedef ThreadEngineStarterBase<T> Base;
+ typedef ThreadEngine<T> TypedThreadEngine;
public:
- ThreadEngineStarter(ThreadEngine<T> *threadEngine)
- :ThreadEngineStarterBase<T>(threadEngine) {}
+ ThreadEngineStarter(TypedThreadEngine *eng)
+ : Base(eng) { }
T startBlocking()
{
diff --git a/src/corelib/concurrent/qthreadpool.cpp b/src/corelib/concurrent/qthreadpool.cpp
index 286387d..599296f 100644
--- a/src/corelib/concurrent/qthreadpool.cpp
+++ b/src/corelib/concurrent/qthreadpool.cpp
@@ -222,6 +222,8 @@ void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority)
int QThreadPoolPrivate::activeThreadCount() const
{
+ // To improve scalability this function is called without holding
+ // the mutex lock -- keep it thread-safe.
return (allThreads.count()
- expiredThreads.count()
- waitingThreads
@@ -246,14 +248,14 @@ bool QThreadPoolPrivate::tooManyThreadsActive() const
*/
void QThreadPoolPrivate::startThread(QRunnable *runnable)
{
- QThreadPoolThread *thread = new QThreadPoolThread(this);
- allThreads.insert(thread);
+ QScopedPointer <QThreadPoolThread> thread(new QThreadPoolThread(this));
+ allThreads.insert(thread.data());
++activeThreads;
if (runnable->autoDelete())
++runnable->ref;
thread->runnable = runnable;
- thread->start();
+ thread.take()->start();
}
/*! \internal
@@ -362,6 +364,8 @@ void QThreadPoolPrivate::stealRunnable(QRunnable *runnable)
\since 4.4
\threadsafe
+ \ingroup thread
+
QThreadPool manages and recyles individual QThread objects to help reduce
thread creation costs in programs that use threads. Each Qt application
has one global QThreadPool object, which can be accessed by calling
@@ -402,7 +406,7 @@ void QThreadPoolPrivate::stealRunnable(QRunnable *runnable)
Note that QThreadPool is a low-level class for managing threads, see
QtConcurrent::run() or the other
- \l {threads.html#qtconcurrent-intro}{Qt Concurrent} APIs for higher
+ \l {Concurrent Programming}{Qt Concurrent} APIs for higher
level alternatives.
\sa QRunnable
@@ -481,6 +485,12 @@ bool QThreadPool::tryStart(QRunnable *runnable)
return false;
Q_D(QThreadPool);
+
+ // To improve scalability perform a check on the thread count
+ // before locking the mutex.
+ if (d->allThreads.isEmpty() == false && d->activeThreadCount() >= d->maxThreadCount)
+ return false;
+
QMutexLocker locker(&d->mutex);
return d->tryStart(runnable);
}
@@ -527,7 +537,6 @@ void QThreadPool::setExpiryTimeout(int expiryTimeout)
int QThreadPool::maxThreadCount() const
{
Q_D(const QThreadPool);
- QMutexLocker locker(&d->mutex);
return d->maxThreadCount;
}
@@ -556,7 +565,6 @@ void QThreadPool::setMaxThreadCount(int maxThreadCount)
int QThreadPool::activeThreadCount() const
{
Q_D(const QThreadPool);
- QMutexLocker locker(&d->mutex);
return d->activeThreadCount();
}
diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro
index f99d57f..f835bee 100644
--- a/src/corelib/corelib.pro
+++ b/src/corelib/corelib.pro
@@ -5,6 +5,7 @@ DEFINES += QT_BUILD_CORE_LIB QT_NO_USING_NAMESPACE
win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x67000000
include(../qbase.pri)
+include(animation/animation.pri)
include(arch/arch.pri)
include(concurrent/concurrent.pri)
include(global/global.pri)
@@ -14,9 +15,10 @@ include(io/io.pri)
include(plugin/plugin.pri)
include(kernel/kernel.pri)
include(codecs/codecs.pri)
+include(statemachine/statemachine.pri)
include(xml/xml.pri)
-mac|darwin:LIBS += -framework ApplicationServices
+mac|darwin:LIBS_PRIVATE += -framework ApplicationServices
mac:lib_bundle:DEFINES += QT_NO_DEBUG_PLUGIN_CHECK
win32:DEFINES-=QT_NO_CAST_TO_ASCII
@@ -26,3 +28,11 @@ QMAKE_LIBS += $$QMAKE_LIBS_CORE
QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtCore.dynlist
contains(DEFINES,QT_EVAL):include(eval.pri)
+
+symbian: {
+ TARGET.UID3=0x2001B2DC
+
+ # Workaroud for problems with paging this dll
+ MMP_RULES -= PAGED
+ MMP_RULES *= UNPAGED
+} \ No newline at end of file
diff --git a/src/corelib/global/qendian.qdoc b/src/corelib/global/qendian.qdoc
new file mode 100644
index 0000000..39da689
--- /dev/null
+++ b/src/corelib/global/qendian.qdoc
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \headerfile <QtEndian>
+ \title Endian Conversion Functions
+ \ingroup funclists
+ \brief The <QtEndian> header provides functions to convert between
+ little and big endian representations of numbers.
+*/
+
+/*!
+ \fn T qFromBigEndian(const uchar *src)
+ \since 4.3
+ \relates <QtEndian>
+
+ Reads a big-endian number from memory location \a src and returns the number in the
+ host byte order representation.
+ On CPU architectures where the host byte order is little-endian (such as x86) this
+ will swap the byte order; otherwise it will just read from \a src.
+
+ \note Template type \c{T} can either be a qint16, qint32 or qint64. Other types of
+ integers, e.g., qlong, are not applicable.
+
+ There are no data alignment constraints for \a src.
+
+ \sa qFromLittleEndian()
+ \sa qToBigEndian()
+ \sa qToLittleEndian()
+*/
+/*!
+ \fn T qFromBigEndian(T src)
+ \since 4.3
+ \relates <QtEndian>
+ \overload
+
+ Converts \a src from big-endian byte order and returns the number in host byte order
+ representation of that number.
+ On CPU architectures where the host byte order is little-endian (such as x86) this
+ will return \a src with the byte order swapped; otherwise it will return \a src
+ unmodified.
+*/
+/*!
+ \fn T qFromLittleEndian(const uchar *src)
+ \since 4.3
+ \relates <QtEndian>
+
+ Reads a little-endian number from memory location \a src and returns the number in
+ the host byte order representation.
+ On CPU architectures where the host byte order is big-endian (such as PowerPC) this
+ will swap the byte order; otherwise it will just read from \a src.
+
+ \note Template type \c{T} can either be a qint16, qint32 or qint64. Other types of
+ integers, e.g., qlong, are not applicable.
+
+ There are no data alignment constraints for \a src.
+
+ \sa qFromBigEndian()
+ \sa qToBigEndian()
+ \sa qToLittleEndian()
+*/
+/*!
+ \fn T qFromLittleEndian(T src)
+ \since 4.3
+ \relates <QtEndian>
+ \overload
+
+ Converts \a src from little-endian byte order and returns the number in host byte
+ order representation of that number.
+ On CPU architectures where the host byte order is big-endian (such as PowerPC) this
+ will return \a src with the byte order swapped; otherwise it will return \a src
+ unmodified.
+*/
+/*!
+ \fn void qToBigEndian(T src, uchar *dest)
+ \since 4.3
+ \relates <QtEndian>
+
+ Writes the number \a src with template type \c{T} to the memory location at \a dest
+ in big-endian byte order.
+
+ Note that template type \c{T} can only be an integer data type (signed or unsigned).
+
+ There are no data alignment constraints for \a dest.
+
+ \sa qFromBigEndian()
+ \sa qFromLittleEndian()
+ \sa qToLittleEndian()
+*/
+/*!
+ \fn T qToBigEndian(T src)
+ \since 4.3
+ \relates <QtEndian>
+ \overload
+
+ Converts \a src from host byte order and returns the number in big-endian byte order
+ representation of that number.
+ On CPU architectures where the host byte order is little-endian (such as x86) this
+ will return \a src with the byte order swapped; otherwise it will return \a src
+ unmodified.
+*/
+/*!
+ \fn void qToLittleEndian(T src, uchar *dest)
+ \since 4.3
+ \relates <QtEndian>
+
+ Writes the number \a src with template type \c{T} to the memory location at \a dest
+ in little-endian byte order.
+
+ Note that template type \c{T} can only be an integer data type (signed or unsigned).
+
+ There are no data alignment constraints for \a dest.
+
+ \sa qFromBigEndian()
+ \sa qFromLittleEndian()
+ \sa qToBigEndian()
+*/
+/*!
+ \fn T qToLittleEndian(T src)
+ \since 4.3
+ \relates <QtEndian>
+ \overload
+
+ Converts \a src from host byte order and returns the number in little-endian byte
+ order representation of that number.
+ On CPU architectures where the host byte order is big-endian (such as PowerPC) this
+ will return \a src with the byte order swapped; otherwise it will return \a src
+ unmodified.
+*/
+
diff --git a/src/corelib/global/qfeatures.h b/src/corelib/global/qfeatures.h
index d8cdd79..b0478df 100644
--- a/src/corelib/global/qfeatures.h
+++ b/src/corelib/global/qfeatures.h
@@ -311,6 +311,11 @@
#define QT_NO_ACCESSIBILITY
#endif
+// Animation
+#if !defined(QT_NO_ANIMATION) && (defined(QT_NO_PROPERTIES))
+#define QT_NO_ANIMATION
+#endif
+
// QButtonGroup
#if !defined(QT_NO_BUTTONGROUP) && (defined(QT_NO_GROUPBOX))
#define QT_NO_BUTTONGROUP
@@ -361,6 +366,11 @@
#define QT_NO_MENU
#endif
+// QNetworkDiskCache
+#if !defined(QT_NO_NETWORKDISKCACHE) && (defined(QT_NO_TEMPORARYFILE))
+#define QT_NO_NETWORKDISKCACHE
+#endif
+
// Phonon::SeekSlider
#if !defined(QT_NO_PHONON_SEEKSLIDER) && (defined(QT_NO_SLIDER))
#define QT_NO_PHONON_SEEKSLIDER
diff --git a/src/corelib/global/qfeatures.txt b/src/corelib/global/qfeatures.txt
index 40ccb15..3a6c050 100644
--- a/src/corelib/global/qfeatures.txt
+++ b/src/corelib/global/qfeatures.txt
@@ -1085,6 +1085,13 @@ Requires:
Name: QNetworkInterface
SeeAlso: ???
+Feature: NETWORKDISKCACHE
+Description: Supports a disk cache for network resources
+Section: Networking
+Requires: TEMPORARYFILE
+Name: QNetworkDiskCache
+SeeAlso: ???
+
# Utilities
Feature: COMPLETER
@@ -1136,13 +1143,6 @@ Requires: UNDOSTACK LISTVIEW
Name: QUndoView
SeeAlso: ???
-Feature: SCRIPT
-Description: Provides support for the QtScript module
-Section: Utilities
-Requires: TEXTDATE DATESTRING PROPERTIES
-Name: QtScript
-SeeAlso: ???
-
Feature: ACCESSIBILITY
Description: Provides accessibility support.
Section: Utilities
@@ -1150,6 +1150,21 @@ Requires: PROPERTIES
Name: Accessibility
SeeAlso: ???
+Feature: ANIMATION
+Description: Provides a framework for animations.
+Section: Utilities
+Requires: PROPERTIES
+Name: Animation
+SeeAlso: ???
+
+Feature: STATEMACHINE
+Description: Provides hierarchical finite state machines.
+Section: Utilities
+Requires: PROPERTIES
+Name: State machine
+SeeAlso: ???
+
+
# SVG
Feature: SVG
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index a28cb9d..935c99b 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -44,6 +44,8 @@
#include "qvector.h"
#include "qlist.h"
#include "qthreadstorage.h"
+#include "qdir.h"
+#include "qstringlist.h"
#ifndef QT_NO_QOBJECT
#include <private/qthread_p.h>
@@ -62,10 +64,19 @@
# endif
#endif
-#ifdef Q_CC_MWERKS
+#if defined(Q_OS_VXWORKS)
+# include <envLib.h>
+#endif
+
+#if defined(Q_CC_MWERKS) && defined(Q_OS_MACX)
#include <CoreServices/CoreServices.h>
#endif
+#if defined(Q_OS_SYMBIAN)
+#include <e32def.h>
+#include <e32debug.h>
+#endif
+
QT_BEGIN_NAMESPACE
@@ -97,7 +108,7 @@ QT_BEGIN_NAMESPACE
\brief The QFlags class provides a type-safe way of storing
OR-combinations of enum values.
- \mainclass
+
\ingroup tools
The QFlags<Enum> class is a template class, where Enum is an enum
@@ -397,13 +408,13 @@ QT_BEGIN_NAMESPACE
/*!
\headerfile <QtGlobal>
\title Global Qt Declarations
- \ingroup architecture
+ \ingroup funclists
- \brief The <QtGlobal> header provides basic declarations and
- is included by all other Qt headers.
+ \brief The <QtGlobal> header file includes the fundamental global
+ declarations. It is included by most other Qt header files.
- The declarations include \l {types}, \l functions and
- \l macros.
+ The global declarations include \l{types}, \l{functions} and
+ \l{macros}.
The type definitions are partly convenience definitions for basic
types (some of which guarantee certain bit-sizes on all platforms
@@ -915,7 +926,7 @@ QT_BEGIN_NAMESPACE
\fn bool qt_winUnicode()
\relates <QtGlobal>
- Use QSysInfo::WindowsVersion and QSysInfo::WV_DOS_based instead.
+ This function always returns true.
\sa QSysInfo
*/
@@ -1049,6 +1060,20 @@ bool qSharedBuild()
*/
/*!
+ \fn QSysInfo::SymbianVersion QSysInfo::symbianVersion()
+
+ Returns the version of the Symbian operating system on which the
+ application is run (Symbian only).
+*/
+
+/*!
+ \fn QSysInfo::S60Version QSysInfo::s60Version()
+
+ Returns the version of the S60 SDK system on which the
+ application is run (S60 only).
+*/
+
+/*!
\enum QSysInfo::Endian
\value BigEndian Big-endian byte order (also called Network byte order)
@@ -1104,7 +1129,7 @@ bool qSharedBuild()
\value WV_NT_based NT-based version of Windows
\value WV_CE_based CE-based version of Windows
- \sa MacVersion
+ \sa MacVersion, SymbianVersion
*/
/*!
@@ -1133,7 +1158,39 @@ bool qSharedBuild()
\value MV_LEOPARD Apple codename for MV_10_5
\value MV_SNOWLEOPARD Apple codename for MV_10_6
- \sa WinVersion
+ \sa WinVersion, SymbianVersion
+*/
+
+/*!
+ \enum QSysInfo::SymbianVersion
+
+ This enum provides symbolic names for the various versions of the
+ Symbian operating system. On Symbian, the
+ QSysInfo::symbianVersion() function gives the version of the
+ system on which the application is run.
+
+ \value SV_9_2 Symbian OS v9.2
+ \value SV_9_3 Symbian OS v9.3
+ \value SV_9_4 Symbian OS v9.4
+ \value SV_Unknown An unknown and currently unsupported platform
+
+ \sa S60Version, WinVersion, MacVersion
+*/
+
+/*!
+ \enum QSysInfo::S60Version
+
+ This enum provides symbolic names for the various versions of the
+ S60 SDK. On S60, the
+ QSysInfo::s60Version() function gives the version of the
+ SDK on which the application is run.
+
+ \value SV_S60_3_1 S60 3rd Edition Feature Pack 1
+ \value SV_S60_3_2 S60 3rd Edition Feature Pack 2
+ \value SV_S60_5_0 S60 5th Edition
+ \value SV_S60_Unknown An unknown and currently unsupported platform
+
+ \sa SymbianVersion, WinVersion, MacVersion
*/
/*!
@@ -1344,14 +1401,7 @@ bool qSharedBuild()
\macro Q_OS_QNX
\relates <QtGlobal>
- Defined on QNX.
-*/
-
-/*!
- \macro Q_OS_QNX6
- \relates <QtGlobal>
-
- Defined on QNX RTP 6.1.
+ Defined on QNX Neutrino.
*/
/*!
@@ -1620,15 +1670,11 @@ QSysInfo::WinVersion QSysInfo::windowsVersion()
if (winver)
return winver;
winver = QSysInfo::WV_NT;
-#ifndef Q_OS_WINCE
- OSVERSIONINFOA osver;
- osver.dwOSVersionInfoSize = sizeof(osver);
- GetVersionExA(&osver);
-#else
- DWORD qt_cever = 0;
OSVERSIONINFOW osver;
osver.dwOSVersionInfoSize = sizeof(osver);
GetVersionEx(&osver);
+#ifdef Q_OS_WINCE
+ DWORD qt_cever = 0;
qt_cever = osver.dwMajorVersion * 100;
qt_cever += osver.dwMinorVersion * 10;
#endif
@@ -1672,7 +1718,7 @@ QSysInfo::WinVersion QSysInfo::windowsVersion()
winver = QSysInfo::WV_WINDOWS7;
} else {
qWarning("Qt: Untested Windows version %d.%d detected!",
- osver.dwMajorVersion, osver.dwMinorVersion);
+ int(osver.dwMajorVersion), int(osver.dwMinorVersion));
winver = QSysInfo::WV_NT_based;
}
}
@@ -1711,6 +1757,87 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion()
#endif
+#ifdef Q_OS_SYMBIAN
+# ifdef Q_WS_S60
+static QSysInfo::S60Version cachedS60Version = QSysInfo::S60Version(-1);
+
+QSysInfo::S60Version QSysInfo::s60Version()
+{
+# ifdef Q_CC_NOKIAX86
+ // For emulator builds. Emulators don't support the trick we use to figure
+ // out which SDK we are running under, so simply hardcode it there.
+# if defined(__SERIES60_31__)
+ return SV_S60_3_1;
+
+# elif defined(__S60_32__)
+ return SV_S60_3_2;
+
+# elif defined(__S60_50__)
+ return SV_S60_5_0;
+
+# else
+ return SV_S60_Unknown;
+
+# endif
+
+# else
+ // For hardware builds.
+ if (cachedS60Version != -1)
+ return cachedS60Version;
+
+ QDir dir(QLatin1String("z:\\system\\install"));
+ QStringList filters;
+ filters << QLatin1String("Series60v?.*.sis");
+ dir.setNameFilters(filters);
+
+ QStringList names = dir.entryList(QDir::NoFilter, QDir::Name | QDir::Reversed | QDir::IgnoreCase);
+ if (names.size() == 0)
+ return cachedS60Version = SV_S60_Unknown;
+
+ int major, minor;
+ major = names[0][9].toAscii() - '0';
+ minor = names[0][11].toAscii() - '0';
+ if (major == 3) {
+ if (minor == 1) {
+ return cachedS60Version = SV_S60_3_1;
+ } else if (minor == 2) {
+ return cachedS60Version = SV_S60_3_2;
+ }
+ } else if (major == 5) {
+ if (minor == 0) {
+ return cachedS60Version = SV_S60_5_0;
+ }
+ }
+
+ return cachedS60Version = SV_S60_Unknown;
+# endif
+}
+QSysInfo::SymbianVersion QSysInfo::symbianVersion()
+{
+ switch (s60Version()) {
+ case SV_S60_3_1:
+ return SV_9_2;
+ case SV_S60_3_2:
+ return SV_9_3;
+ case SV_S60_5_0:
+ return SV_9_4;
+ default:
+ return SV_Unknown;
+ }
+}
+#else
+QSysInfo::S60Version QSysInfo::s60Version()
+{
+ return SV_S60_None;
+}
+
+QSysInfo::SymbianVersion QSysInfo::symbianVersion()
+{
+ return SV_Unknown;
+}
+# endif // ifdef Q_WS_S60
+#endif // ifdef Q_OS_SYMBIAN
+
/*!
\macro void Q_ASSERT(bool test)
\relates <QtGlobal>
@@ -1776,6 +1903,15 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion()
*/
/*!
+ \fn T *q_check_ptr(T *pointer)
+ \relates <QtGlobal>
+
+ Users Q_CHECK_PTR on \a pointer, then returns \a pointer.
+
+ This can be used as an inline version of Q_CHECK_PTR.
+*/
+
+/*!
\macro const char* Q_FUNC_INFO()
\relates <QtGlobal>
@@ -1803,6 +1939,17 @@ void qt_check_pointer(const char *n, int l)
qWarning("In file %s, line %d: Out of memory", n, l);
}
+#ifndef QT_NO_EXCEPTIONS
+/* \internal
+ Allows you to throw an exception without including <new>
+ Called internally from Q_CHECK_PTR on certain OS combinations
+*/
+void qBadAlloc()
+{
+ QT_THROW(std::bad_alloc());
+}
+#endif
+
/*
The Q_ASSERT macro calls this function when the test fails.
*/
@@ -1860,7 +2007,7 @@ void *qMemSet(void *dest, int c, size_t n) { return memset(dest, c, n); }
static QtMsgHandler handler = 0; // pointer to debug handler
-#ifdef Q_CC_MWERKS
+#if defined(Q_CC_MWERKS) && defined(Q_OS_MACX)
extern bool qt_is_gui_used;
static void mac_default_handler(const char *msg)
{
@@ -1872,7 +2019,7 @@ static void mac_default_handler(const char *msg)
fprintf(stderr, msg);
}
}
-#endif // Q_CC_MWERKS
+#endif // Q_CC_MWERKS && Q_OS_MACX
@@ -1904,34 +2051,21 @@ QString qt_error_string(int errorCode)
break;
default: {
#ifdef Q_OS_WIN
- QT_WA({
- unsigned short *string = 0;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- errorCode,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR)&string,
- 0,
- NULL);
- ret = QString::fromUtf16(string);
- LocalFree((HLOCAL)string);
- }, {
- char *string = 0;
- FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- errorCode,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPSTR)&string,
- 0,
- NULL);
- ret = QString::fromLocal8Bit(string);
- LocalFree((HLOCAL)string);
- });
+ wchar_t *string = 0;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ errorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ string,
+ 0,
+ NULL);
+ ret = QString::fromWCharArray(string);
+ LocalFree((HLOCAL)string);
if (ret.isEmpty() && errorCode == ERROR_MOD_NOT_FOUND)
ret = QString::fromLatin1("The specified module could not be found.");
-#elif !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L && !defined(Q_OS_INTEGRITY)
+#elif !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX)
QByteArray buf(1024, '\0');
strerror_r(errorCode, buf.data(), buf.size());
@@ -1961,8 +2095,8 @@ QString qt_error_string(int errorCode)
warnings, critical and fatal error messages. The Qt library (debug
mode) contains hundreds of warning messages that are printed
when internal errors (usually invalid function arguments)
- occur. Qt built in release mode also contains such warnings unless
- QT_NO_WARNING_OUTPUT and/or QT_NO_DEBUG_OUTPUT have been set during
+ occur. Qt built in release mode also contains such warnings unless
+ QT_NO_WARNING_OUTPUT and/or QT_NO_DEBUG_OUTPUT have been set during
compilation. If you implement your own message handler, you get total
control of these messages.
@@ -2006,12 +2140,23 @@ void qt_message_output(QtMsgType msgType, const char *buf)
if (handler) {
(*handler)(msgType, buf);
} else {
-#if defined(Q_CC_MWERKS)
+#if defined(Q_CC_MWERKS) && defined(Q_OS_MACX)
mac_default_handler(buf);
#elif defined(Q_OS_WINCE)
QString fstr = QString::fromLatin1(buf);
- fstr += QLatin1String("\n");
+ fstr += QLatin1Char('\n');
OutputDebugString(reinterpret_cast<const wchar_t *> (fstr.utf16()));
+#elif defined(Q_OS_SYMBIAN)
+ // RDebug::Print has a cap of 256 characters so break it up
+ _LIT(format, "[Qt Message] %S");
+ const int maxBlockSize = 256 - ((const TDesC &)format).Length();
+ const TPtrC8 ptr(reinterpret_cast<const TUint8*>(buf));
+ HBufC* hbuffer = q_check_ptr(HBufC::New(qMin(maxBlockSize, ptr.Length())));
+ for (int i = 0; i < ptr.Length(); i += hbuffer->Length()) {
+ hbuffer->Des().Copy(ptr.Mid(i, qMin(maxBlockSize, ptr.Length()-i)));
+ RDebug::Print(format, hbuffer);
+ }
+ delete hbuffer;
#else
fprintf(stderr, "%s\n", buf);
fflush(stderr);
@@ -2038,7 +2183,15 @@ void qt_message_output(QtMsgType msgType, const char *buf)
_CrtDbgBreak();
#endif
-#if (defined(Q_OS_UNIX) || defined(Q_CC_MINGW))
+#if defined(Q_OS_SYMBIAN)
+ __DEBUGGER(); // on the emulator, get the debugger to kick in if there's one around
+ TBuf<256> tmp;
+ TPtrC8 ptr(reinterpret_cast<const TUint8*>(buf));
+ TInt len = Min(tmp.MaxLength(), ptr.Length());
+ tmp.Copy(ptr.Left(len));
+ // Panic the current thread. We don't use real panic codes, so 0 has no special meaning.
+ User::Panic(tmp, 0);
+#elif (defined(Q_OS_UNIX) || defined(Q_CC_MINGW))
abort(); // trap; generates core dump
#else
exit(1); // goodbye cruel world
@@ -2046,6 +2199,48 @@ void qt_message_output(QtMsgType msgType, const char *buf)
}
}
+#if !defined(QT_NO_EXCEPTIONS)
+/*!
+ \internal
+ Uses a local buffer to output the message. Not locale safe + cuts off
+ everything after character 255, but will work in out of memory situations.
+*/
+static void qEmergencyOut(QtMsgType msgType, const char *msg, va_list ap)
+{
+ char emergency_buf[256] = { '\0' };
+ emergency_buf[255] = '\0';
+ if (msg)
+ qvsnprintf(emergency_buf, 255, msg, ap);
+ qt_message_output(msgType, emergency_buf);
+}
+#endif
+
+/*!
+ \internal
+*/
+static void qt_message(QtMsgType msgType, const char *msg, va_list ap)
+{
+#if !defined(QT_NO_EXCEPTIONS)
+ if (std::uncaught_exception()) {
+ qEmergencyOut(msgType, msg, ap);
+ return;
+ }
+#endif
+ QByteArray buf;
+ if (msg) {
+ QT_TRY {
+ buf = QString().vsprintf(msg, ap).toLocal8Bit();
+ } QT_CATCH(const std::bad_alloc &) {
+#if !defined(QT_NO_EXCEPTIONS)
+ qEmergencyOut(msgType, msg, ap);
+ // don't rethrow - we use qWarning and friends in destructors.
+ return;
+#endif
+ }
+ }
+ qt_message_output(msgType, buf.constData());
+}
+
#undef qDebug
/*!
\relates <QtGlobal>
@@ -2083,14 +2278,10 @@ void qt_message_output(QtMsgType msgType, const char *buf)
*/
void qDebug(const char *msg, ...)
{
- QString buf;
va_list ap;
- va_start(ap, msg); // use variable arg list
- if (msg)
- buf.vsprintf(msg, ap);
+ va_start(ap, msg); // use variable arg list
+ qt_message(QtDebugMsg, msg, ap);
va_end(ap);
-
- qt_message_output(QtDebugMsg, buf.toLocal8Bit().constData());
}
#undef qWarning
@@ -2127,14 +2318,10 @@ void qDebug(const char *msg, ...)
*/
void qWarning(const char *msg, ...)
{
- QString buf;
va_list ap;
va_start(ap, msg); // use variable arg list
- if (msg)
- buf.vsprintf(msg, ap);
+ qt_message(QtWarningMsg, msg, ap);
va_end(ap);
-
- qt_message_output(QtWarningMsg, buf.toLocal8Bit().constData());
}
/*!
@@ -2167,15 +2354,12 @@ void qWarning(const char *msg, ...)
*/
void qCritical(const char *msg, ...)
{
- QString buf;
va_list ap;
va_start(ap, msg); // use variable arg list
- if (msg)
- buf.vsprintf(msg, ap);
+ qt_message(QtCriticalMsg, msg, ap);
va_end(ap);
-
- qt_message_output(QtCriticalMsg, buf.toLocal8Bit().constData());
}
+
#ifdef QT3_SUPPORT
void qSystemWarning(const char *msg, int code)
{ qCritical("%s (%s)", msg, qt_error_string(code).toLocal8Bit().constData()); }
@@ -2183,6 +2367,8 @@ void qSystemWarning(const char *msg, int code)
void qErrnoWarning(const char *msg, ...)
{
+ // qt_error_string() will allocate anyway, so we don't have
+ // to be careful here (like we do in plain qWarning())
QString buf;
va_list ap;
va_start(ap, msg);
@@ -2195,6 +2381,8 @@ void qErrnoWarning(const char *msg, ...)
void qErrnoWarning(int code, const char *msg, ...)
{
+ // qt_error_string() will allocate anyway, so we don't have
+ // to be careful here (like we do in plain qWarning())
QString buf;
va_list ap;
va_start(ap, msg);
@@ -2231,14 +2419,10 @@ void qErrnoWarning(int code, const char *msg, ...)
*/
void qFatal(const char *msg, ...)
{
- QString buf;
va_list ap;
va_start(ap, msg); // use variable arg list
- if (msg)
- buf.vsprintf(msg, ap);
+ qt_message(QtFatalMsg, msg, ap);
va_end(ap);
-
- qt_message_output(QtFatalMsg, buf.toLocal8Bit().constData());
}
// getenv is declared as deprecated in VS2005. This function
@@ -2268,13 +2452,17 @@ bool qputenv(const char *varName, const QByteArray& value)
return _putenv_s(varName, value.constData()) == 0;
#else
QByteArray buffer(varName);
- buffer += "=";
+ buffer += '=';
buffer += value;
- return putenv(qstrdup(buffer.constData())) == 0;
+ char* envVar = qstrdup(buffer.constData());
+ int result = putenv(envVar);
+ if (result != 0) // error. we have to delete the string.
+ delete[] envVar;
+ return result == 0;
#endif
}
-#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD)
+#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && !defined(Q_OS_SYMBIAN)
# if defined(Q_OS_INTEGRITY) && defined(__GHS_VERSION_NUMBER) && (__GHS_VERSION_NUMBER < 500)
// older versions of INTEGRITY used a long instead of a uint for the seed.
@@ -2307,7 +2495,7 @@ Q_GLOBAL_STATIC(SeedStorage, randTLS) // Thread Local Storage for seed value
*/
void qsrand(uint seed)
{
-#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD)
+#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && !defined(Q_OS_SYMBIAN)
SeedStorageType *pseed = randTLS()->localData();
if (!pseed)
randTLS()->setLocalData(pseed = new SeedStorageType);
@@ -2336,7 +2524,7 @@ void qsrand(uint seed)
*/
int qrand()
{
-#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD)
+#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && !defined(Q_OS_SYMBIAN)
SeedStorageType *pseed = randTLS()->localData();
if (!pseed) {
randTLS()->setLocalData(pseed = new SeedStorageType);
@@ -2476,6 +2664,62 @@ int qrand()
*/
/*!
+ \fn QString qtTrId(const char *id, int n = -1)
+ \relates <QtGlobal>
+ \reentrant
+ \since 4.6
+
+ Returns a translated string identified by \a id.
+ If no matching string is found, the id itself is returned. This
+ should not happen under normal conditions.
+
+ 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.
+
+ Meta data and comments can be passed as documented for QObject::tr().
+ In addition, it is possible to supply a source string template like that:
+
+ \tt{//% <C string>}
+
+ or
+
+ \tt{\begincomment% <C string> \endcomment}
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp qttrid
+
+ Creating QM files suitable for use with this function requires passing
+ the \c -idbased option to the \c lrelease tool.
+
+ \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 QObject::tr(), QCoreApplication::translate(), {Internationalization with Qt}
+*/
+
+/*!
+ \macro QT_TRID_NOOP(id)
+ \relates <QtGlobal>
+ \since 4.6
+
+ Marks \a id for dynamic translation.
+ The only purpose of this macro is to provide an anchor for attaching
+ meta data like to qtTrId().
+
+ The macro expands to \a id.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp qttrid_noop
+
+ \sa qtTrId(), {Internationalization with Qt}
+*/
+
+/*!
\macro QT_POINTER_SIZE
\relates <QtGlobal>
@@ -2970,7 +3214,7 @@ bool QInternal::callFunction(InternalFunction func, void **args)
Compares the floating point value \a p1 and \a p2 and
returns \c true if they are considered equal, otherwise \c false.
- Note that comparing values where either \a p1 or \a p2 is 0.0 will not work.
+ Note that comparing values where either \a p1 or \a p2 is 0.0 will not work.
The solution to this is to compare against values greater than or equal to 1.0.
\snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 46
@@ -2984,7 +3228,12 @@ bool QInternal::callFunction(InternalFunction func, void **args)
\relates <QtGlobal>
\since 4.4
\threadsafe
- \overload
+
+ Compares the floating point value \a p1 and \a p2 and
+ returns \c true if they are considered equal, otherwise \c false.
+
+ The two numbers are compared in a relative way, where the
+ exactness is stronger the smaller the numbers are.
*/
/*!
@@ -3026,4 +3275,185 @@ bool QInternal::callFunction(InternalFunction func, void **args)
\sa Q_DECL_EXPORT
*/
+#if defined(Q_OS_SYMBIAN)
+
+#include <typeinfo>
+
+/*! \macro QT_TRAP_THROWING(function)
+ \relates <QtGlobal>
+ \ingroup qts60
+
+ TRAP leaves from Symbian \a function and throws an appropriate
+ standard C++ exception instead.
+ This must be used when calling Symbian OS leaving functions
+ from inside Qt or standard C++ code, so that the code can respond
+ correctly to the exception.
+
+ \warning This macro is only available on Symbian.
+
+ Example:
+
+ \code
+ // A Symbian leaving function is being called within a Qt function.
+ // Any leave must be converted to an exception
+ CAknTitlePane* titlePane = S60->titlePane();
+ if (titlePane) {
+ TPtrC captionPtr(qt_QString2TPtrC(caption));
+ QT_TRAP_THROWING(titlePane->SetTextL(captionPtr));
+ }
+ \endcode
+
+ \sa QT_TRYCATCH_ERROR(), QT_TRYCATCH_LEAVING()
+*/
+
+/*! \macro QT_TRYCATCH_ERROR(error, function)
+ \relates <QtGlobal>
+ \ingroup qts60
+
+ Catch standard C++ exceptions from a \a function and convert them to a Symbian OS
+ \a error code, or \c KErrNone if there is no exception.
+ This must be used inside Qt or standard C++ code when using exception throwing
+ code (practically anything) and returning an error code to Symbian OS.
+
+ \warning This macro is only available on Symbian.
+
+ Example:
+
+ \code
+ // An exception might be thrown in this Symbian TInt error returning function.
+ // It is caught and translated to an error code
+ TInt QServerApp::Connect(const QString &serverName)
+ {
+ TPtrC name;
+ TInt err;
+ QT_TRYCATCH_ERROR(err, name.Set(qt_QString2TPtrC(serverName)));
+ if (err != KErrNone)
+ return err;
+ return iServer.Connect(name);
+ }
+ \endcode
+}
+
+ \sa QT_TRYCATCH_LEAVING(), QT_TRAP_THROWING()
+*/
+
+/*! \macro QT_TRYCATCH_LEAVING(function)
+ \relates <QtGlobal>
+ \ingroup qts60
+
+ Catch standard C++ exceptions from \a function and convert them to Symbian OS
+ leaves. This must be used inside Qt or standard C++ code when using exception
+ throwing code (practically anything) and returning to Symbian OS from a leaving function.
+ For example inside a Symbian active object's \c RunL function implemented with Qt code.
+
+ \warning This macro is only available on Symbian.
+
+ Example:
+
+ \code
+ // This active object signals Qt code
+ // Exceptions from the Qt code must be converted to Symbian OS leaves for the active scheduler
+ void QWakeUpActiveObject::RunL()
+ {
+ iStatus = KRequestPending;
+ SetActive();
+ QT_TRYCATCH_LEAVING(m_dispatcher->wakeUpWasCalled());
+ }
+ \endcode
+
+ \sa QT_TRAP_THROWING(), QT_TRYCATCH_ERROR()
+*/
+
+#include <stdexcept>
+
+class QSymbianLeaveException : public std::exception
+{
+public:
+ inline QSymbianLeaveException(int err) : error(err) {}
+ inline const char* what() const throw() { return "Symbian leave exception"; }
+
+public:
+ int error;
+};
+
+/*! \relates <QtGlobal>
+ \ingroup qts60
+
+ Throws an exception if the \a error parameter is a symbian error code.
+ This is the exception throwing equivalent of Symbian's User::LeaveIfError.
+
+ \warning This function is only available on Symbian.
+
+ \sa qt_symbian_exception2LeaveL(), qt_symbian_exception2Error()
+*/
+void qt_symbian_throwIfError(int error)
+{
+ if (error >= KErrNone)
+ return; // do nothing - not an exception
+ switch (error) {
+ case KErrNoMemory:
+ throw std::bad_alloc();
+ case KErrArgument:
+ throw std::invalid_argument("from Symbian error");
+ case KErrOverflow:
+ throw std::overflow_error("from Symbian error");
+ case KErrUnderflow:
+ throw std::underflow_error("from Symbian error");
+ default:
+ throw QSymbianLeaveException(error);
+ }
+}
+
+/*! \relates <QtGlobal>
+ \ingroup qts60
+
+ Convert a caught standard C++ exception \a aThrow to a Symbian leave
+
+ \warning This function is only available on Symbian.
+
+ \sa qt_symbian_throwIfError(), qt_symbian_exception2Error()
+*/
+void qt_symbian_exception2LeaveL(const std::exception& aThrow)
+{
+ User::Leave(qt_symbian_exception2Error(aThrow));
+}
+
+/*! \relates <QtGlobal>
+ \ingroup qts60
+
+ Convert a caught standard C++ exception \a aThrow to a Symbian error code
+
+ \warning This function is only available on Symbian.
+
+ \sa qt_symbian_throwIfError(), qt_symbian_exception2LeaveL()
+*/
+int qt_symbian_exception2Error(const std::exception& aThrow)
+{
+ const std::type_info& atype = typeid(aThrow);
+ int err = KErrGeneral;
+
+ if(atype == typeid (std::bad_alloc))
+ err = KErrNoMemory;
+ else if(atype == typeid(QSymbianLeaveException))
+ err = static_cast<const QSymbianLeaveException&>(aThrow).error;
+ else {
+ if(atype == typeid(std::invalid_argument))
+ err = KErrArgument;
+ else if(atype == typeid(std::out_of_range))
+ // std::out_of_range is of type logic_error which by definition means that it is
+ // "presumably detectable before the program executes".
+ // std::out_of_range is used to report an argument is not within the expected range.
+ // The description of KErrArgument says an argument is out of range. Hence the mapping.
+ err = KErrArgument;
+ else if(atype == typeid(std::overflow_error))
+ err = KErrOverflow;
+ else if(atype == typeid(std::underflow_error))
+ err = KErrUnderflow;
+ qWarning("translation from std exception \"%s\" to %d", aThrow.what(), err);
+ }
+
+ return err;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index c6629fc..c34fc31 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -44,11 +44,11 @@
#include <stddef.h>
-#define QT_VERSION_STR "4.5.3"
+#define QT_VERSION_STR "4.6.0"
/*
QT_VERSION is (major << 16) + (minor << 8) + patch.
*/
-#define QT_VERSION 0x040503
+#define QT_VERSION 0x040600
/*
can be used like #if (QT_VERSION >= QT_VERSION_CHECK(4, 4, 0))
*/
@@ -110,7 +110,7 @@ namespace QT_NAMESPACE {}
This expands to a "using QT_NAMESPACE" also in _header files_.
It is the only way the feature can be used without too much
pain, but if people _really_ do not want it they can add
- DEFINES += QT_NO_USING_NAMESPACE to theur .pro files.
+ DEFINES += QT_NO_USING_NAMESPACE to their .pro files.
*/
QT_USE_NAMESPACE
# endif
@@ -144,10 +144,11 @@ namespace QT_NAMESPACE {}
The operating system, must be one of: (Q_OS_x)
DARWIN - Darwin OS (synonym for Q_OS_MAC)
+ SYMBIAN - Symbian
MSDOS - MS-DOS and Windows
OS2 - OS/2
OS2EMX - XFree86 on OS/2 (not PM)
- WIN32 - Win32 (Windows 95/98/ME and Windows NT/2000/XP)
+ WIN32 - Win32 (Windows 2000/XP/Vista/7 and Windows Server 2003/2008)
WINCE - WinCE (Windows CE 5.0)
CYGWIN - Cygwin
SOLARIS - Sun Solaris
@@ -182,6 +183,10 @@ namespace QT_NAMESPACE {}
# else
# define Q_OS_DARWIN32
# endif
+#elif defined(__SYMBIAN32__) || defined(SYMBIAN)
+# define Q_OS_SYMBIAN
+# define Q_NO_POSIX_SIGNALS
+# define QT_NO_GETIFADDRS
#elif defined(__CYGWIN__)
# define Q_OS_CYGWIN
#elif defined(MSDOS) || defined(_MSDOS)
@@ -238,8 +243,6 @@ namespace QT_NAMESPACE {}
#elif defined(__DGUX__)
# define Q_OS_DGUX
#elif defined(__QNXNTO__)
-# define Q_OS_QNX6
-#elif defined(__QNX__)
# define Q_OS_QNX
#elif defined(_SEQUENT_)
# define Q_OS_DYNIX
@@ -251,6 +254,8 @@ namespace QT_NAMESPACE {}
# define Q_OS_UNIXWARE
#elif defined(__INTEGRITY)
# define Q_OS_INTEGRITY
+#elif defined(VXWORKS) /* there is no "real" VxWorks define - this has to be set in the mkspec! */
+# define Q_OS_VXWORKS
#elif defined(__MAKEDEPEND__)
#else
# error "Qt has not been ported to this OS - talk to qt-bugs@trolltech.com"
@@ -297,7 +302,7 @@ namespace QT_NAMESPACE {}
# ifdef MAC_OS_X_VERSION_MIN_REQUIRED
# undef MAC_OS_X_VERSION_MIN_REQUIRED
# endif
-# define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_3
+# define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_4
# include <AvailabilityMacros.h>
# if !defined(MAC_OS_X_VERSION_10_3)
# define MAC_OS_X_VERSION_10_3 MAC_OS_X_VERSION_10_2 + 1
@@ -311,18 +316,11 @@ namespace QT_NAMESPACE {}
# if !defined(MAC_OS_X_VERSION_10_6)
# define MAC_OS_X_VERSION_10_6 MAC_OS_X_VERSION_10_5 + 1
# endif
-# if (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_6)
-# warning "Support for this version of Mac OS X is still preliminary"
-# endif
# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_6)
-# error "This version of Mac OS X is unsupported"
+# warning "This version of Mac OS X is unsupported"
# endif
#endif
-#ifdef QT_MAC_USE_COCOA
-#define QT_MAC_NO_QUICKDRAW 1
-#endif
-
#ifdef __LSB_VERSION__
# if __LSB_VERSION__ < 40
# error "This version of the Linux Standard Base is unsupported"
@@ -355,7 +353,9 @@ namespace QT_NAMESPACE {}
HIGHC - MetaWare High C/C++
PGI - Portland Group C++
GHS - Green Hills Optimizing C++ Compilers
+ GCCE - GCCE (Symbian GCCE builds)
RVCT - ARM Realview Compiler Suite
+ NOKIAX86 - Nokia x86 (Symbian WINSCW builds)
Should be sorted most to least authoritative.
@@ -376,6 +376,9 @@ namespace QT_NAMESPACE {}
#elif defined(__MWERKS__)
# define Q_CC_MWERKS
+# if defined(__EMU_SYMBIAN_OS__)
+# define Q_CC_NOKIAX86
+# endif
/* "explicit" recognized since 4.0d1 */
#elif defined(_MSC_VER)
@@ -385,6 +388,9 @@ namespace QT_NAMESPACE {}
# define Q_OUTOFLINE_TEMPLATE inline
# define Q_NO_TEMPLATE_FRIENDS
# define QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION
+# define Q_ALIGNOF(type) __alignof(type)
+# define Q_DECL_ALIGN(n) __declspec(align(n))
+
/* Visual C++.Net issues for _MSC_VER >= 1300 */
# if _MSC_VER >= 1300
# define Q_CC_MSVC_NET
@@ -426,27 +432,16 @@ namespace QT_NAMESPACE {}
#elif defined(__WATCOMC__)
# define Q_CC_WAT
-# if defined(Q_OS_QNX4)
-/* compiler flags */
-# define Q_TYPENAME
-# define Q_NO_BOOL_TYPE
-# define Q_CANNOT_DELETE_CONSTANT
-# define mutable
-/* ??? */
-# define Q_BROKEN_TEMPLATE_SPECIALIZATION
-/* no template classes in QVariant */
-# define QT_NO_TEMPLATE_VARIANT
-/* Wcc does not fill in functions needed by valuelists, maps, and
- valuestacks implicitly */
-# define Q_FULL_TEMPLATE_INSTANTIATION
-/* can we just compare the structures? */
-# define Q_FULL_TEMPLATE_INSTANTIATION_MEMCMP
-/* these are not useful to our customers */
-# define QT_NO_QWS_MULTIPROCESS
-# define QT_NO_QWS_CURSOR
-# endif
-#elif defined(__CC_ARM)
+/* Symbian GCCE */
+#elif defined(__GCCE__)
+# define Q_CC_GCCE
+# define QT_VISIBILITY_AVAILABLE
+
+/* ARM Realview Compiler Suite
+ RVCT compiler also defines __EDG__ and __GNUC__ (if --gnu flag is given),
+ so check for it before that */
+#elif defined(__ARMCC__) || defined(__CC_ARM)
# define Q_CC_RVCT
#elif defined(__GNUC__)
@@ -471,6 +466,11 @@ namespace QT_NAMESPACE {}
# define Q_NO_USING_KEYWORD
# define QT_NO_STL_WCHAR
# endif
+# if __GNUC__ >= 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+# define Q_ALIGNOF(type) __alignof__(type)
+# define Q_TYPEOF(expr) __typeof__(expr)
+# define Q_DECL_ALIGN(n) __attribute__((__aligned__(n)))
+# endif
/* GCC 3.1 and GCC 3.2 wrongly define _SB_CTYPE_MACROS on HP-UX */
# if defined(Q_OS_HPUX) && __GNUC__ == 3 && __GNUC_MINOR__ >= 1
# define Q_WRONG_SB_CTYPE_MACROS
@@ -524,6 +524,11 @@ namespace QT_NAMESPACE {}
# define Q_OUTOFLINE_TEMPLATE inline
# define Q_BROKEN_TEMPLATE_SPECIALIZATION
# define Q_CANNOT_DELETE_CONSTANT
+# elif __xlC__ >= 0x0600
+# define Q_ALIGNOF(type) __alignof__(type)
+# define Q_TYPEOF(expr) __typeof__(expr)
+# define Q_DECL_ALIGN(n) __attribute__((__aligned__(n)))
+# define Q_PACKED __attribute__((__packed__))
# endif
/* Older versions of DEC C++ do not define __EDG__ or __EDG - observed
@@ -602,6 +607,13 @@ namespace QT_NAMESPACE {}
# elif defined(__ghs)
# define Q_CC_GHS
+# elif defined(__DCC__)
+# define Q_CC_DIAB
+# undef Q_NO_BOOL_TYPE
+# if !defined(__bool)
+# define Q_NO_BOOL_TYPE
+# endif
+
/* The UnixWare 7 UDK compiler is based on EDG and does define __EDG__ */
# elif defined(__USLC__) && defined(__SCO_VERSION__)
# define Q_CC_USLC
@@ -633,6 +645,11 @@ namespace QT_NAMESPACE {}
# endif
# endif
+/* VxWorks' DIAB toolchain has an additional EDG type C++ compiler
+ (see __DCC__ above). This one is for C mode files (__EDG is not defined) */
+#elif defined(_DIAB_TOOL)
+# define Q_CC_DIAB
+
/* Never tested! */
#elif defined(__HIGHC__)
# define Q_CC_HIGHC
@@ -644,8 +661,17 @@ namespace QT_NAMESPACE {}
in which case _BOOL is not defined
this is the default in 4.2 compatibility mode triggered by -compat=4 */
# if __SUNPRO_CC >= 0x500
-# if __SUNPRO_CC < 0x570
-# define QT_NO_TEMPLATE_TEMPLATE_PARAMETERS
+# define QT_NO_TEMPLATE_TEMPLATE_PARAMETERS
+ /* see http://developers.sun.com/sunstudio/support/Ccompare.html */
+# if __SUNPRO_CC >= 0x590
+# define Q_ALIGNOF(type) __alignof__(type)
+# define Q_TYPEOF(expr) __typeof__(expr)
+# define Q_DECL_ALIGN(n) __attribute__((__aligned__(n)))
+// using CC 5.9: Warning: attribute visibility is unsupported and will be skipped..
+//# define Q_DECL_EXPORT __attribute__((__visibility__("default")))
+# endif
+# if __SUNPRO_CC < 0x5a0
+# define Q_NO_TEMPLATE_FRIENDS
# endif
# if !defined(_BOOL)
# define Q_NO_BOOL_TYPE
@@ -676,8 +702,17 @@ namespace QT_NAMESPACE {}
# if defined(__HP_aCC) || __cplusplus >= 199707L
# define Q_NO_TEMPLATE_FRIENDS
# define Q_CC_HPACC
-# ifdef QT_ARCH_PARISC
+# if __HP_aCC-0 < 060000
# define QT_NO_TEMPLATE_TEMPLATE_PARAMETERS
+# define Q_DECL_EXPORT __declspec(dllexport)
+# define Q_DECL_IMPORT __declspec(dllimport)
+# endif
+# if __HP_aCC-0 >= 061200
+# define Q_DECL_ALIGNED(n) __attribute__((aligned(n)))
+# endif
+# if __HP_aCC-0 >= 062000
+# define Q_DECL_EXPORT __attribute__((visibility("default")))
+# define Q_DECL_IMPORT Q_DECL_EXPORT
# endif
# else
# define Q_CC_HP
@@ -688,6 +723,10 @@ namespace QT_NAMESPACE {}
# endif
# define Q_NO_USING_KEYWORD /* ### check "using" status */
+#elif defined(__WINSCW__) && !defined(Q_CC_NOKIAX86)
+# define Q_CC_NOKIAX86
+
+
#else
# error "Qt has not been tested with this compiler - talk to qt-bugs@trolltech.com"
#endif
@@ -735,6 +774,7 @@ namespace QT_NAMESPACE {}
QWS - Qt for Embedded Linux
WIN32 - Windows
X11 - X Window System
+ S60 - Symbian S60
PM - unsupported
WIN16 - unsupported
*/
@@ -751,6 +791,10 @@ namespace QT_NAMESPACE {}
# endif
#elif defined(Q_OS_WINCE)
# define Q_WS_WIN32
+# define Q_WS_WINCE
+# if defined(Q_OS_WINCE_WM)
+# define Q_WS_WINCE_WM
+# endif
#elif defined(Q_OS_OS2)
# define Q_WS_PM
# error "Qt does not work with OS/2 Presentation Manager or Workplace Shell"
@@ -763,15 +807,20 @@ namespace QT_NAMESPACE {}
# elif defined(Q_OS_MAC32)
# define Q_WS_MAC32
# endif
+# elif defined(Q_OS_SYMBIAN)
+# if (defined(__SERIES60_31__) || defined(__S60_32__) || defined(__S60_50__)) && !defined(QT_NO_S60)
+# define Q_WS_S60
+# endif
# elif !defined(Q_WS_QWS)
# define Q_WS_X11
# endif
#endif
-#if defined(Q_WS_WIN16) || defined(Q_WS_WIN32)
+#if defined(Q_WS_WIN16) || defined(Q_WS_WIN32) || defined(Q_WS_WINCE)
# define Q_WS_WIN
#endif
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -787,7 +836,7 @@ typedef short qint16; /* 16 bit signed */
typedef unsigned short quint16; /* 16 bit unsigned */
typedef int qint32; /* 32 bit signed */
typedef unsigned int quint32; /* 32 bit unsigned */
-#if defined(Q_OS_WIN) && !defined(Q_CC_GNU)
+#if defined(Q_OS_WIN) && !defined(Q_CC_GNU) && !defined(Q_CC_MWERKS)
# define Q_INT64_C(c) c ## i64 /* signed 64 bit constant */
# define Q_UINT64_C(c) c ## ui64 /* unsigned 64 bit constant */
typedef __int64 qint64; /* 64 bit signed */
@@ -805,7 +854,7 @@ typedef quint64 qulonglong;
#ifndef QT_POINTER_SIZE
# if defined(Q_OS_WIN64)
# define QT_POINTER_SIZE 8
-# elif defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+# elif defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
# define QT_POINTER_SIZE 4
# endif
#endif
@@ -825,17 +874,14 @@ typedef quint64 qulonglong;
sizeof(void *) == sizeof(quintptr)
&& sizeof(void *) == sizeof(qptrdiff)
*/
-template <int> class QUintForSize { private: typedef void Type; };
-template <> class QUintForSize<4> { public: typedef quint32 Type; };
-template <> class QUintForSize<8> { public: typedef quint64 Type; };
-template <typename T> class QUintForType : public QUintForSize<sizeof(T)> { };
-typedef QUintForType<void *>::Type quintptr;
-
-template <int> class QIntForSize { private: typedef void Type; };
-template <> class QIntForSize<4> { public: typedef qint32 Type; };
-template <> class QIntForSize<8> { public: typedef qint64 Type; };
-template <typename T> class QIntForType : public QIntForSize<sizeof(T)> { };
-typedef QIntForType<void *>::Type qptrdiff;
+template <int> struct QIntegerForSize;
+template <> struct QIntegerForSize<1> { typedef quint8 Unsigned; typedef qint8 Signed; };
+template <> struct QIntegerForSize<2> { typedef quint16 Unsigned; typedef qint16 Signed; };
+template <> struct QIntegerForSize<4> { typedef quint32 Unsigned; typedef qint32 Signed; };
+template <> struct QIntegerForSize<8> { typedef quint64 Unsigned; typedef qint64 Signed; };
+template <class T> struct QIntegerForSizeof: QIntegerForSize<sizeof(T)> { };
+typedef QIntegerForSizeof<void*>::Unsigned quintptr;
+typedef QIntegerForSizeof<void*>::Signed qptrdiff;
/*
Useful type definitions for Qt
@@ -857,6 +903,12 @@ QT_END_INCLUDE_NAMESPACE
*/
#ifndef QT_LINUXBASE /* the LSB defines TRUE and FALSE for us */
+/* Symbian OS defines TRUE = 1 and FALSE = 0,
+redefine to built-in booleans to make autotests work properly */
+#ifdef Q_OS_SYMBIAN
+ #undef TRUE
+ #undef FALSE
+#endif
# ifndef TRUE
# define TRUE true
# define FALSE false
@@ -1008,9 +1060,10 @@ typedef int QNoImplicitBoolCast;
#define QT_NO_FPU
#endif
+// This logic must match the one in qmetatype.h
#if defined(QT_COORD_TYPE)
typedef QT_COORD_TYPE qreal;
-#elif defined(QT_NO_FPU) || defined(QT_ARCH_ARM) || defined(QT_ARCH_WINDOWSCE)
+#elif defined(QT_NO_FPU) || defined(QT_ARCH_ARM) || defined(QT_ARCH_WINDOWSCE) || defined(QT_ARCH_SYMBIAN)
typedef float qreal;
#else
typedef double qreal;
@@ -1026,8 +1079,13 @@ inline T qAbs(const T &t) { return t >= 0 ? t : -t; }
inline int qRound(qreal d)
{ return d >= 0.0 ? int(d + 0.5) : int(d - int(d-1) + 0.5) + int(d-1); }
+#if defined(QT_NO_FPU) || defined(QT_ARCH_ARM) || defined(QT_ARCH_WINDOWSCE) || defined(QT_ARCH_SYMBIAN)
+inline qint64 qRound64(double d)
+{ return d >= 0.0 ? qint64(d + 0.5) : qint64(d - qint64(d-1) + 0.5) + qint64(d-1); }
+#else
inline qint64 qRound64(qreal d)
{ return d >= 0.0 ? qint64(d + 0.5) : qint64(d - qint64(d-1) + 0.5) + qint64(d-1); }
+#endif
template <typename T>
inline const T &qMin(const T &a, const T &b) { if (a < b) return a; return b; }
@@ -1082,12 +1140,21 @@ class QDataStream;
# define QT_NO_COP
#endif
+#if defined(Q_OS_VXWORKS)
+# define QT_NO_CRASHHANDLER // no popen
+# define QT_NO_PROCESS // no exec*, no fork
+# define QT_NO_LPR
+# define QT_NO_SHAREDMEMORY // only POSIX, no SysV and in the end...
+# define QT_NO_SYSTEMSEMAPHORE // not needed at all in a flat address space
+# define QT_NO_QWS_MULTIPROCESS // no processes
+#endif
+
# include <QtCore/qfeatures.h>
#define QT_SUPPORTS(FEATURE) (!defined(QT_NO_##FEATURE))
#ifndef Q_DECL_EXPORT
-# ifdef Q_OS_WIN
+# if defined(Q_OS_WIN) || defined(Q_CC_NOKIAX86) || defined(Q_CC_RVCT)
# define Q_DECL_EXPORT __declspec(dllexport)
# elif defined(QT_VISIBILITY_AVAILABLE)
# define Q_DECL_EXPORT __attribute__((visibility("default")))
@@ -1097,7 +1164,7 @@ class QDataStream;
# endif
#endif
#ifndef Q_DECL_IMPORT
-# if defined(Q_OS_WIN)
+# if defined(Q_OS_WIN) || defined(Q_CC_NOKIAX86) || defined(Q_CC_RVCT)
# define Q_DECL_IMPORT __declspec(dllimport)
# else
# define Q_DECL_IMPORT
@@ -1105,10 +1172,10 @@ class QDataStream;
#endif
/*
- Create Qt DLL if QT_DLL is defined (Windows only)
+ Create Qt DLL if QT_DLL is defined (Windows and Symbian only)
*/
-#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
# if defined(QT_NODLL)
# undef QT_MAKEDLL
# undef QT_DLL
@@ -1146,6 +1213,16 @@ class QDataStream;
# else
# define Q_OPENGL_EXPORT Q_DECL_IMPORT
# endif
+# if defined(QT_BUILD_MULTIMEDIA_LIB)
+# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT
+# else
+# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT
+# endif
+# if defined(QT_BUILD_OPENVG_LIB)
+# define Q_OPENVG_EXPORT Q_DECL_EXPORT
+# else
+# define Q_OPENVG_EXPORT Q_DECL_IMPORT
+# endif
# if defined(QT_BUILD_XML_LIB)
# define Q_XML_EXPORT Q_DECL_EXPORT
# else
@@ -1185,6 +1262,8 @@ class QDataStream;
# define Q_SVG_EXPORT Q_DECL_IMPORT
# define Q_CANVAS_EXPORT Q_DECL_IMPORT
# define Q_OPENGL_EXPORT Q_DECL_IMPORT
+# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT
+# define Q_OPENVG_EXPORT Q_DECL_IMPORT
# define Q_XML_EXPORT Q_DECL_IMPORT
# define Q_XMLPATTERNS_EXPORT Q_DECL_IMPORT
# define Q_SCRIPT_EXPORT Q_DECL_IMPORT
@@ -1210,6 +1289,8 @@ class QDataStream;
# define Q_NETWORK_EXPORT Q_DECL_EXPORT
# define Q_SVG_EXPORT Q_DECL_EXPORT
# define Q_OPENGL_EXPORT Q_DECL_EXPORT
+# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT
+# define Q_OPENVG_EXPORT Q_DECL_EXPORT
# define Q_XML_EXPORT Q_DECL_EXPORT
# define Q_XMLPATTERNS_EXPORT Q_DECL_EXPORT
# define Q_SCRIPT_EXPORT Q_DECL_EXPORT
@@ -1222,6 +1303,7 @@ class QDataStream;
# define Q_NETWORK_EXPORT
# define Q_SVG_EXPORT
# define Q_OPENGL_EXPORT
+# define Q_MULTIMEDIA_EXPORT
# define Q_XML_EXPORT
# define Q_XMLPATTERNS_EXPORT
# define Q_SCRIPT_EXPORT
@@ -1243,6 +1325,12 @@ class QDataStream;
# else
# define Q_GUI_EXPORT_INLINE inline
# endif
+#elif defined(Q_CC_RVCT)
+// we force RVCT not to export inlines by passing --visibility_inlines_hidden
+// so we need to just inline it, rather than exporting and inlining
+// note: this affects the contents of the DEF files (ie. these functions do not appear)
+# define Q_CORE_EXPORT_INLINE inline
+# define Q_GUI_EXPORT_INLINE inline
#else
# define Q_CORE_EXPORT_INLINE Q_CORE_EXPORT inline
# define Q_GUI_EXPORT_INLINE Q_GUI_EXPORT inline
@@ -1253,16 +1341,42 @@ class QDataStream;
for Qt's internal unit tests. If you want slower loading times and more
symbols that can vanish from version to version, feel free to define QT_BUILD_INTERNAL.
*/
-#if defined(QT_BUILD_INTERNAL) && defined(Q_OS_WIN) && defined(QT_MAKEDLL)
+#if defined(QT_BUILD_INTERNAL) && (defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_MAKEDLL)
# define Q_AUTOTEST_EXPORT Q_DECL_EXPORT
-#elif defined(QT_BUILD_INTERNAL) && defined(Q_OS_WIN) && defined(QT_DLL)
+#elif defined(QT_BUILD_INTERNAL) && (defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_DLL)
# define Q_AUTOTEST_EXPORT Q_DECL_IMPORT
-#elif defined(QT_BUILD_INTERNAL) && !defined(Q_OS_WIN) && defined(QT_SHARED)
+#elif defined(QT_BUILD_INTERNAL) && !(defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_SHARED)
# define Q_AUTOTEST_EXPORT Q_DECL_EXPORT
#else
# define Q_AUTOTEST_EXPORT
#endif
+inline void qt_noop() {}
+
+/* These wrap try/catch so we can switch off exceptions later.
+
+ Beware - do not use more than one QT_CATCH per QT_TRY, and do not use
+ the exception instance in the catch block.
+ If you can't live with those constraints, don't use these macros.
+ Use the QT_NO_EXCEPTIONS macro to protect your code instead.
+*/
+
+#ifdef QT_BOOTSTRAPPED
+# define QT_NO_EXCEPTIONS
+#endif
+
+#ifdef QT_NO_EXCEPTIONS
+# define QT_TRY if (true)
+# define QT_CATCH(A) else
+# define QT_THROW(A) qt_noop()
+# define QT_RETHROW qt_noop()
+#else
+# define QT_TRY try
+# define QT_CATCH(A) catch (A)
+# define QT_THROW(A) throw A
+# define QT_RETHROW throw
+#endif
+
/*
System information
*/
@@ -1359,6 +1473,23 @@ public:
};
static const MacVersion MacintoshVersion;
#endif
+#ifdef Q_OS_SYMBIAN
+ enum SymbianVersion {
+ SV_Unknown = 0x0000,
+ SV_9_2 = 0x0001,
+ SV_9_3 = 0x0002,
+ SV_9_4 = 0x0004
+ };
+ static SymbianVersion symbianVersion();
+ enum S60Version {
+ SV_S60_None = 0x0000,
+ SV_S60_Unknown = 0x0001,
+ SV_S60_3_1 = 0x0002,
+ SV_S60_3_2 = 0x0004,
+ SV_S60_5_0 = 0x0008
+ };
+ static S60Version s60Version();
+#endif
};
Q_CORE_EXPORT const char *qVersion();
@@ -1379,21 +1510,13 @@ inline QT3_SUPPORT bool qSysInfo(int *wordSize, bool *bigEndian)
#if defined(Q_WS_WIN) || defined(Q_OS_CYGWIN)
#if defined(QT3_SUPPORT)
-inline QT3_SUPPORT bool qt_winUnicode() { return !(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based); }
+inline QT3_SUPPORT bool qt_winUnicode() { return true; }
inline QT3_SUPPORT int qWinVersion() { return QSysInfo::WindowsVersion; }
#endif
-#ifdef Q_OS_WINCE
-#define QT_WA(uni, ansi) uni
-#define QT_WA_INLINE(uni, ansi) (uni)
-#elif defined(UNICODE)
-#define QT_WA(uni, ansi) if (!(QSysInfo::windowsVersion() & QSysInfo::WV_DOS_based)) { uni } else { ansi }
+#define QT_WA(unicode, ansi) unicode
+#define QT_WA_INLINE(unicode, ansi) (unicode)
-#define QT_WA_INLINE(uni, ansi) (!(QSysInfo::windowsVersion() & QSysInfo::WV_DOS_based) ? uni : ansi)
-#else
-#define QT_WA(uni, ansi) ansi
-#define QT_WA_INLINE(uni, ansi) ansi
-#endif
#endif /* Q_WS_WIN */
#ifndef Q_OUTOFLINE_TEMPLATE
@@ -1411,7 +1534,7 @@ inline QT3_SUPPORT int qWinVersion() { return QSysInfo::WindowsVersion; }
Avoid "unused parameter" warnings
*/
-#if defined(Q_CC_INTEL) && !defined(Q_OS_WIN)
+#if defined(Q_CC_INTEL) && !defined(Q_OS_WIN) || defined(Q_CC_RVCT)
template <typename T>
inline void qUnused(T &x) { (void)x; }
# define Q_UNUSED(x) qUnused(x);
@@ -1423,6 +1546,15 @@ inline void qUnused(T &x) { (void)x; }
Debugging and error handling
*/
+/*
+ On Symbian we do not know beforehand whether we are compiling in
+ release or debug mode, so check the Symbian build define here,
+ and set the QT_NO_DEBUG define appropriately.
+*/
+#if defined(Q_OS_SYMBIAN) && defined(NDEBUG) && !defined(QT_NO_DEBUG)
+# define QT_NO_DEBUG
+#endif
+
#if !defined(QT_NO_DEBUG) && !defined(QT_DEBUG)
# define QT_DEBUG
#endif
@@ -1491,8 +1623,6 @@ inline QNoDebug qDebug();
#endif
-inline void qt_noop() {}
-
Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line);
#if !defined(Q_ASSERT)
@@ -1519,13 +1649,24 @@ Q_CORE_EXPORT void qt_assert_x(const char *where, const char *what, const char *
Q_CORE_EXPORT void qt_check_pointer(const char *, int);
-#ifndef QT_NO_DEBUG
-# define Q_CHECK_PTR(p) do {if(!(p))qt_check_pointer(__FILE__,__LINE__);} while (0)
+#ifndef QT_NO_EXCEPTIONS
+Q_CORE_EXPORT void qBadAlloc();
+#endif
+
+#ifdef QT_NO_EXCEPTIONS
+# if defined(QT_NO_DEBUG)
+# define Q_CHECK_PTR(p) qt_noop();
+# else
+# define Q_CHECK_PTR(p) do {if(!(p))qt_check_pointer(__FILE__,__LINE__);} while (0)
+# endif
#else
-# define Q_CHECK_PTR(p)
+# define Q_CHECK_PTR(p) do { if (!(p)) qBadAlloc(); } while (0)
#endif
-#if (defined(Q_CC_GNU) && !defined(Q_OS_SOLARIS)) || defined(Q_CC_HPACC)
+template <typename T>
+inline T *q_check_ptr(T *p) { Q_CHECK_PTR(p); return p; }
+
+#if (defined(Q_CC_GNU) && !defined(Q_OS_SOLARIS)) || defined(Q_CC_HPACC) || defined(Q_CC_DIAB)
# define Q_FUNC_INFO __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
/* MSVC 2002 doesn't have __FUNCSIG__ nor can it handle QT_STRINGIFY. */
@@ -1535,7 +1676,7 @@ Q_CORE_EXPORT void qt_check_pointer(const char *, int);
# define Q_FUNC_INFO __FUNCSIG__
# endif
#else
-# if defined(Q_OS_SOLARIS) || defined(Q_CC_XLC)
+# if defined(Q_OS_SOLARIS) || defined(Q_CC_XLC) || defined(Q_OS_SYMBIAN)
# define Q_FUNC_INFO __FILE__ "(line number unavailable)"
# else
/* These two macros makes it possible to turn the builtin line expander into a
@@ -1544,9 +1685,9 @@ Q_CORE_EXPORT void qt_check_pointer(const char *, int);
# define QT_STRINGIFY(x) QT_STRINGIFY2(x)
# define Q_FUNC_INFO __FILE__ ":" QT_STRINGIFY(__LINE__)
# endif
- /* The MIPSpro compiler postpones macro expansion, and therefore macros must be in scope
- * when being used. */
-# if !defined(Q_CC_MIPS)
+ /* The MIPSpro and RVCT compilers postpones macro expansion,
+ and therefore macros must be in scope when being used. */
+# if !defined(Q_CC_MIPS) && !defined(Q_CC_RVCT) && !defined(Q_CC_NOKIAX86)
# undef QT_STRINGIFY2
# undef QT_STRINGIFY
# endif
@@ -1671,12 +1812,12 @@ public:
static TYPE *NAME() \
{ \
if (!this_##NAME.pointer && !this_##NAME.destroyed) { \
- TYPE *x = new TYPE; \
+ QScopedPointer<TYPE > x(new TYPE); \
INITIALIZER; \
- if (!this_##NAME.pointer.testAndSetOrdered(0, x)) \
- delete x; \
- else \
+ if (this_##NAME.pointer.testAndSetOrdered(0, x.data())) { \
static QGlobalStaticDeleter<TYPE > cleanup(this_##NAME); \
+ x.take(); \
+ } \
} \
return this_##NAME.pointer; \
}
@@ -1710,6 +1851,22 @@ static inline bool qFuzzyCompare(float p1, float p2)
return (qAbs(p1 - p2) <= 0.00001f * qMin(qAbs(p1), qAbs(p2)));
}
+/*!
+ \internal
+*/
+static inline bool qFuzzyIsNull(double d)
+{
+ return qAbs(d) <= 0.000000000001;
+}
+
+/*!
+ \internal
+*/
+static inline bool qFuzzyIsNull(float f)
+{
+ return qAbs(f) <= 0.00001f;
+}
+
/*
This function tests a double for a null value. It doesn't
check whether the actual value is 0 or close to 0, but whether
@@ -1841,7 +1998,7 @@ enum { /* TYPEINFO flags */
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS) \
template <> \
-class QTypeInfo<TYPE> \
+class QTypeInfo<TYPE > \
{ \
public: \
enum { \
@@ -1854,6 +2011,14 @@ public: \
static inline const char *name() { return #TYPE; } \
}
+template <typename T>
+inline void qSwap(T &value1, T &value2)
+{
+ const T t = value1;
+ value1 = value2;
+ value2 = t;
+}
+
/*
Specialize a shared type with:
@@ -1863,33 +2028,12 @@ public: \
types must declare a 'bool isDetached(void) const;' member for this
to work.
*/
-#if defined Q_CC_MSVC && _MSC_VER < 1300
-template <typename T>
-inline void qSwap_helper(T &value1, T &value2, T*)
-{
- T t = value1;
- value1 = value2;
- value2 = t;
-}
-#define Q_DECLARE_SHARED(TYPE) \
-template <> inline bool qIsDetached<TYPE>(TYPE &t) { return t.isDetached(); } \
-template <> inline void qSwap_helper<TYPE>(TYPE &value1, TYPE &value2, TYPE*) \
-{ \
- const TYPE::DataPtr t = value1.data_ptr(); \
- value1.data_ptr() = value2.data_ptr(); \
- value2.data_ptr() = t; \
-}
-#else
#define Q_DECLARE_SHARED(TYPE) \
template <> inline bool qIsDetached<TYPE>(TYPE &t) { return t.isDetached(); } \
-template <typename T> inline void qSwap(T &, T &); \
template <> inline void qSwap<TYPE>(TYPE &value1, TYPE &value2) \
{ \
- const TYPE::DataPtr t = value1.data_ptr(); \
- value1.data_ptr() = value2.data_ptr(); \
- value2.data_ptr() = t; \
+ qSwap(value1.data_ptr(), value2.data_ptr()); \
}
-#endif
/*
QTypeInfo primitive specializations
@@ -2046,7 +2190,7 @@ typedef uint Flags;
#endif /* Q_NO_TYPESAFE_FLAGS */
-#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
+#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_RVCT)
/* make use of typeof-extension */
template <typename T>
class QForeachContainer {
@@ -2099,6 +2243,17 @@ inline const QForeachContainer<T> *qForeachContainer(const QForeachContainerBase
qForeachContainer(&_container_, true ? 0 : qForeachPointer(container))->brk; \
--qForeachContainer(&_container_, true ? 0 : qForeachPointer(container))->brk)
+#elif defined(Q_CC_DIAB)
+// VxWorks DIAB generates unresolvable symbols, if container is a function call
+# define Q_FOREACH(variable,container) \
+ if(0){}else \
+ for (const QForeachContainerBase &_container_ = qForeachContainerNew(container); \
+ qForeachContainer(&_container_, (__typeof__(container) *) 0)->condition(); \
+ ++qForeachContainer(&_container_, (__typeof__(container) *) 0)->i) \
+ for (variable = *qForeachContainer(&_container_, (__typeof__(container) *) 0)->i; \
+ qForeachContainer(&_container_, (__typeof__(container) *) 0)->brk; \
+ --qForeachContainer(&_container_, (__typeof__(container) *) 0)->brk)
+
#else
# define Q_FOREACH(variable, container) \
for (const QForeachContainerBase &_container_ = qForeachContainerNew(container); \
@@ -2129,9 +2284,12 @@ inline const QForeachContainer<T> *qForeachContainer(const QForeachContainerBase
#endif
#endif
+template <typename T> static inline T *qGetPtrHelper(T *ptr) { return ptr; }
+template <typename Wrapper> static inline typename Wrapper::pointer qGetPtrHelper(const Wrapper &p) { return p.data(); }
+
#define Q_DECLARE_PRIVATE(Class) \
- inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(d_ptr); } \
- inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(d_ptr); } \
+ inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \
+ inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } \
friend class Class##Private;
#define Q_DECLARE_PRIVATE_D(Dptr, Class) \
@@ -2153,6 +2311,18 @@ inline const QForeachContainer<T> *qForeachContainer(const QForeachContainerBase
#define QT_TRANSLATE_NOOP_UTF8(scope, x) (x)
#define QT_TRANSLATE_NOOP3(scope, x, comment) {x, comment}
#define QT_TRANSLATE_NOOP3_UTF8(scope, x, comment) {x, comment}
+
+#ifndef QT_NO_TRANSLATION // ### This should enclose the NOOPs above
+
+// Defined in qcoreapplication.cpp
+// The better name qTrId() is reserved for an upcoming function which would
+// return a much more powerful QStringFormatter instead of a QString.
+Q_CORE_EXPORT QString qtTrId(const char *id, int n = -1);
+
+#define QT_TRID_NOOP(id) id
+
+#endif // QT_NO_TRANSLATION
+
#define QDOC_PROPERTY(text)
/*
@@ -2173,14 +2343,9 @@ inline const QForeachContainer<T> *qForeachContainer(const QForeachContainerBase
classes contains a private copy constructor and assignment
operator to disable copying (the compiler gives an error message).
*/
-
-#if !defined(Q_NO_DECLARED_NOT_DEFINED) || !defined(QT_MAKEDLL)
-# define Q_DISABLE_COPY(Class) \
- Class(const Class &); \
- Class &operator=(const Class &);
-#else
-# define Q_DISABLE_COPY(Class)
-#endif
+#define Q_DISABLE_COPY(Class) \
+ Class(const Class &); \
+ Class &operator=(const Class &);
class QByteArray;
Q_CORE_EXPORT QByteArray qgetenv(const char *varName);
@@ -2216,6 +2381,47 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathTranslations();
QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf();
#endif
+#if defined(Q_OS_SYMBIAN)
+
+//Symbian does not support data imports from a DLL
+#define Q_NO_DATA_RELOCATION
+
+QT_END_NAMESPACE
+// forward declare std::exception
+#ifdef __cplusplus
+namespace std { class exception; }
+#endif
+QT_BEGIN_NAMESPACE
+Q_CORE_EXPORT void qt_symbian_throwIfError(int error);
+Q_CORE_EXPORT void qt_symbian_exception2LeaveL(const std::exception& ex);
+Q_CORE_EXPORT int qt_symbian_exception2Error(const std::exception& ex);
+
+#define QT_TRAP_THROWING(_f) \
+ { \
+ TInt ____error; \
+ TRAP(____error, _f); \
+ qt_symbian_throwIfError(____error); \
+ }
+
+#define QT_TRYCATCH_ERROR(_err, _f) \
+ { \
+ _err = KErrNone; \
+ try { \
+ _f; \
+ } catch (const std::exception &____ex) { \
+ _err = qt_symbian_exception2Error(____ex); \
+ } \
+ }
+
+#define QT_TRYCATCH_LEAVING(_f) \
+ { \
+ TInt ____err; \
+ QT_TRYCATCH_ERROR(____err, _f) \
+ User::LeaveIfError(____err); \
+ }
+#endif
+
+
/*
This gives us the possibility to check which modules the user can
use. These are purely compile time checks and will generate no code.
@@ -2239,12 +2445,15 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf();
#define QT_MODULE_TEST 0x04000
#define QT_MODULE_DBUS 0x08000
#define QT_MODULE_SCRIPTTOOLS 0x10000
+#define QT_MODULE_OPENVG 0x20000
+#define QT_MODULE_MULTIMEDIA 0x40000
/* Qt editions */
#define QT_EDITION_CONSOLE (QT_MODULE_CORE \
| QT_MODULE_NETWORK \
| QT_MODULE_SQL \
| QT_MODULE_SCRIPT \
+ | QT_MODULE_MULTIMEDIA \
| QT_MODULE_XML \
| QT_MODULE_XMLPATTERNS \
| QT_MODULE_TEST \
@@ -2258,7 +2467,9 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf();
| QT_MODULE_GUI \
| QT_MODULE_NETWORK \
| QT_MODULE_OPENGL \
+ | QT_MODULE_OPENVG \
| QT_MODULE_SQL \
+ | QT_MODULE_MULTIMEDIA \
| QT_MODULE_XML \
| QT_MODULE_XMLPATTERNS \
| QT_MODULE_SCRIPT \
@@ -2289,6 +2500,9 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf();
#define QT_LICENSED_MODULE(x) \
enum QtValidLicenseFor##x##Module { Licensed##x = true };
+/* qdoc is really unhappy with the following block of preprocessor checks,
+ making it difficult to document classes properly after this point. */
+
#if (QT_EDITION & QT_MODULE_CORE)
QT_LICENSED_MODULE(Core)
#endif
@@ -2301,9 +2515,15 @@ QT_LICENSED_MODULE(Network)
#if (QT_EDITION & QT_MODULE_OPENGL)
QT_LICENSED_MODULE(OpenGL)
#endif
+#if (QT_EDITION & QT_MODULE_OPENVG)
+QT_LICENSED_MODULE(OpenVG)
+#endif
#if (QT_EDITION & QT_MODULE_SQL)
QT_LICENSED_MODULE(Sql)
#endif
+#if (QT_EDITION & QT_MODULE_MULTIMEDIA)
+QT_LICENSED_MODULE(Multimedia)
+#endif
#if (QT_EDITION & QT_MODULE_XML)
QT_LICENSED_MODULE(Xml)
#endif
@@ -2345,32 +2565,30 @@ QT_LICENSED_MODULE(DBus)
# define QT_NO_QFUTURE
#endif
-/*
- Turn off certain features for compilers that have problems parsing
- the code.
-*/
-#if (defined(Q_CC_HPACC) && defined(QT_ARCH_PARISC)) \
- || defined(Q_CC_MIPS) \
- || defined(Q_CC_XLC)
-// HP aCC A.03.*, MIPSpro, and xlC cannot handle
-// the template function declarations for the QtConcurrent functions
-# define QT_NO_QFUTURE
-# define QT_NO_CONCURRENT
-#endif
-
-// MSVC 6.0, MSVC .NET 2002, and old versions of Sun CC can`t handle the map(), etc templates,
+// MSVC 6.0 and MSVC .NET 2002, can`t handle the map(), etc templates,
// but the QFuture class compiles.
-#if (defined(Q_CC_MSVC) && _MSC_VER <= 1300) || (defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x590)
+#if (defined(Q_CC_MSVC) && _MSC_VER <= 1300)
# define QT_NO_CONCURRENT
#endif
-// Mingw uses a gcc 3 version which has problems with some of the
-// map/filter overloads. So does IRIX and Solaris.
-#if (defined(Q_OS_IRIX) || defined(Q_CC_MINGW) || defined (Q_OS_SOLARIS)) && (__GNUC__ < 4)
+// gcc 3 version has problems with some of the
+// map/filter overloads.
+#if defined(Q_CC_GNU) && (__GNUC__ < 4)
# define QT_NO_CONCURRENT_MAP
# define QT_NO_CONCURRENT_FILTER
#endif
+#ifdef Q_OS_QNX
+// QNX doesn't have SYSV style shared memory. Multiprocess QWS apps,
+// shared fonts and QSystemSemaphore + QSharedMemory are not available
+# define QT_NO_QWS_MULTIPROCESS
+# define QT_NO_QWS_SHARE_FONTS
+# define QT_NO_SYSTEMSEMAPHORE
+# define QT_NO_SHAREDMEMORY
+// QNX currently doesn't support forking in a thread, so disable QProcess
+# define QT_NO_PROCESS
+#endif
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp
index 2f8637a..2189d39 100644
--- a/src/corelib/global/qlibraryinfo.cpp
+++ b/src/corelib/global/qlibraryinfo.cpp
@@ -40,11 +40,11 @@
****************************************************************************/
#include "qdir.h"
-#include "qfile.h"
+#include "qfile.h"
#include "qconfig.h"
#include "qsettings.h"
#include "qlibraryinfo.h"
-#include "qpointer.h"
+#include "qscopedpointer.h"
#ifdef QT_BUILD_QMAKE
QT_BEGIN_NAMESPACE
@@ -67,8 +67,7 @@ QT_BEGIN_NAMESPACE
struct QLibrarySettings
{
QLibrarySettings();
- ~QLibrarySettings() { delete static_cast<QSettings *>(settings); }
- QSettings *settings;
+ QScopedPointer<QSettings> settings;
};
Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings)
@@ -79,32 +78,19 @@ public:
static void cleanup()
{
QLibrarySettings *ls = qt_library_settings();
- if (ls) {
- delete static_cast<QSettings *>(ls->settings);
- ls->settings = 0;
- }
+ if (ls)
+ ls->settings.reset(0);
}
static QSettings *configuration()
{
-#ifdef QT_NO_THREAD
- // This recursion guard should be a temporary solution; the recursive
- // dependency should be found and removed.
- static bool initializing = false;
- if (initializing)
- return 0;
- initializing = true;
-#endif
QLibrarySettings *ls = qt_library_settings();
-#ifdef QT_NO_THREAD
- initializing = false;
-#endif
- return ls ? static_cast<QSettings *>(qt_library_settings()->settings) : (QSettings*)0;
+ return ls ? ls->settings.data() : 0;
}
};
QLibrarySettings::QLibrarySettings()
+ : settings(QLibraryInfoPrivate::findConfiguration())
{
- settings = QLibraryInfoPrivate::findConfiguration();
#ifndef QT_BUILD_QMAKE
qAddPostRoutine(QLibraryInfoPrivate::cleanup);
#endif
@@ -147,9 +133,6 @@ QSettings *QLibraryInfoPrivate::findConfiguration()
\class QLibraryInfo
\brief The QLibraryInfo class provides information about the Qt library.
- \ingroup misc
- \mainclass
-
Many pieces of information are established when Qt is configured.
Installation paths, license information, and even a unique build
key. This class provides an abstraction for accessing this
@@ -434,14 +417,14 @@ QLibraryInfo::location(LibraryLocation loc)
#else
if (QCoreApplication::instance()) {
#ifdef Q_OS_MAC
- CFBundleRef bundleRef = CFBundleGetMainBundle();
- if (bundleRef) {
- QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef);
- if (urlRef) {
- QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
- return QDir::cleanPath(path + QLatin1String("/Contents"));
- }
- }
+ CFBundleRef bundleRef = CFBundleGetMainBundle();
+ if (bundleRef) {
+ QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef);
+ if (urlRef) {
+ QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
+ return QDir::cleanPath(path + QLatin1String("/Contents/") + ret);
+ }
+ }
#endif
return QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(ret);
} else {
@@ -490,7 +473,7 @@ QT_END_NAMESPACE
extern const char qt_core_interpreter[] __attribute__((section(".interp")))
= ELF_INTERPRETER;
-extern "C"
+extern "C" void qt_core_boilerplate();
void qt_core_boilerplate()
{
printf("This is the QtCore library version " QT_VERSION_STR "\n"
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 8860f72..a6f5907 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -44,6 +44,10 @@
#include <QtCore/qglobal.h>
+#ifdef Q_OS_SYMBIAN
+# include <e32def.h>
+#endif
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -87,7 +91,8 @@ Qt {
Q_FLAGS(MatchFlags)
Q_FLAGS(KeyboardModifiers MouseButtons)
Q_ENUMS(WindowType WindowState WindowModality WidgetAttribute ApplicationAttribute)
- Q_FLAGS(WindowFlags WindowStates)
+ Q_ENUMS(InputMethodHint)
+ Q_FLAGS(WindowFlags WindowStates InputMethodHints)
Q_ENUMS(ConnectionType)
#endif // (defined(Q_MOC_RUN) || defined(QT_JAMBI_RUN))
@@ -188,6 +193,12 @@ public:
#endif
};
+ enum TileRule {
+ Stretch,
+ Repeat,
+ Round
+ };
+
// Text formatting flags for QPainter::drawText and QLabel.
// The following two enums can be combined to one integer which
// is passed as 'flags' to drawText and qt_format_text.
@@ -227,7 +238,8 @@ public:
TextHideMnemonic = 0x8000,
TextJustificationForced = 0x10000,
TextForceLeftToRight = 0x20000,
- TextForceRightToLeft = 0x40000
+ TextForceRightToLeft = 0x40000,
+ TextLongestVariant = 0x80000
#if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN)
,SingleLine = TextSingleLine,
@@ -485,6 +497,10 @@ public:
WA_WState_WindowOpacitySet = 119, // internal
WA_TranslucentBackground = 120,
+ WA_AcceptTouchEvents = 121,
+ WA_WState_AcceptedTouchBeginEvent = 122,
+ WA_TouchPadAcceptSingleTouchEvents = 123,
+
// Add new attributes before this line
WA_AttributeCount
};
@@ -497,6 +513,8 @@ public:
AA_NativeWindows = 3,
AA_DontCreateNativeWidgetSiblings = 4,
AA_MacPluginApplication = 5,
+ AA_DontUseNativeMenuBar = 6,
+ AA_MacDontSwapCtrlAndMeta = 7,
// Add new attributes before this line
AA_AttributeCount
@@ -1319,7 +1337,8 @@ public:
DirectConnection,
QueuedConnection,
AutoCompatConnection,
- BlockingQueuedConnection
+ BlockingQueuedConnection,
+ UniqueConnection = 0x80
};
enum ShortcutContext {
@@ -1390,14 +1409,36 @@ public:
ImFont,
ImCursorPosition,
ImSurroundingText,
- ImCurrentSelection
+ ImCurrentSelection,
+ ImMaximumTextLength,
+ ImAnchorPosition
+ };
+
+ enum InputMethodHint {
+ ImhNone = 0x0,
+ ImhHiddenText = 0x1,
+ ImhNoAutoUppercase = 0x2,
+ ImhPreferNumbers = 0x4,
+ ImhPreferUppercase = 0x8,
+ ImhPreferLowercase = 0x10,
+ ImhNoPredictiveText = 0x20,
+
+ ImhDigitsOnly = 0x10000,
+ ImhFormattedNumbersOnly = 0x20000,
+ ImhUppercaseOnly = 0x40000,
+ ImhLowercaseOnly = 0x80000,
+ ImhDialableCharactersOnly = 0x100000,
+
+ ImhExclusiveInputMask = 0xffff0000
};
+ Q_DECLARE_FLAGS(InputMethodHints, InputMethodHint)
enum ToolButtonStyle {
ToolButtonIconOnly,
ToolButtonTextOnly,
ToolButtonTextBesideIcon,
- ToolButtonTextUnderIcon
+ ToolButtonTextUnderIcon,
+ ToolButtonFollowStyle
};
enum LayoutDirection {
@@ -1405,6 +1446,17 @@ public:
RightToLeft
};
+ enum AnchorPoint {
+ AnchorLeft = 0,
+ AnchorHorizontalCenter,
+ AnchorRight,
+ AnchorTop,
+ AnchorVerticalCenter,
+ AnchorBottom
+ };
+
+
+
enum DropAction {
CopyAction = 0x1,
MoveAction = 0x2,
@@ -1485,6 +1537,8 @@ public:
typedef unsigned long HANDLE;
#elif defined(Q_WS_QWS)
typedef void * HANDLE;
+#elif defined(Q_OS_SYMBIAN)
+ typedef unsigned long int HANDLE; // equivalent to TUint32
#endif
typedef WindowFlags WFlags;
@@ -1533,6 +1587,35 @@ public:
BottomLeftSection,
TitleBarArea // For move
};
+
+ enum Initialization {
+ Uninitialized
+ };
+
+ enum CoordinateSystem {
+ DeviceCoordinates,
+ LogicalCoordinates
+ };
+
+ enum TouchPointState {
+ TouchPointPressed = 0x01,
+ TouchPointMoved = 0x02,
+ TouchPointStationary = 0x04,
+ TouchPointReleased = 0x08,
+ TouchPointStateMask = 0x0f,
+
+ TouchPointPrimary = 0x10
+ };
+ Q_DECLARE_FLAGS(TouchPointStates, TouchPointState)
+
+ enum GestureState
+ {
+ NoGesture,
+ GestureStarted = 1,
+ GestureUpdated = 2,
+ GestureFinished = 3
+ };
+
}
#ifdef Q_MOC_RUN
;
@@ -1552,6 +1635,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::DropActions)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::ItemFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::MatchFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::TextInteractionFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::InputMethodHints)
+Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::TouchPointStates)
typedef bool (*qInternalCallback)(void **);
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
new file mode 100644
index 0000000..ace70ff
--- /dev/null
+++ b/src/corelib/global/qnamespace.qdoc
@@ -0,0 +1,2775 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \namespace Qt
+ \inmodule QtCore
+
+ \brief The Qt namespace contains miscellaneous identifiers
+ used throughout the Qt library.
+*/
+
+/*!
+ \enum Qt::Orientation
+
+ This type is used to signify an object's orientation.
+
+ \value Horizontal
+ \value Vertical
+
+ Orientation is used with QScrollBar for example.
+*/
+
+/*!
+ \enum Qt::AlignmentFlag
+
+ This enum type is used to describe alignment. It contains
+ horizontal and vertical flags that can be combined to produce
+ the required effect.
+
+ The \l{TextElideMode} enum can also be used in many situations
+ to fine-tune the appearance of aligned text.
+
+ The horizontal flags are:
+
+ \value AlignLeft Aligns with the left edge.
+ \value AlignRight Aligns with the right edge.
+ \value AlignHCenter Centers horizontally in the available space.
+ \value AlignJustify Justifies the text in the available space.
+ \omitvalue AlignAuto
+
+ The vertical flags are:
+
+ \value AlignTop Aligns with the top.
+ \value AlignBottom Aligns with the bottom.
+ \value AlignVCenter Centers vertically in the available space.
+
+ You can use only one of the horizontal flags at a time. There is
+ one two-dimensional flag:
+
+ \value AlignCenter Centers in both dimensions.
+
+ You can use at most one horizontal and one vertical flag at a
+ time. Qt::AlignCenter counts as both horizontal and vertical.
+
+ Three enum values are useful in applications that can be run in
+ right-to-left mode:
+
+ \value AlignAbsolute If the widget's layout direction is
+ Qt::RightToLeft (instead of Qt::LeftToRight, the default),
+ Qt::AlignLeft refers to the \e right edge and Qt::AlignRight
+ to the \e left edge. This is normally the desired behavior.
+ If you want Qt::AlignLeft to always mean "left" and
+ Qt::AlignRight to always mean "right", combine the flag with
+ Qt::AlignAbsolute.
+ \value AlignLeading Synonym for Qt::AlignLeft.
+ \value AlignTrailing Synonym for Qt::AlignRight.
+
+ Masks:
+
+ \value AlignHorizontal_Mask
+ \value AlignVertical_Mask
+
+ Conflicting combinations of flags have undefined meanings.
+*/
+
+/*!
+ \enum Qt::ApplicationAttribute
+
+ This enum describes attributes that change the behavior of
+ application-wide features. These are enabled and disabled using
+ QCoreApplication::setAttribute(), and can be tested for with
+ QCoreApplication::testAttribute().
+
+ \value AA_ImmediateWidgetCreation Ensures that widgets are created
+ as soon as they are constructed. By default, resources for
+ widgets are allocated on demand to improve efficiency and
+ minimize resource usage. Setting or clearing this attribute
+ affects widgets constructed after the change. Setting it
+ tells Qt to create toplevel windows immediately.
+ Therefore, if it is important to minimize resource
+ consumption, do not set this attribute.
+
+ \value AA_MSWindowsUseDirect3DByDefault This value is obsolete and
+ has no effect.
+
+ \value AA_DontShowIconsInMenus Actions with the Icon property won't be
+ shown in any menus unless specifically set by the
+ QAction::iconVisibleInMenu property.
+
+ Menus that are currently open or menus already created in the native
+ Mac OS X menubar \e{may not} pick up a change in this attribute. Changes
+ in the QAction::iconVisibleInMenu property will always be picked up.
+
+ \value AA_NativeWindows Ensures that widgets have native windows.
+
+ \value AA_DontCreateNativeWidgetSiblings Ensures that siblings of native
+ widgets stay non-native unless specifically set by the
+ Qt::WA_NativeWindow attribute.
+
+ \value AA_MacPluginApplication Stops the Qt mac application from doing
+ specific initializations that do not necessarily make sense when using Qt
+ to author a plugin. This includes avoiding loading our nib for the main
+ menu and not taking possession of the native menu bar. When setting this
+ attribute to true will also set the AA_DontUseNativeMenuBar attribute
+ to true.
+
+ \value AA_DontUseNativeMenuBar All menubars created while this attribute is
+ set to true won't be used as a native menubar (e.g, the menubar at
+ the top of the main screen on Mac OS X or at the bottom in Windows CE).
+
+ \value AA_MacDontSwapCtrlAndMeta On Mac OS X by default, Qt swaps the
+ Control and Meta (Command) keys (i.e., whenever Control is pressed, Qt
+ sends Meta and whenever Meta is pressed Control is sent. When this
+ attribute is true, Qt will not do the flip. QKeySequence::StandardShortcuts
+ will also flip accordingly (i.e., QKeySequence::Copy will be
+ Command+C on the keyboard regardless of the value set, though what is output for
+ QKeySequence::toString(QKeySequence::PortableText) will be different).
+
+ \omitvalue AA_AttributeCount
+*/
+
+/*!
+ \enum Qt::MouseButton
+
+ This enum type describes the different mouse buttons.
+
+ \value NoButton The button state does not refer to any
+ button (see QMouseEvent::button()).
+ \value LeftButton The left button is pressed, or an event refers
+ to the left button. (The left button may be the right button on
+ left-handed mice.)
+ \value RightButton The right button.
+ \value MidButton The middle button.
+ \value XButton1 The first X button.
+ \value XButton2 The second X button.
+
+ \omitvalue MouseButtonMask
+
+ \sa KeyboardModifier Modifier
+*/
+
+/*!
+ \enum Qt::KeyboardModifier
+
+ This enum describes the modifier keys.
+
+ \value NoModifier No modifier key is pressed.
+ \value ShiftModifier A Shift key on the keyboard is pressed.
+ \value ControlModifier A Ctrl key on the keyboard is pressed.
+ \value AltModifier An Alt key on the keyboard is pressed.
+ \value MetaModifier A Meta key on the keyboard is pressed.
+ \value KeypadModifier A keypad button is pressed.
+ \value GroupSwitchModifier X11 only. A Mode_switch key on the keyboard is pressed.
+
+ \omitvalue KeyboardModifierMask
+
+ \note On Mac OS X, the \c ControlModifier value corresponds to
+ the Command keys on the Macintosh keyboard, and the \c MetaModifier value
+ corresponds to the Control keys. The \c KeypadModifier value will also be set
+ when an arrow key is pressed as the arrow keys are considered part of the
+ keypad.
+
+ \note On Windows Keyboards, Qt::MetaModifier and Qt::Key_Meta are mapped
+ to the Windows key.
+
+ \sa MouseButton Modifier
+*/
+
+/*!
+ \enum Qt::Modifier
+
+ This enum provides shorter names for the keyboard modifier keys
+ supported by Qt.
+
+ \bold{Note:} On Mac OS X, the \c CTRL value corresponds to
+ the Command keys on the Macintosh keyboard, and the \c META value
+ corresponds to the Control keys.
+
+ \value SHIFT The Shift keys provided on all standard keyboards.
+ \value META The Meta keys.
+ \value CTRL The Ctrl keys.
+ \value ALT The normal Alt keys, but not keys like AltGr.
+ \value UNICODE_ACCEL The shortcut is specified as a Unicode code
+ point, not as a Qt Key.
+ \omitvalue MODIFIER_MASK
+
+ \sa KeyboardModifier MouseButton
+*/
+
+/*!
+ \enum Qt::GlobalColor
+
+ \raw HTML
+ <style type="text/css" id="colorstyles">
+ #white { background-color: #ffffff; color: #000000 }
+ #black { background-color: #000000; color: #ffffff }
+ #red { background-color: #ff0000; color: #000000 }
+ #darkRed { background-color: #800000; color: #ffffff }
+ #green { background-color: #00ff00; color: #000000 }
+ #darkGreen { background-color: #008000; color: #ffffff }
+ #blue { background-color: #0000ff; color: #ffffff }
+ #darkBlue { background-color: #000080; color: #ffffff }
+ #cyan { background-color: #00ffff; color: #000000 }
+ #darkCyan { background-color: #008080; color: #ffffff }
+ #magenta { background-color: #ff00ff; color: #000000 }
+ #darkMagenta { background-color: #800080; color: #ffffff }
+ #yellow { background-color: #ffff00; color: #000000 }
+ #darkYellow { background-color: #808000; color: #ffffff }
+ #gray { background-color: #a0a0a4; color: #000000 }
+ #darkGray { background-color: #808080; color: #ffffff }
+ #lightGray { background-color: #c0c0c0; color: #000000 }
+ </style>
+ \endraw
+
+ Qt's predefined QColor objects:
+
+ \value white \raw HTML
+ White <tt id="white">(#ffffff)</tt>
+ \endraw
+ \value black \raw HTML
+ Black <tt id="black">(#000000)</tt>
+ \endraw
+ \value red \raw HTML
+ Red <tt id="red">(#ff0000)</tt>
+ \endraw
+ \value darkRed \raw HTML
+ Dark red <tt id="darkRed">(#800000)</tt>
+ \endraw
+ \value green \raw HTML
+ Green <tt id="green">(#00ff00)</tt>
+ \endraw
+ \value darkGreen \raw HTML
+ Dark green <tt id="darkGreen">(#008000)</tt>
+ \endraw
+ \value blue \raw HTML
+ Blue <tt id="blue">(#0000ff)</tt>
+ \endraw
+ \value darkBlue \raw HTML
+ Dark blue <tt id="darkBlue">(#000080)</tt>
+ \endraw
+ \value cyan \raw HTML
+ Cyan <tt id="cyan">(#00ffff)</tt>
+ \endraw
+ \value darkCyan \raw HTML
+ Dark cyan <tt id="darkCyan">(#008080)</tt>
+ \endraw
+ \value magenta \raw HTML
+ Magenta <tt id="magenta">(#ff00ff)</tt>
+ \endraw
+ \value darkMagenta \raw HTML
+ Dark magenta <tt id="darkMagenta">(#800080)</tt>
+ \endraw
+ \value yellow \raw HTML
+ Yellow <tt id="yellow">(#ffff00)</tt>
+ \endraw
+ \value darkYellow \raw HTML
+ Dark yellow <tt id="darkYellow">(#808000)</tt>
+ \endraw
+ \value gray \raw HTML
+ Gray <tt id="gray">(#a0a0a4)</tt>
+ \endraw
+ \value darkGray \raw HTML
+ Dark gray <tt id="darkGray">(#808080)</tt>
+ \endraw
+ \value lightGray \raw HTML
+ Light gray <tt id="lightGray">(#c0c0c0)</tt>
+ \endraw
+ \value transparent a transparent black value (i.e., QColor(0, 0, 0, 0))
+ \value color0 0 pixel value (for bitmaps)
+ \value color1 1 pixel value (for bitmaps)
+
+ \sa QColor
+
+*/
+
+/*!
+ \enum Qt::PenStyle
+
+ This enum type defines the pen styles that can be drawn using
+ QPainter. The styles are:
+
+ \table
+ \row
+ \o \inlineimage qpen-solid.png
+ \o \inlineimage qpen-dash.png
+ \o \inlineimage qpen-dot.png
+ \row
+ \o Qt::SolidLine
+ \o Qt::DashLine
+ \o Qt::DotLine
+ \row
+ \o \inlineimage qpen-dashdot.png
+ \o \inlineimage qpen-dashdotdot.png
+ \o \inlineimage qpen-custom.png
+ \row
+ \o Qt::DashDotLine
+ \o Qt::DashDotDotLine
+ \o Qt::CustomDashLine
+ \endtable
+
+ \value NoPen no line at all. For example, QPainter::drawRect()
+ fills but does not draw any boundary line.
+
+ \value SolidLine A plain line.
+ \value DashLine Dashes separated by a few pixels.
+ \value DotLine Dots separated by a few pixels.
+ \value DashDotLine Alternate dots and dashes.
+ \value DashDotDotLine One dash, two dots, one dash, two dots.
+ \value CustomDashLine A custom pattern defined using
+ QPainterPathStroker::setDashPattern().
+
+ \omitvalue MPenStyle
+
+ \sa QPen
+*/
+
+/*!
+ \enum Qt::PenCapStyle
+
+ This enum type defines the pen cap styles supported by Qt, i.e.
+ the line end caps that can be drawn using QPainter.
+
+ \table
+ \row
+ \o \inlineimage qpen-square.png
+ \o \inlineimage qpen-flat.png
+ \o \inlineimage qpen-roundcap.png
+ \row
+ \o Qt::SquareCap
+ \o Qt::FlatCap
+ \o Qt::RoundCap
+ \endtable
+
+ \value FlatCap a square line end that does not cover the end
+ point of the line.
+ \value SquareCap a square line end that covers the end point and
+ extends beyond it by half the line width.
+ \value RoundCap a rounded line end.
+ \omitvalue MPenCapStyle
+
+ \sa QPen
+*/
+
+/*!
+ \enum Qt::PenJoinStyle
+
+ This enum type defines the pen join styles supported by Qt, i.e.
+ which joins between two connected lines can be drawn using
+ QPainter.
+
+ \table
+ \row
+ \o \inlineimage qpen-bevel.png
+ \o \inlineimage qpen-miter.png
+ \o \inlineimage qpen-roundjoin.png
+ \row
+ \o Qt::BevelJoin
+ \o Qt::MiterJoin
+ \o Qt::RoundJoin
+ \endtable
+
+ \value MiterJoin The outer edges of the lines are extended to
+ meet at an angle, and this area is filled.
+ \value BevelJoin The triangular notch between the two lines is filled.
+ \value RoundJoin A circular arc between the two lines is filled.
+ \value SvgMiterJoin A miter join corresponding to the definition of
+ a miter join in the \l{SVG 1.2 Tiny} specification.
+ \omitvalue MPenJoinStyle
+
+ \sa QPen
+*/
+
+/*!
+ \enum Qt::BrushStyle
+
+ This enum type defines the brush styles supported by Qt, i.e. the
+ fill pattern of shapes drawn using QPainter.
+
+ \image brush-styles.png Brush Styles
+
+ \value NoBrush No brush pattern.
+ \value SolidPattern Uniform color.
+ \value Dense1Pattern Extremely dense brush pattern.
+ \value Dense2Pattern Very dense brush pattern.
+ \value Dense3Pattern Somewhat dense brush pattern.
+ \value Dense4Pattern Half dense brush pattern.
+ \value Dense5Pattern Somewhat sparse brush pattern.
+ \value Dense6Pattern Very sparse brush pattern.
+ \value Dense7Pattern Extremely sparse brush pattern.
+ \value HorPattern Horizontal lines.
+ \value VerPattern Vertical lines.
+ \value CrossPattern Crossing horizontal and vertical lines.
+ \value BDiagPattern Backward diagonal lines.
+ \value FDiagPattern Forward diagonal lines.
+ \value DiagCrossPattern Crossing diagonal lines.
+ \value LinearGradientPattern Linear gradient (set using a dedicated QBrush constructor).
+ \value ConicalGradientPattern Conical gradient (set using a dedicated QBrush constructor).
+ \value RadialGradientPattern Radial gradient (set using a dedicated QBrush constructor).
+ \value TexturePattern Custom pattern (see QBrush::setTexture()).
+
+ \omitvalue CustomPattern
+
+ \sa QBrush
+*/
+
+/*!
+ \enum Qt::TextFlag
+
+ This enum type is used to define some modifier flags. Some of
+ these flags only make sense in the context of printing:
+
+ \value TextSingleLine Treats all whitespace as spaces and prints just
+ one line.
+ \value TextDontClip If it's impossible to stay within the given bounds,
+ it prints outside.
+ \value TextExpandTabs Makes the U+0009 (ASCII tab) character move to
+ the next tab stop.
+ \value TextShowMnemonic Displays the string "\&P" as \underline{P}
+ (see QButton for an example). For an ampersand, use "\&\&".
+ \value TextWordWrap Breaks lines at appropriate points, e.g. at word
+ boundaries.
+ \value TextWrapAnywhere Breaks lines anywhere, even within words.
+ \value TextHideMnemonic Same as Qt::TextShowMnemonic but doesn't draw the underlines.
+ \value TextDontPrint Treat this text as "hidden" and don't print
+ it.
+ \value IncludeTrailingSpaces When this option is set, QTextLine::naturalTextWidth() and naturalTextRect() will
+ return a value that includes the width of trailing spaces in the text; otherwise
+ this width is excluded.
+ \value TextIncludeTrailingSpaces Same as IncludeTrailingSpaces
+ \value TextJustificationForced Ensures that text lines are justified.
+
+ \omitvalue BreakAnywhere
+ \omitvalue DontClip
+ \omitvalue DontPrint
+ \omitvalue ExpandTabs
+ \omitvalue IncludeTrailingSpaces
+ \omitvalue NoAccel
+ \omitvalue ShowPrefix
+ \omitvalue SingleLine
+ \omitvalue WordBreak
+ \omitvalue TextForceLeftToRight
+ \omitvalue TextForceRightToLeft
+ \omitvalue TextLongestVariant Always use the longest variant when computing the size of a multi-variant string
+
+ You can use as many modifier flags as you want, except that
+ Qt::TextSingleLine and Qt::TextWordWrap cannot be combined.
+
+ Flags that are inappropriate for a given use are generally
+ ignored.
+*/
+
+/*!
+ \enum Qt::BGMode
+
+ Background mode:
+
+ \value TransparentMode
+ \value OpaqueMode
+*/
+
+/*!
+ \enum Qt::ConnectionType
+
+ This enum describes the types of connection that can be used between signals and
+ slots. In particular, it determines whether a particular signal is delivered to a
+ slot immediately or queued for delivery at a later time.
+
+ \value DirectConnection When emitted, the signal is immediately delivered to the slot.
+ \value QueuedConnection When emitted, the signal is queued until the event loop is
+ able to deliver it to the slot.
+ \value BlockingQueuedConnection
+ Same as QueuedConnection, except that the current thread blocks
+ until the slot has been delivered. This connection type should
+ only be used for receivers in a different thread. Note that misuse
+ of this type can lead to deadlocks in your application.
+ \value AutoConnection If the signal is emitted from the thread
+ in which the receiving object lives, the
+ slot is invoked directly, as with
+ Qt::DirectConnection; otherwise the
+ signal is queued, as with
+ Qt::QueuedConnection.
+ \value UniqueConnection Same as AutoConnection, but there will be a check that the signal is
+ not already connected to the same slot before connecting, otherwise,
+ the connection will fail.
+ This value was introduced in Qt 4.6.
+ \value AutoCompatConnection
+ The default connection type for signals and slots when Qt 3 support
+ is enabled. Equivalent to AutoConnection for connections but will cause warnings
+ to be output under certain circumstances. See
+ \l{Porting to Qt 4#Compatibility Signals and Slots}{Compatibility Signals and Slots}
+ for further information.
+
+ With queued connections, 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/doc_src_qnamespace.qdoc 0
+
+ call qRegisterMetaType() to register the data type before you
+ establish the connection.
+
+ \sa {Thread Support in Qt}, QObject::connect(), qRegisterMetaType()
+*/
+
+/*!
+ \enum Qt::DateFormat
+
+ \value TextDate The default Qt format, which includes the day and month name,
+ the day number in the month, and the year in full. The day and month names will
+ be short, localized names. This is basically equivalent to using the date format
+ string, "ddd MMM d yyyy". See QDate::toString() for more information.
+
+ \value ISODate ISO 8601 extended format: either \c{YYYY-MM-DD} for dates or
+ \c{YYYY-MM-DDTHH:MM:SS} for combined dates and times.
+
+ \value SystemLocaleShortDate The \l{QLocale::ShortFormat}{short format} used
+ by the \l{QLocale::system()}{operating system}.
+
+ \value SystemLocaleLongDate The \l{QLocale::LongFormat}{long format} used
+ by the \l{QLocale::system()}{operating system}.
+
+ \value DefaultLocaleShortDate The \l{QLocale::ShortFormat}{short format} specified
+ by the \l{QLocale::setDefault()}{application's locale}.
+
+ \value DefaultLocaleLongDate The \l{QLocale::LongFormat}{long format} used
+ by the \l{QLocale::setDefault()}{application's locale}.
+
+ \value SystemLocaleDate \e{This enum value is deprecated.} Use Qt::SystemLocaleShortDate
+ instead (or Qt::SystemLocaleLongDate if you want long dates).
+
+ \value LocaleDate \e{This enum value is deprecated.} Use Qt::DefaultLocaleShortDate
+ instead (or Qt::DefaultLocaleLongDate if you want long dates).
+
+ \value LocalDate \e{This enum value is deprecated.} Use Qt::SystemLocaleShortDate
+ instead (or Qt::SystemLocaleLongDate if you want long dates).
+
+ \note For \c ISODate formats, each \c Y, \c M and \c D represents a single digit
+ of the year, month and day used to specify the date. Each \c H, \c M and \c S
+ represents a single digit of the hour, minute and second used to specify the time.
+ The presence of a literal \c T character is used to separate the date and time when
+ both are specified.
+*/
+
+
+/*!
+ \enum Qt::TimeSpec
+
+ \value LocalTime Locale dependent time (Timezones and Daylight Savings Time).
+ \value UTC Coordinated Universal Time, replaces Greenwich Mean Time.
+ \value OffsetFromUTC An offset in seconds from Coordinated Universal Time.
+*/
+
+/*!
+ \enum Qt::DayOfWeek
+
+ \value Monday
+ \value Tuesday
+ \value Wednesday
+ \value Thursday
+ \value Friday
+ \value Saturday
+ \value Sunday
+*/
+
+/*!
+ \enum Qt::CaseSensitivity
+
+ \value CaseInsensitive
+ \value CaseSensitive
+*/
+
+/*!
+ \enum Qt::ToolBarArea
+
+ \value LeftToolBarArea
+ \value RightToolBarArea
+ \value TopToolBarArea
+ \value BottomToolBarArea
+ \value AllToolBarAreas
+ \value NoToolBarArea
+
+ \omitvalue ToolBarArea_Mask
+*/
+
+/*!
+ \enum Qt::DockWidgetArea
+
+ \value LeftDockWidgetArea
+ \value RightDockWidgetArea
+ \value TopDockWidgetArea
+ \value BottomDockWidgetArea
+ \value AllDockWidgetAreas
+ \value NoDockWidgetArea
+
+ \omitvalue DockWidgetArea_Mask
+*/
+
+/*!
+ \enum Qt::BackgroundMode
+
+ \compat
+
+ \value FixedColor
+ \value FixedPixmap
+ \value NoBackground
+ \value PaletteForeground
+ \value PaletteButton
+ \value PaletteLight
+ \value PaletteMidlight
+ \value PaletteDark
+ \value PaletteMid
+ \value PaletteText
+ \value PaletteBrightText
+ \value PaletteBase
+ \value PaletteBackground
+ \value PaletteShadow
+ \value PaletteHighlight
+ \value PaletteHighlightedText
+ \value PaletteButtonText
+ \value PaletteLink
+ \value PaletteLinkVisited
+ \value X11ParentRelative
+*/
+
+/*!
+ \enum Qt::ImageConversionFlag
+
+ The options marked "(default)" are set if no other values from
+ the list are included (since the defaults are zero):
+
+ Color/Mono preference (ignored for QBitmap):
+
+ \value AutoColor (default) - If the image has \link
+ QImage::depth() depth\endlink 1 and contains only
+ black and white pixels, the pixmap becomes monochrome.
+ \value ColorOnly The pixmap is dithered/converted to the
+ \link QPixmap::defaultDepth() native display depth\endlink.
+ \value MonoOnly The pixmap becomes monochrome. If necessary,
+ it is dithered using the chosen dithering algorithm.
+
+ Dithering mode preference for RGB channels:
+
+ \value DiffuseDither (default) - A high-quality dither.
+ \value OrderedDither A faster, more ordered dither.
+ \value ThresholdDither No dithering; closest color is used.
+
+ Dithering mode preference for alpha channel:
+
+ \value ThresholdAlphaDither (default) - No dithering.
+ \value OrderedAlphaDither A faster, more ordered dither.
+ \value DiffuseAlphaDither A high-quality dither.
+ \omitvalue NoAlpha
+
+ Color matching versus dithering preference:
+
+ \value PreferDither (default when converting to a pixmap) - Always dither
+ 32-bit images when the image is converted to 8 bits.
+ \value AvoidDither (default when converting for the purpose of saving to
+ file) - Dither 32-bit images only if the image has more than 256
+ colors and it is being converted to 8 bits.
+ \omitvalue AutoDither
+
+ \omitvalue ColorMode_Mask
+ \omitvalue Dither_Mask
+ \omitvalue AlphaDither_Mask
+ \omitvalue DitherMode_Mask
+ \omitvalue NoOpaqueDetection
+*/
+
+/*! \enum Qt::GUIStyle
+
+ \compat
+
+ \value WindowsStyle
+ \value MotifStyle
+ \value MacStyle
+ \value Win3Style
+ \value PMStyle
+*/
+
+/*!
+ \enum Qt::UIEffect
+
+ This enum describes the available UI effects.
+
+ By default, Qt will try to use the platform specific desktop
+ settings for each effect. Use the
+ QApplication::setDesktopSettingsAware() function (passing \c false
+ as argument) to prevent this, and the
+ QApplication::setEffectEnabled() to enable or disable a particular
+ effect.
+
+ Note that all effects are disabled on screens running at less than
+ 16-bit color depth.
+
+ \omitvalue UI_General
+
+ \value UI_AnimateMenu Show animated menus.
+ \value UI_FadeMenu Show faded menus.
+ \value UI_AnimateCombo Show animated comboboxes.
+ \value UI_AnimateTooltip Show tooltip animations.
+ \value UI_FadeTooltip Show tooltip fading effects.
+ \value UI_AnimateToolBox Reserved
+
+ \sa QApplication::setEffectEnabled(), QApplication::setDesktopSettingsAware()
+*/
+
+/*! \enum Qt::AspectRatioMode
+
+ This enum type defines what happens to the aspect ratio when
+ scaling an rectangle.
+
+ \image qimage-scaling.png
+
+ \value IgnoreAspectRatio The size is scaled freely. The aspect
+ ratio is not preserved.
+ \value KeepAspectRatio The size is scaled to a rectangle as
+ large as possible inside a given
+ rectangle, preserving the aspect ratio.
+ \value KeepAspectRatioByExpanding The size is scaled to a
+ rectangle as small as possible
+ outside a given rectangle,
+ preserving the aspect ratio.
+
+ \omitvalue ScaleFree
+ \omitvalue ScaleMin
+ \omitvalue ScaleMax
+
+ \sa QSize::scale(), QImage::scaled()
+*/
+
+/*! \typedef Qt::ScaleMode
+ \compat
+
+ Use Qt::AspectRatioMode instead.
+
+ The enum values have been renamed as follows:
+
+ \table
+ \row \i Old enum value \i New enum value
+ \row \i Qt::ScaleFree \i Qt::IgnoreAspectRatio
+ \row \i Qt::ScaleMin \i Qt::KeepAspectRatio
+ \row \i Qt::ScaleMax \i Qt::KeepAspectRatioByExpanding
+ \endtable
+*/
+
+/*! \enum Qt::TransformationMode
+
+ This enum type defines whether image transformations (e.g.,
+ scaling) should be smooth or not.
+
+ \value FastTransformation The transformation is performed
+ quickly, with no smoothing.
+ \value SmoothTransformation The resulting image is transformed
+ using bilinear filtering.
+
+ \sa QImage::scaled()
+*/
+
+/*! \enum Qt::Axis
+
+ This enum type defines three values to represent the three
+ axes in the cartesian coordinate system.
+
+ \value XAxis The X axis.
+ \value YAxis The Y axis.
+ \value ZAxis The Z axis.
+
+ \sa QTransform::rotate(), QTransform::rotateRadians()
+ */
+
+/*!
+ \enum Qt::WidgetAttribute
+
+ \keyword widget attributes
+
+ This enum type is used to specify various widget attributes.
+ Attributes are set and cleared with QWidget::setAttribute(), and
+ queried with QWidget::testAttribute(), although some have special
+ convenience functions which are mentioned below.
+
+ \value WA_AcceptDrops Allows data from drag and drop operations
+ to be dropped onto the widget (see QWidget::setAcceptDrops()).
+
+ \value WA_AlwaysShowToolTips Enables tooltips for inactive windows.
+
+ \value WA_ContentsPropagated This flag is superfluous and
+ obsolete; it no longer has any effect. Since Qt 4.1, all widgets
+ that do not set WA_PaintOnScreen propagate their contents.
+
+ \value WA_CustomWhatsThis Indicates that the widget wants to
+ continue operating normally in "What's This?" mode. This is set by the
+ widget's author.
+
+ \value WA_DeleteOnClose Makes Qt delete this widget when the
+ widget has accepted the close event (see QWidget::closeEvent()).
+
+ \value WA_Disabled Indicates that the widget is disabled, i.e.
+ it does not receive any mouse or keyboard events. There is also a
+ getter functions QWidget::isEnabled(). This is set/cleared by the
+ Qt kernel.
+
+ \omitvalue WA_DropSiteRegistered
+ \omitvalue WA_ForceAcceptDrops
+
+ \value WA_ForceDisabled Indicates that the widget is
+ explicitly disabled, i.e. it will remain disabled even when all
+ its ancestors are set to the enabled state. This implies
+ WA_Disabled. This is set/cleared by QWidget::setEnabled() and
+ QWidget::setDisabled().
+
+ \value WA_ForceUpdatesDisabled Indicates that updates are
+ explicitly disabled for the widget; i.e. it will remain disabled
+ even when all its ancestors are set to the updates-enabled state.
+ This implies WA_UpdatesDisabled. This is set/cleared by
+ QWidget::setUpdatesEnabled().
+
+ \value WA_GroupLeader
+ \e{This attribute has been deprecated.} Use QWidget::windowModality
+ instead.
+
+ \value WA_Hover Forces Qt to generate paint events when the mouse
+ enters or leaves the widget. This feature is typically used when
+ implementing custom styles; see the \l{widgets/styles}{Styles}
+ example for details.
+
+ \value WA_InputMethodEnabled Enables input methods for Asian languages.
+ Must be set when creating custom text editing widgets.
+ On Windows CE this flag can be used in addition to
+ QApplication::autoSipEnabled to automatically display the SIP when
+ entering a widget.
+
+ \value WA_KeyboardFocusChange Set on a toplevel window when
+ the users changes focus with the keyboard (tab, backtab, or shortcut).
+
+ \value WA_KeyCompression Enables key event compression if set,
+ and disables it if not set. By default key compression is off, so
+ widgets receive one key press event for each key press (or more,
+ since autorepeat is usually on). If you turn it on and your
+ program doesn't keep up with key input, Qt may try to compress key
+ events so that more than one character can be processed in each
+ event.
+ For example, a word processor widget might receive 2, 3 or more
+ characters in each QKeyEvent::text(), if the layout recalculation
+ takes too long for the CPU.
+ If a widget supports multiple character unicode input, it is
+ always safe to turn the compression on.
+ Qt performs key event compression only for printable characters.
+ Qt::Modifier keys, cursor movement keys, function keys and
+ miscellaneous action keys (e.g. Escape, Enter, Backspace,
+ PrintScreen) will stop key event compression, even if there are
+ more compressible key events available.
+ Platforms other than Mac and X11 do not support this compression,
+ in which case turning it on will have no effect.
+ This is set/cleared by the widget's author.
+
+ \value WA_LayoutOnEntireRect Indicates that the widget
+ wants QLayout to operate on the entire QWidget::rect(), not only
+ on QWidget::contentsRect(). This is set by the widget's author.
+
+ \value WA_LayoutUsesWidgetRect Ignore the layout item rect from the style
+ when laying out this widget with QLayout. This makes a difference in
+ QMacStyle and QPlastiqueStyle for some widgets.
+
+ \value WA_MacNoClickThrough When a widget that has this attribute set
+ is clicked, and its window is inactive, the click will make the window
+ active but won't be seen by the widget. Typical use of this attribute
+ is on widgets with "destructive" actions, such as a "Delete" button.
+ WA_MacNoClickThrough also applies to all child widgets of the widget
+ that has it set.
+
+ \value WA_MacOpaqueSizeGrip Indicates that the native Carbon size grip
+ should be opaque instead of transparent (the default). This attribute
+ is only applicable to Mac OS X and is set by the widget's author.
+
+ \value WA_MacShowFocusRect Indicates that this widget should get a
+ QFocusFrame around it. Some widgets draw their own focus halo
+ regardless of this attribute. Not that the QWidget::focusPolicy
+ also plays the main role in whether something is given focus or
+ not, this only controls whether or not this gets the focus
+ frame. This attribute is only applicable to Mac OS X.
+
+ \value WA_MacNormalSize Indicates the widget should have the
+ normal size for widgets in Mac OS X. This attribute is only
+ applicable to Mac OS X.
+
+ \value WA_MacSmallSize Indicates the widget should have the small
+ size for widgets in Mac OS X. This attribute is only applicable to
+ Mac OS X.
+
+ \value WA_MacMiniSize Indicates the widget should have the mini
+ size for widgets in Mac OS X. This attribute is only applicable to
+ Mac OS X.
+
+ \value WA_MacVariableSize Indicates the widget can choose between
+ alternative sizes for widgets to avoid clipping.
+ This attribute is only applicable to Mac OS X.
+
+ \value WA_MacBrushedMetal Indicates the widget should be drawn in
+ the brushed metal style as supported by the windowing system. This
+ attribute is only applicable to Mac OS X.
+
+ \omitvalue WA_MacMetalStyle
+
+ \value WA_Mapped Indicates that the widget is mapped on screen.
+ This is set/cleared by the Qt kernel.
+
+ \value WA_MouseNoMask Makes the widget receive mouse events for
+ the entire widget regardless of the currently set mask,
+ overriding QWidget::setMask(). This is not applicable for
+ top-level windows.
+
+ \value WA_MouseTracking Indicates that the widget has mouse
+ tracking enabled. See QWidget::mouseTracking.
+
+ \value WA_Moved Indicates that the widget has an explicit
+ position. This is set/cleared by QWidget::move() and
+ by QWidget::setGeometry().
+
+ \value WA_MSWindowsUseDirect3D This value is obsolete and has no
+ effect.
+
+ \value WA_NoBackground This value is obsolete. Use
+ WA_OpaquePaintEvent instead.
+
+ \value WA_NoChildEventsForParent Indicates that the widget does
+ not want ChildAdded or ChildRemoved events sent to its
+ parent. This is rarely necessary but can help to avoid automatic
+ insertion widgets like splitters and layouts. This is set by a
+ widget's author.
+
+ \value WA_NoChildEventsFromChildren Indicates that the widget does
+ not want to receive ChildAdded or ChildRemoved events sent from its
+ children. This is set by a widget's author.
+
+ \value WA_NoMouseReplay Used for pop-up widgets. Indicates that the most
+ recent mouse press event should not be replayed when the pop-up widget
+ closes. The flag is set by the widget's author and cleared by the Qt kernel
+ every time the widget receives a new mouse event.
+
+ \value WA_NoMousePropagation Prohibits mouse events from being propagated
+ to the widget's parent. This attribute is disabled by default.
+
+ \value WA_TransparentForMouseEvents When enabled, this attribute disables
+ the delivery of mouse events to the widget and its children. Mouse events
+ are delivered to other widgets as if the widget and its children were not
+ present in the widget hierarchy; mouse clicks and other events effectively
+ "pass through" them. This attribute is disabled by default.
+
+ \value WA_NoSystemBackground Indicates that the widget has no background,
+ i.e. when the widget receives paint events, the background is not
+ automatically repainted. \note Unlike WA_OpaquePaintEvent, newly exposed
+ areas are \bold never filled with the background (e.g., after showing a
+ window for the first time the user can see "through" it until the
+ application processes the paint events). This flag is set or cleared by the
+ widget's author.
+
+ \value WA_OpaquePaintEvent Indicates that the widget paints all its pixels
+ when it receives a paint event. Thus, it is not required for operations
+ like updating, resizing, scrolling and focus changes to erase the widget
+ before generating paint events. The use of WA_OpaquePaintEvent provides a
+ small optimization by helping to reduce flicker on systems that do not
+ support double buffering and avoiding computational cycles necessary to
+ erase the background prior to painting. \note Unlike
+ WA_NoSystemBackground, WA_OpaquePaintEvent makes an effort to avoid
+ transparent window backgrounds. This flag is set or cleared by the widget's
+ author.
+
+ \value WA_OutsideWSRange Indicates that the widget is outside
+ the valid range of the window system's coordinate system. A widget
+ outside the valid range cannot be mapped on screen. This is
+ set/cleared by the Qt kernel.
+
+ \value WA_PaintOnScreen Indicates that the widget wants to draw directly
+ onto the screen. Widgets with this attribute set do not participate in
+ composition management, i.e. they cannot be semi-transparent or shine
+ through semi-transparent overlapping widgets. \note This flag is only
+ supported on X11 and it disables double buffering. On Qt for Embedded
+ Linux, the flag only works when set on a top-level widget and it relies on
+ support from the active screen driver. This flag is set or cleared by the
+ widget's author. To render outside of Qt's paint system, e.g., if you
+ require native painting primitives, you need to reimplement
+ QWidget::paintEngine() to return 0 and set this flag.
+
+ \value WA_PaintOutsidePaintEvent Makes it possible to use QPainter to
+ paint on the widget outside \l{QWidget::paintEvent()}{paintEvent()}. This
+ flag is not supported on Windows, Mac OS X or Embedded Linux. We recommend
+ that you use it only when porting Qt 3 code to Qt 4.
+
+ \value WA_PaintUnclipped Makes all painters operating on this widget
+ unclipped. Children of this widget or other widgets in front of it do not
+ clip the area the painter can paint on. This flag is only supported for
+ widgets with the WA_PaintOnScreen flag set. The preferred way to do this in
+ a cross platform way is to create a transparent widget that lies in front
+ of the other widgets.
+
+ \value WA_PendingMoveEvent Indicates that a move event is pending, e.g.,
+ when a hidden widget was moved. This flag is set or cleared by the Qt
+ kernel.
+
+ \value WA_PendingResizeEvent Indicates that a resize event is pending,
+ e.g., when a hidden widget was resized. This flag is set or cleared by the
+ Qt kernel.
+
+ \value WA_QuitOnClose Makes Qt quit the application when the last widget
+ with the attribute set has accepted closeEvent(). This behavior can be
+ modified with the QApplication::quitOnLastWindowClosed property. By default
+ this attribute is set for all widgets of type Qt::Window.
+
+ \value WA_Resized Indicates that the widget has an explicit size. This flag
+ is set or cleared by QWidget::resize() and QWidget::setGeometry().
+
+ \value WA_RightToLeft Indicates that the layout direction for the widget
+ is right to left.
+
+ \value WA_SetCursor Indicates that the widget has a cursor of its own. This
+ flag is set or cleared by QWidget::setCursor() and QWidget::unsetCursor().
+
+ \value WA_SetFont Indicates that the widget has a font of its own. This
+ flag is set or cleared by QWidget::setFont().
+
+ \value WA_SetPalette Indicates that the widget has a palette of its own.
+ This flag is set or cleared by QWidget::setPalette().
+
+ \value WA_SetStyle Indicates that the widget has a style of its own. This
+ flag is set or cleared by QWidget::setStyle().
+
+ \value WA_ShowModal \e{This attribute has been deprecated.} Use
+ QWidget::windowModality instead.
+
+ \value WA_StaticContents Indicates that the widget contents are north-west
+ aligned and static. On resize, such a widget will receive paint events only
+ for parts of itself that are newly visible. This flag is set or cleared by
+ the widget's author.
+
+ \value WA_StyleSheet Indicates that the widget is styled using a
+ \l{Qt Style Sheets}{style sheet}.
+
+ \value WA_TranslucentBackground Indicates that the widget should have a
+ translucent background, i.e., any non-opaque regions of the widgets will be
+ translucent because the widget will have an alpha channel. Setting this
+ flag causes WA_NoSystemBackground to be set. On Windows the
+ widget also needs the Qt::FramelessWindowHint window flag to be set.
+ This flag is set or cleared by the widget's author.
+
+ \value WA_UnderMouse Indicates that the widget is under the mouse cursor.
+ The value is not updated correctly during drag and drop operations. There
+ is also a getter function, QWidget::underMouse(). This flag is set or
+ cleared by the Qt kernel.
+
+ \value WA_UpdatesDisabled Indicates that updates are blocked (including the
+ system background). This flag is set or cleared by the Qt kernel.
+ \warning This flag must \e never be set or cleared by the widget's author.
+
+ \value WA_WindowModified Indicates that the window is marked as modified.
+ On some platforms this flag will do nothing, on others (including Mac OS X
+ and Windows) the window will take a modified appearance. This flag is set
+ or cleared by QWidget::setWindowModified().
+
+ \value WA_WindowPropagation Makes a toplevel window inherit font and
+ palette from its parent.
+
+ \value WA_MacAlwaysShowToolWindow On Mac OS X, show the tool window even
+ when the application is not active. By default, all tool windows are
+ hidden when the application is inactive.
+
+ \value WA_SetLocale Indicates the locale should be taken into consideration
+ in the widget.
+
+ \value WA_StyledBackground Indicates the widget should be drawn using a
+ styled background.
+
+ \value WA_ShowWithoutActivating Show the widget without making it active.
+
+ \value WA_NativeWindow Indicates that a native window is created for the
+ widget. Enabling this flag will also force a native window for the widget's
+ ancestors unless Qt::WA_DontCreateNativeAncestors is set.
+
+ \value WA_DontCreateNativeAncestors Indicates that the widget's ancestors
+ are kept non-native even though the widget itself is native.
+
+ \value WA_X11NetWmWindowTypeDesktop Adds _NET_WM_WINDOW_TYPE_DESKTOP to the
+ window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This attribute
+ has no effect on non-X11 platforms.
+
+ \value WA_X11NetWmWindowTypeDock Adds _NET_WM_WINDOW_TYPE_DOCK to the
+ window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This attribute
+ has no effect on non-X11 platforms.
+
+ \value WA_X11NetWmWindowTypeToolBar Adds _NET_WM_WINDOW_TYPE_TOOLBAR to the
+ window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This attribute
+ has no effect on non-X11 platforms. \note Qt automaticaly sets this
+ attribute for QToolBar.
+
+ \value WA_X11NetWmWindowTypeMenu Adds _NET_WM_WINDOW_TYPE_MENU to the
+ window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This attribute
+ has no effect on non-X11 platforms. \note Qt automatically sets this
+ attribute for QMenu when torn-off.
+
+ \value WA_X11NetWmWindowTypeUtility Adds _NET_WM_WINDOW_TYPE_UTILITY to the
+ window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This attribute
+ has no effect on non-X11 platforms. \note Qt automatically sets this
+ attribute for the Qt::Tool window type.
+
+ \value WA_X11NetWmWindowTypeSplash Adds _NET_WM_WINDOW_TYPE_SPLASH to the
+ window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This attribute
+ has no effect on non-X11 platforms. \note Qt automatically sets this
+ attribute for the Qt::SplashScreen window type.
+
+ \value WA_X11NetWmWindowTypeDialog Adds _NET_WM_WINDOW_TYPE_DIALOG
+ to the window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This
+ attribute has no effect on non-X11 platforms. \note Qt automatically sets
+ this attribute for the Qt::Dialog and Qt::Sheet window types.
+
+ \value WA_X11NetWmWindowTypeDropDownMenu Adds
+ _NET_WM_WINDOW_TYPE_DROPDOWN_MENU to the window's
+ _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This
+ attribute has no effect on non-X11 platforms. \note Qt
+ automatically sets this attribute for QMenus added to a QMenuBar.
+
+ \value WA_X11NetWmWindowTypePopupMenu Adds _NET_WM_WINDOW_TYPE_POPUP_MENU
+ to the window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This attribute
+ has no effect on non-X11 platforms. \note Qt automatically sets this
+ attribute for QMenu.
+
+ \value WA_X11NetWmWindowTypeToolTip Adds _NET_WM_WINDOW_TYPE_TOOLTIP to the
+ window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This attribute
+ has no effect on non-X11 platforms. \note Qt automatically sets this
+ attribute for the Qt::ToolTip window type.
+
+ \value WA_X11NetWmWindowTypeNotification Adds
+ _NET_WM_WINDOW_TYPE_NOTIFICATION to the window's _NET_WM_WINDOW_TYPE X11
+ window property. See http://standards.freedesktop.org/wm-spec/ for more
+ details. This attribute has no effect on non-X11 platforms.
+
+ \value WA_X11NetWmWindowTypeCombo Adds _NET_WM_WINDOW_TYPE_COMBO
+ to the window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This attribute
+ has no effect on non-X11 platforms. \note Qt automatically sets this
+ attribute for the QComboBox pop-up.
+
+ \value WA_X11NetWmWindowTypeDND Adds _NET_WM_WINDOW_TYPE_DND to
+ the window's _NET_WM_WINDOW_TYPE X11 window property. See
+ http://standards.freedesktop.org/wm-spec/ for more details. This attribute
+ has no effect on non-X11 platforms. \note Qt automatically sets this
+ attribute on the feedback widget used during a drag.
+
+ \value WA_MacFrameworkScaled Enables resolution independence aware mode
+ on Mac when using Carbon. This attribute has no effect on Cocoa.
+ The attribute is off by default and can be enabled on a per-window basis.
+
+ \value WA_AcceptTouchEvents Allows touch events (see QTouchEvent)
+ to be sent to the widget. Must be set on all widgets that can
+ handle touch events. Without this attribute set, events from a
+ touch device will be sent as mouse events.
+
+ \value WA_TouchPadAcceptSingleTouchEvents Allows touchpad single
+ touch events to be sent to the widget.
+
+ \omitvalue WA_SetLayoutDirection
+ \omitvalue WA_InputMethodTransparent
+ \omitvalue WA_WState_CompressKeys
+ \omitvalue WA_WState_ConfigPending
+ \omitvalue WA_WState_Created
+ \omitvalue WA_WState_DND
+ \omitvalue WA_WState_ExplicitShowHide
+ \omitvalue WA_WState_Hidden
+ \omitvalue WA_WState_InPaintEvent
+ \omitvalue WA_WState_OwnSizePolicy
+ \omitvalue WA_WState_Polished
+ \omitvalue WA_WState_Reparented
+ \omitvalue WA_WState_Visible
+ \omitvalue WA_SetWindowIcon
+ \omitvalue WA_PendingUpdate
+ \omitvalue WA_LaidOut
+ \omitvalue WA_GrabbedShortcut
+ \omitvalue WA_DontShowOnScreen
+ \omitvalue WA_InvalidSize
+ \omitvalue WA_ForceUpdatesDisabled
+ \omitvalue WA_NoX11EventCompression
+ \omitvalue WA_TintedBackground
+ \omitvalue WA_X11OpenGLOverlay
+ \omitvalue WA_CanHostQMdiSubWindowTitleBar
+ \omitvalue WA_AttributeCount
+ \omitvalue WA_StyleSheet
+ \omitvalue WA_X11BypassTransientForHint
+ \omitvalue WA_SetWindowModality
+ \omitvalue WA_WState_WindowOpacitySet
+ \omitvalue WA_WState_AcceptedTouchBeginEvent
+*/
+
+/*! \typedef Qt::HANDLE
+
+ Platform-specific handle type for system objects. This is
+ equivalent to \c{void *} on Mac OS X and embedded Linux,
+ and to \c{unsigned long} on X11. On Windows it is the
+ DWORD returned by the Win32 function getCurrentThreadId().
+
+ \warning Using this type is not portable.
+*/
+
+/*!
+ \enum Qt::Key
+
+ The key names used by Qt.
+
+ \value Key_Escape
+ \value Key_Tab
+ \value Key_Backtab
+ \omitvalue Key_BackTab
+ \value Key_Backspace
+ \omitvalue Key_BackSpace
+ \value Key_Return
+ \value Key_Enter Typically located on the keypad.
+ \value Key_Insert
+ \value Key_Delete
+ \value Key_Pause
+ \value Key_Print
+ \value Key_SysReq
+ \value Key_Clear
+ \value Key_Home
+ \value Key_End
+ \value Key_Left
+ \value Key_Up
+ \value Key_Right
+ \value Key_Down
+ \value Key_PageUp
+ \omitvalue Key_Prior
+ \value Key_PageDown
+ \omitvalue Key_Next
+ \value Key_Shift
+ \value Key_Control On Mac OS X, this corresponds to the Command keys.
+ \value Key_Meta On Mac OS X, this corresponds to the Control keys.
+ On Windows keyboards, this key is mapped to the
+ Windows key.
+ \value Key_Alt
+ \value Key_AltGr On Windows, when the KeyDown event for this key is
+ sent, the Ctrl+Alt modifiers are also set.
+ \value Key_CapsLock
+ \value Key_NumLock
+ \value Key_ScrollLock
+ \value Key_F1
+ \value Key_F2
+ \value Key_F3
+ \value Key_F4
+ \value Key_F5
+ \value Key_F6
+ \value Key_F7
+ \value Key_F8
+ \value Key_F9
+ \value Key_F10
+ \value Key_F11
+ \value Key_F12
+ \value Key_F13
+ \value Key_F14
+ \value Key_F15
+ \value Key_F16
+ \value Key_F17
+ \value Key_F18
+ \value Key_F19
+ \value Key_F20
+ \value Key_F21
+ \value Key_F22
+ \value Key_F23
+ \value Key_F24
+ \value Key_F25
+ \value Key_F26
+ \value Key_F27
+ \value Key_F28
+ \value Key_F29
+ \value Key_F30
+ \value Key_F31
+ \value Key_F32
+ \value Key_F33
+ \value Key_F34
+ \value Key_F35
+ \value Key_Super_L
+ \value Key_Super_R
+ \value Key_Menu
+ \value Key_Hyper_L
+ \value Key_Hyper_R
+ \value Key_Help
+ \value Key_Direction_L
+ \value Key_Direction_R
+ \value Key_Space
+ \value Key_Any
+ \value Key_Exclam
+ \value Key_QuoteDbl
+ \value Key_NumberSign
+ \value Key_Dollar
+ \value Key_Percent
+ \value Key_Ampersand
+ \value Key_Apostrophe
+ \value Key_ParenLeft
+ \value Key_ParenRight
+ \value Key_Asterisk
+ \value Key_Plus
+ \value Key_Comma
+ \value Key_Minus
+ \value Key_Period
+ \value Key_Slash
+ \value Key_0
+ \value Key_1
+ \value Key_2
+ \value Key_3
+ \value Key_4
+ \value Key_5
+ \value Key_6
+ \value Key_7
+ \value Key_8
+ \value Key_9
+ \value Key_Colon
+ \value Key_Semicolon
+ \value Key_Less
+ \value Key_Equal
+ \value Key_Greater
+ \value Key_Question
+ \value Key_At
+ \value Key_A
+ \value Key_B
+ \value Key_C
+ \value Key_D
+ \value Key_E
+ \value Key_F
+ \value Key_G
+ \value Key_H
+ \value Key_I
+ \value Key_J
+ \value Key_K
+ \value Key_L
+ \value Key_M
+ \value Key_N
+ \value Key_O
+ \value Key_P
+ \value Key_Q
+ \value Key_R
+ \value Key_S
+ \value Key_T
+ \value Key_U
+ \value Key_V
+ \value Key_W
+ \value Key_X
+ \value Key_Y
+ \value Key_Z
+ \value Key_BracketLeft
+ \value Key_Backslash
+ \value Key_BracketRight
+ \value Key_AsciiCircum
+ \value Key_Underscore
+ \value Key_QuoteLeft
+ \value Key_BraceLeft
+ \value Key_Bar
+ \value Key_BraceRight
+ \value Key_AsciiTilde
+ \value Key_nobreakspace
+ \value Key_exclamdown
+ \value Key_cent
+ \value Key_sterling
+ \value Key_currency
+ \value Key_yen
+ \value Key_brokenbar
+ \value Key_section
+ \value Key_diaeresis
+ \value Key_copyright
+ \value Key_ordfeminine
+ \value Key_guillemotleft
+ \value Key_notsign
+ \value Key_hyphen
+ \value Key_registered
+ \value Key_macron
+ \value Key_degree
+ \value Key_plusminus
+ \value Key_twosuperior
+ \value Key_threesuperior
+ \value Key_acute
+ \value Key_mu
+ \value Key_paragraph
+ \value Key_periodcentered
+ \value Key_cedilla
+ \value Key_onesuperior
+ \value Key_masculine
+ \value Key_guillemotright
+ \value Key_onequarter
+ \value Key_onehalf
+ \value Key_threequarters
+ \value Key_questiondown
+ \value Key_Agrave
+ \value Key_Aacute
+ \value Key_Acircumflex
+ \value Key_Atilde
+ \value Key_Adiaeresis
+ \value Key_Aring
+ \value Key_AE
+ \value Key_Ccedilla
+ \value Key_Egrave
+ \value Key_Eacute
+ \value Key_Ecircumflex
+ \value Key_Ediaeresis
+ \value Key_Igrave
+ \value Key_Iacute
+ \value Key_Icircumflex
+ \value Key_Idiaeresis
+ \value Key_ETH
+ \value Key_Ntilde
+ \value Key_Ograve
+ \value Key_Oacute
+ \value Key_Ocircumflex
+ \value Key_Otilde
+ \value Key_Odiaeresis
+ \value Key_multiply
+ \value Key_Ooblique
+ \value Key_Ugrave
+ \value Key_Uacute
+ \value Key_Ucircumflex
+ \value Key_Udiaeresis
+ \value Key_Yacute
+ \value Key_THORN
+ \value Key_ssharp
+ \omitvalue Key_agrave
+ \omitvalue Key_aacute
+ \omitvalue Key_acircumflex
+ \omitvalue Key_atilde
+ \omitvalue Key_adiaeresis
+ \omitvalue Key_aring
+ \omitvalue Key_ae
+ \omitvalue Key_ccedilla
+ \omitvalue Key_egrave
+ \omitvalue Key_eacute
+ \omitvalue Key_ecircumflex
+ \omitvalue Key_ediaeresis
+ \omitvalue Key_igrave
+ \omitvalue Key_iacute
+ \omitvalue Key_icircumflex
+ \omitvalue Key_idiaeresis
+ \omitvalue Key_eth
+ \omitvalue Key_ntilde
+ \omitvalue Key_ograve
+ \omitvalue Key_oacute
+ \omitvalue Key_ocircumflex
+ \omitvalue Key_otilde
+ \omitvalue Key_odiaeresis
+ \value Key_division
+ \omitvalue Key_oslash
+ \omitvalue Key_ugrave
+ \omitvalue Key_uacute
+ \omitvalue Key_ucircumflex
+ \omitvalue Key_udiaeresis
+ \omitvalue Key_yacute
+ \omitvalue Key_thorn
+ \value Key_ydiaeresis
+ \value Key_Multi_key
+ \value Key_Codeinput
+ \value Key_SingleCandidate
+ \value Key_MultipleCandidate
+ \value Key_PreviousCandidate
+ \value Key_Mode_switch
+ \value Key_Kanji
+ \value Key_Muhenkan
+ \value Key_Henkan
+ \value Key_Romaji
+ \value Key_Hiragana
+ \value Key_Katakana
+ \value Key_Hiragana_Katakana
+ \value Key_Zenkaku
+ \value Key_Hankaku
+ \value Key_Zenkaku_Hankaku
+ \value Key_Touroku
+ \value Key_Massyo
+ \value Key_Kana_Lock
+ \value Key_Kana_Shift
+ \value Key_Eisu_Shift
+ \value Key_Eisu_toggle
+ \value Key_Hangul
+ \value Key_Hangul_Start
+ \value Key_Hangul_End
+ \value Key_Hangul_Hanja
+ \value Key_Hangul_Jamo
+ \value Key_Hangul_Romaja
+ \value Key_Hangul_Jeonja
+ \value Key_Hangul_Banja
+ \value Key_Hangul_PreHanja
+ \value Key_Hangul_PostHanja
+ \value Key_Hangul_Special
+ \value Key_Dead_Grave
+ \value Key_Dead_Acute
+ \value Key_Dead_Circumflex
+ \value Key_Dead_Tilde
+ \value Key_Dead_Macron
+ \value Key_Dead_Breve
+ \value Key_Dead_Abovedot
+ \value Key_Dead_Diaeresis
+ \value Key_Dead_Abovering
+ \value Key_Dead_Doubleacute
+ \value Key_Dead_Caron
+ \value Key_Dead_Cedilla
+ \value Key_Dead_Ogonek
+ \value Key_Dead_Iota
+ \value Key_Dead_Voiced_Sound
+ \value Key_Dead_Semivoiced_Sound
+ \value Key_Dead_Belowdot
+ \value Key_Dead_Hook
+ \value Key_Dead_Horn
+ \value Key_Back
+ \value Key_Forward
+ \value Key_Stop
+ \value Key_Refresh
+ \value Key_VolumeDown
+ \value Key_VolumeMute
+ \value Key_VolumeUp
+ \value Key_BassBoost
+ \value Key_BassUp
+ \value Key_BassDown
+ \value Key_TrebleUp
+ \value Key_TrebleDown
+ \value Key_MediaPlay
+ \value Key_MediaStop
+ \value Key_MediaPrevious
+ \omitvalue Key_MediaPrev
+ \value Key_MediaNext
+ \value Key_MediaRecord
+ \value Key_HomePage
+ \value Key_Favorites
+ \value Key_Search
+ \value Key_Standby
+ \value Key_OpenUrl
+ \value Key_LaunchMail
+ \value Key_LaunchMedia
+ \value Key_Launch0
+ \value Key_Launch1
+ \value Key_Launch2
+ \value Key_Launch3
+ \value Key_Launch4
+ \value Key_Launch5
+ \value Key_Launch6
+ \value Key_Launch7
+ \value Key_Launch8
+ \value Key_Launch9
+ \value Key_LaunchA
+ \value Key_LaunchB
+ \value Key_LaunchC
+ \value Key_LaunchD
+ \value Key_LaunchE
+ \value Key_LaunchF
+ \value Key_MediaLast
+ \value Key_unknown
+
+ \value Key_Call
+ \value Key_Context1
+ \value Key_Context2
+ \value Key_Context3
+ \value Key_Context4
+ \value Key_Flip
+ \value Key_Hangup
+ \value Key_No
+ \value Key_Select
+ \value Key_Yes
+
+ \value Key_Execute
+ \value Key_Printer
+ \value Key_Play
+ \value Key_Sleep
+ \value Key_Zoom
+ \value Key_Cancel
+
+ \sa QKeyEvent::key()
+*/
+
+/*!
+ \enum Qt::HitTestAccuracy
+
+ This enum contains the types of accuracy that can be used by the
+ QTextDocument class when testing for mouse clicks on text documents.
+
+ \value ExactHit The point at which input occurred must coincide
+ exactly with input-sensitive parts of the document.
+ \value FuzzyHit The point at which input occurred can lie close to
+ input-sensitive parts of the document.
+
+ This enum is defined in the \c <QTextDocument> header file.
+*/
+
+/*!
+ \enum Qt::WhiteSpaceMode
+
+ This enum describes the types of whitespace mode that are used by
+ the QTextDocument class to meet the requirements of different kinds
+ of textual information.
+
+ \value WhiteSpaceNormal The whitespace mode used to display
+ normal word wrapped text in paragraphs.
+ \value WhiteSpacePre A preformatted text mode in which
+ whitespace is reproduced exactly.
+ \value WhiteSpaceNoWrap
+
+ \omitvalue WhiteSpaceModeUndefined
+
+ This enum is defined in the \c <QTextDocument> header file.
+*/
+
+/*!
+ \enum Qt::ButtonState_enum
+ \compat
+ \value ShiftButton
+ \value ControlButton
+ \value AltButton
+ \value MetaButton
+ \value Keypad
+ \value KeyButtonMask
+
+ Use Qt::KeyboardModifier instead.
+*/
+
+/*!
+ \typedef Qt::ButtonState
+ \compat
+
+ Use Qt::KeyboardModifier instead.
+*/
+
+/*!
+ \enum Qt::CheckState
+
+ This enum describes the state of checkable items, controls, and widgets.
+
+ \value Unchecked The item is unchecked.
+ \value PartiallyChecked The item is partially checked. Items in hierarchical models
+ may be partially checked if some, but not all, of their
+ children are checked.
+ \value Checked The item is checked.
+
+ \sa QCheckBox, Qt::ItemFlags, Qt::ItemDataRole
+*/
+
+
+/*!
+ \enum Qt::ToolButtonStyle
+
+ The style of the tool button, describing how the button's text and
+ icon should be displayed.
+
+ \value ToolButtonIconOnly Only display the icon.
+ \value ToolButtonTextOnly Only display the text.
+ \value ToolButtonTextBesideIcon The text appears beside the icon.
+ \value ToolButtonTextUnderIcon The text appears under the icon.
+ \value ToolButtonFollowStyle Follow the \l{QStyle::SH_ToolButtonStyle}{style}.
+*/
+
+/*!
+ \enum Qt::Corner
+
+ This enum type specifies a corner in a rectangle:
+
+ \value TopLeftCorner The top-left corner of the rectangle.
+ \value TopRightCorner The top-right corner of the rectangle.
+ \value BottomLeftCorner The bottom-left corner of the rectangle.
+ \value BottomRightCorner The bottom-right corner of the rectangle.
+
+ \omitvalue TopLeft
+ \omitvalue TopRight
+ \omitvalue BottomLeft
+ \omitvalue BottomRight
+*/
+
+/*!
+ \enum Qt::ScrollBarPolicy
+
+ This enum type describes the various modes of QAbstractScrollArea's scroll
+ bars.
+
+ \value ScrollBarAsNeeded QAbstractScrollArea shows a scroll bar when the
+ content is too large to fit and not otherwise. This is the
+ default.
+
+ \value ScrollBarAlwaysOff QAbstractScrollArea never shows a scroll bar.
+
+ \value ScrollBarAlwaysOn QAbstractScrollArea always shows a scroll bar.
+
+ (The modes for the horizontal and vertical scroll bars are
+ independent.)
+*/
+
+/*!
+ \enum Qt::ArrowType
+
+ \value NoArrow
+ \value UpArrow
+ \value DownArrow
+ \value LeftArrow
+ \value RightArrow
+*/
+
+/*!
+ \enum Qt::FocusReason
+
+ This enum specifies why the focus changed. It will be passed
+ through QWidget::setFocus and can be retrieved in the QFocusEvent
+ sent to the widget upon focus change.
+
+ \value MouseFocusReason A mouse action occurred.
+ \value TabFocusReason The Tab key was pressed.
+ \value BacktabFocusReason A Backtab occurred. The input for this may
+ include the Shift or Control keys;
+ e.g. Shift+Tab.
+ \value ActiveWindowFocusReason The window system made this window either
+ active or inactive.
+ \value PopupFocusReason The application opened/closed a pop-up that
+ grabbed/released the keyboard focus.
+ \value ShortcutFocusReason The user typed a label's buddy shortcut
+ \value MenuBarFocusReason The menu bar took focus.
+ \value OtherFocusReason Another reason, usually application-specific.
+
+ \omitvalue NoFocusReason
+
+ \sa {Keyboard Focus}
+*/
+
+/*!
+ \enum Qt::WindowState
+
+ \keyword window state
+
+ This enum type is used to specify the current state of a top-level
+ window.
+
+ The states are
+
+ \value WindowNoState The window has no state set (in normal state).
+ \value WindowMinimized The window is minimized (i.e. iconified).
+ \value WindowMaximized The window is maximized with a frame around it.
+ \value WindowFullScreen The window fills the entire screen without any frame around it.
+ \value WindowActive The window is the active window, i.e. it has keyboard focus.
+
+*/
+
+/*!
+ \enum Qt::ContextMenuPolicy
+
+ This enum type defines the various policies a widget can have with
+ respect to showing a context menu.
+
+ \value NoContextMenu the widget does not feature a context menu,
+ context menu handling is deferred to the widget's parent.
+ \value PreventContextMenu the widget does not feature a context
+ menu, and in contrast to \c NoContextMenu, the handling is \e not
+ deferred to the widget's parent. This means that all right mouse
+ button events are guaranteed to be delivered to the widget itself
+ through mousePressEvent(), and mouseReleaseEvent().
+ \value DefaultContextMenu the widget's QWidget::contextMenuEvent() handler is called.
+ \value ActionsContextMenu the widget displays its QWidget::actions() as context menu.
+ \value CustomContextMenu the widget emits the QWidget::customContextMenuRequested() signal.
+*/
+
+/*!
+ \enum Qt::FocusPolicy
+
+ This enum type defines the various policies a widget can have with
+ respect to acquiring keyboard focus.
+
+ \value TabFocus the widget accepts focus by tabbing.
+ \value ClickFocus the widget accepts focus by clicking.
+ \value StrongFocus the widget accepts focus by both tabbing
+ and clicking. On Mac OS X this will also
+ be indicate that the widget accepts tab focus
+ when in 'Text/List focus mode'.
+ \value WheelFocus like Qt::StrongFocus plus the widget accepts
+ focus by using the mouse wheel.
+ \value NoFocus the widget does not accept focus.
+
+*/
+
+/*!
+ \enum Qt::ShortcutContext
+
+ For a QEvent::Shortcut event to occur, the shortcut's key sequence
+ must be entered by the user in a context where the shortcut is
+ active. The possible contexts are these:
+
+ \value WidgetShortcut The shortcut is active when its
+ parent widget has focus.
+ \value WidgetWithChildrenShortcut The shortcut is active
+ when its parent widget, or any of its children has focus.
+ Children which are top-level widgets, except pop-ups, are
+ not affected by this shortcut context.
+ \value WindowShortcut The shortcut is active when its
+ parent widget is a logical subwidget of the
+ active top-level window.
+ \value ApplicationShortcut The shortcut is active when one of
+ the applications windows are active.
+*/
+
+/*!
+ \typedef Qt::WFlags
+
+ Synonym for Qt::WindowFlags.
+*/
+
+/*!
+ \enum Qt::WindowType
+
+ \keyword window flag
+
+ This enum type is used to specify various window-system properties
+ for the widget. They are fairly unusual but necessary in a few
+ cases. Some of these flags depend on whether the underlying window
+ manager supports them.
+
+ The main types are
+
+ \value Widget This is the default type for QWidget. Widgets of
+ this type are child widgets if they have a parent,
+ and independent windows if they have no parent.
+ See also Qt::Window and Qt::SubWindow.
+
+ \value Window Indicates that the widget is a window, usually
+ with a window system frame and a title bar,
+ irrespective of whether the widget has a parent or
+ not. Note that it is not possible to unset this
+ flag if the widget does not have a parent.
+
+ \value Dialog Indicates that the widget is a window that should
+ be decorated as a dialog (i.e., typically no
+ maximize or minimize buttons in the title bar).
+ This is the default type for QDialog. If you want
+ to use it as a modal dialog, it should be launched
+ from another window, or have a parent and used
+ with the QWidget::windowModality property. If you make
+ it modal, the dialog will prevent other top-level
+ windows in the application from getting any input.
+ We refer to a top-level window that has a parent
+ as a \e secondary window.
+
+ \value Sheet Indicates that the window is a Macintosh sheet. Since
+ using a sheet implies window modality, the recommended
+ way is to use QWidget::setWindowModality(), or
+ QDialog::open(), instead.
+
+ \value Drawer Indicates that the widget is a Macintosh drawer.
+
+ \value Popup Indicates that the widget is a pop-up top-level
+ window, i.e. that it is modal, but has a window
+ system frame appropriate for pop-up menus.
+
+ \value Tool Indicates that the widget is a tool window. A tool
+ window is often a small window with a smaller than
+ usual title bar and decoration, typically used for
+ collections of tool buttons. It there is a parent,
+ the tool window will always be kept on top of it.
+ If there isn't a parent, you may consider using
+ Qt::WindowStaysOnTopHint as well. If the window
+ system supports it, a tool window can be decorated
+ with a somewhat lighter frame. It can also be
+ combined with Qt::FramelessWindowHint.
+ \br
+ \br
+ On Mac OS X, tool windows correspond to the
+ \l{http://developer.apple.com/documentation/Carbon/Conceptual/HandlingWindowsControls/hitb-wind_cont_concept/chapter_2_section_2.html}{Floating}
+ class of windows. This means that the window lives on a
+ level above normal windows; it impossible to put a normal
+ window on top of it. By default, tool windows will disappear
+ when the application is inactive. This can be controlled by
+ the Qt::WA_MacAlwaysShowToolWindow attribute.
+
+ \value ToolTip Indicates that the widget is a tooltip. This is
+ used internally to implement
+ \l{QWidget::toolTip}{tooltips}.
+
+ \value SplashScreen Indicates that the window is a splash screen.
+ This is the default type for QSplashScreen.
+
+ \value Desktop Indicates that this widget is the desktop. This
+ is the type for QDesktopWidget.
+
+ \value SubWindow Indicates that this widget is a sub-window, such
+ as a QMdiSubWindow widget.
+
+ There are also a number of flags which you can use to customize
+ the appearance of top-level windows. These have no effect on other
+ windows:
+
+ \value MSWindowsFixedSizeDialogHint Gives the window a thin dialog border on Windows.
+ This style is traditionally used for fixed-size dialogs.
+
+ \value MSWindowsOwnDC Gives the window its own display
+ context on Windows.
+
+ \value X11BypassWindowManagerHint Bypass the window
+ manager completely. This results in a borderless window
+ that is not managed at all (i.e., no keyboard input unless
+ you call QWidget::activateWindow() manually).
+
+ \value FramelessWindowHint Produces a borderless window.
+ The user cannot move or resize a borderless window via the window
+ system. On X11, the result of the flag is dependent on the window manager and its
+ ability to understand Motif and/or NETWM hints. Most existing
+ modern window managers can handle this.
+
+ The \c CustomizeWindowHint flag is used to enable customization of
+ the window controls. This flag must be set to allow the \c
+ WindowTitleHint, \c WindowSystemMenuHint, \c
+ WindowMinimizeButtonHint, \c WindowMaximizeButtonHint and \c
+ WindowCloseButtonHint flags to be changed.
+
+ \value CustomizeWindowHint Turns off the default window title hints.
+
+ \value WindowTitleHint Gives the window a title bar.
+
+ \value WindowSystemMenuHint Adds a window system menu, and
+ possibly a close button (for example on Mac). If you need to hide
+ or show a close button, it is more portable to use \c
+ WindowCloseButtonHint.
+
+ \value WindowMinimizeButtonHint Adds a minimize button. On
+ some platforms this implies Qt::WindowSystemMenuHint for it to work.
+
+ \value WindowMaximizeButtonHint Adds a maximize button. On
+ some platforms this implies Qt::WindowSystemMenuHint for it to work.
+
+ \value WindowMinMaxButtonsHint Adds a minimize and a maximize
+ button. On some platforms this implies Qt::WindowSystemMenuHint for it to work.
+
+ \value WindowCloseButtonHint Adds a close button. On
+ some platforms this implies Qt::WindowSystemMenuHint for it
+ to work.
+
+ \value WindowContextHelpButtonHint Adds a context help button to dialogs.
+ On some platforms this implies Qt::WindowSystemMenuHint for it to work.
+
+ \value MacWindowToolBarButtonHint On Mac OS X adds a tool bar button (i.e.,
+ the oblong button that is on the top right of windows that have toolbars.
+
+ \value BypassGraphicsProxyWidget Prevents the window and its children from
+ automatically embedding themselves into a QGraphicsProxyWidget if the
+ parent widget is already embedded. You can set this flag if you
+ want your widget to always be a toplevel widget on the desktop,
+ regardless of whether the parent widget is embedded in a scene or
+ not.
+
+ \value WindowShadeButtonHint
+
+ \value WindowStaysOnTopHint Informs the window system that the
+ window should stay on top of all other windows. Note that
+ on some window managers on X11 you also have to pass
+ Qt::X11BypassWindowManagerHint for this flag to work
+ correctly.
+
+ \value WindowStaysOnBottomHint Informs the window system that the
+ window should stay on bottom of all other windows. Note
+ that on X11 this hint will work only in window managers
+ that support _NET_WM_STATE_BELOW atom. If a window always
+ on the bottom has a parent, the parent will also be left on
+ the bottom. This window hint is currently not implemented
+ for Mac OS X.
+
+ \value WindowOkButtonHint Adds an OK button to the window decoration of a dialog.
+ Only supported for Windows CE.
+
+ \value WindowCancelButtonHint Adds a Cancel button to the window decoration of a dialog.
+ Only supported for Windows CE.
+
+ \value WindowType_Mask A mask for extracting the window type
+ part of the window flags.
+
+ Obsolete flags:
+
+ \value WMouseNoMask Use Qt::WA_MouseNoMask instead.
+ \value WDestructiveClose Use Qt::WA_DeleteOnClose instead.
+ \value WStaticContents Use Qt::WA_StaticContents instead.
+ \value WGroupLeader No longer needed.
+ \value WShowModal Use QWidget::windowModality instead.
+ \value WNoMousePropagation Use Qt::WA_NoMousePropagation instead.
+ \value WType_TopLevel Use Qt::Window instead.
+ \value WType_Dialog Use Qt::Dialog instead.
+ \value WType_Popup Use Qt::Popup instead.
+ \value WType_Desktop Use Qt::Desktop instead.
+ \value WType_Mask Use Qt::WindowType_Mask instead.
+
+ \value WStyle_Customize No longer needed.
+ \value WStyle_NormalBorder No longer needed.
+ \value WStyle_DialogBorder Use Qt::MSWindowsFixedSizeDialogHint instead.
+ \value WStyle_NoBorder Use Qt::FramelessWindowHint instead.
+ \value WStyle_Title Use Qt::WindowTitleHint instead.
+ \value WStyle_SysMenu Use Qt::WindowSystemMenuHint instead.
+ \value WStyle_Minimize Use Qt::WindowMinimizeButtonHint instead.
+ \value WStyle_Maximize Use Qt::WindowMaximizeButtonHint instead.
+ \value WStyle_MinMax Use Qt::WindowMinMaxButtonsHint instead.
+ \value WStyle_Tool Use Qt::Tool instead.
+ \value WStyle_StaysOnTop Use Qt::WindowStaysOnTopHint instead.
+ \value WStyle_ContextHelp Use Qt::WindowContextHelpButtonHint instead.
+
+ \value WPaintDesktop No longer needed.
+ \value WPaintClever No longer needed.
+
+ \value WX11BypassWM Use Qt::X11BypassWindowManagerHint instead.
+ \value WWinOwnDC Use Qt::MSWindowsOwnDC instead.
+ \value WMacSheet Use Qt::Sheet instead.
+ \value WMacDrawer Use Qt::Drawer instead.
+
+ \value WStyle_Splash Use Qt::SplashScreen instead.
+
+ \value WNoAutoErase No longer needed.
+ \value WRepaintNoErase No longer needed.
+ \value WNorthWestGravity Use Qt::WA_StaticContents instead.
+ \value WType_Modal Use Qt::Dialog and QWidget::windowModality instead.
+ \value WStyle_Dialog Use Qt::Dialog instead.
+ \value WStyle_NoBorderEx Use Qt::FramelessWindowHint instead.
+ \value WResizeNoErase No longer needed.
+ \value WMacNoSheet No longer needed.
+
+ \sa QWidget::windowFlags, {Window Flags Example}
+*/
+
+/*!
+ \enum Qt::DropAction
+
+ \value CopyAction Copy the data to the target.
+ \value MoveAction Move the data from the source to the target.
+ \value LinkAction Create a link from the source to the target.
+ \value ActionMask
+ \value IgnoreAction Ignore the action (do nothing with the data).
+ \value TargetMoveAction On Windows, this value is used when the ownership of the D&D data
+ should be taken over by the target application,
+ i.e., the source application should not delete
+ the data.
+ \br
+ On X11 this value is used to do a move.
+ \br
+ TargetMoveAction is not used on the Mac.
+*/
+
+#if defined(Q_OS_WIN) && defined(QT3_SUPPORT)
+/*!
+ \enum Qt::WindowsVersion
+ \compat
+
+ \value WV_32s
+ \value WV_95
+ \value WV_98
+ \value WV_Me
+ \value WV_DOS_based
+ \value WV_NT
+ \value WV_2000
+ \value WV_XP
+ \value WV_2003
+ \value WV_NT_based
+ \value WV_CE
+ \value WV_CENET
+ \value WV_CE_based
+ \value WV_CE_5
+ \value WV_CE_6
+*/
+#endif
+
+#if defined(Q_OS_MAC) && defined(QT3_SUPPORT)
+/*!
+ \enum Qt::MacintoshVersion
+ \compat
+
+ \value MV_Unknown Use QSysInfo::MV_Unknown instead.
+ \value MV_9 Use QSysInfo::MV_9 instead.
+ \value MV_10_DOT_0 Use QSysInfo::MV_10_0 instead.
+ \value MV_10_DOT_1 Use QSysInfo::MV_10_1 instead.
+ \value MV_10_DOT_2 Use QSysInfo::MV_10_2 instead.
+ \value MV_10_DOT_3 Use QSysInfo::MV_10_3 instead.
+ \value MV_10_DOT_4 Use QSysInfo::MV_10_4 instead.
+
+ \value MV_CHEETAH Use QSysInfo::MV_10_0 instead.
+ \value MV_PUMA Use QSysInfo::MV_10_1 instead.
+ \value MV_JAGUAR Use QSysInfo::MV_10_2 instead.
+ \value MV_PANTHER Use QSysInfo::MV_10_3 instead.
+ \value MV_TIGER Use QSysInfo::MV_10_4 instead.
+
+ \sa QSysInfo::MacVersion
+*/
+#endif
+
+/*! \typedef Qt::ToolBarDock
+ \compat
+
+ Use Qt::Dock instead.
+*/
+
+/*!
+ \enum Qt::Dock
+ \compat
+
+ Each dock window can be in one of the following positions:
+
+ \value DockUnmanaged not managed by a Q3MainWindow.
+
+ \value DockTornOff the dock window floats as its own top level
+ window which always stays on top of the main window.
+
+ \value DockTop above the central widget, below the menu bar.
+
+ \value DockBottom below the central widget, above the status bar.
+
+ \value DockRight to the right of the central widget.
+
+ \value DockLeft to the left of the central widget.
+
+ \value DockMinimized the dock window is not shown (this is
+ effectively a 'hidden' dock area); the handles of all minimized
+ dock windows are drawn in one row below the menu bar.
+
+ \omitvalue Bottom
+ \omitvalue Left
+ \omitvalue Minimized
+ \omitvalue Right
+ \omitvalue Top
+ \omitvalue TornOff
+ \omitvalue Unmanaged
+*/
+
+/*!
+ \enum Qt::AnchorAttribute
+
+ An anchor has one or more of the following attributes:
+
+ \value AnchorName the name attribute of the anchor. This attribute is
+ used when scrolling to an anchor in the document.
+
+ \value AnchorHref the href attribute of the anchor. This attribute is
+ used when a link is clicked to determine what content to load.
+*/
+
+/*!
+ \enum Qt::SortOrder
+
+ This enum describes how the items in a widget are sorted.
+
+ \value AscendingOrder The items are sorted ascending e.g. starts with
+ 'AAA' ends with 'ZZZ' in Latin-1 locales
+
+ \value DescendingOrder The items are sorted descending e.g. starts with
+ 'ZZZ' ends with 'AAA' in Latin-1 locales
+
+ \omitvalue Ascending
+ \omitvalue Descending
+*/
+
+/*!
+ \enum Qt::ClipOperation
+
+ \value NoClip This operation turns clipping off.
+
+ \value ReplaceClip Replaces the current clip path/rect/region with
+ the one supplied in the function call.
+
+ \value IntersectClip Intersects the current clip path/rect/region
+ with the one supplied in the function call.
+
+ \value UniteClip Unites the current clip path/rect/region with the
+ one supplied in the function call.
+*/
+
+/*!
+ \enum Qt::ItemSelectionMode
+
+ This enum is used in QGraphicsItem, QGraphicsScene and QGraphicsView to
+ specify how items are selected, or how to determine if a shapes and items
+ collide.
+
+ \value ContainsItemShape The output list contains only items whose
+ \l{QGraphicsItem::shape()}{shape} is fully contained inside the
+ selection area. Items that intersect with the area's outline are
+ not included.
+
+ \value IntersectsItemShape The output list contains both items whose
+ \l{QGraphicsItem::shape()}{shape} is fully contained inside the
+ selection area, and items that intersect with the area's
+ outline. This is a common mode for rubber band selection.
+
+ \value ContainsItemBoundingRect The output list contains only items whose
+ \l{QGraphicsItem::boundingRect()}{bounding rectangle} is fully
+ contained inside the selection area. Items that intersect with the
+ area's outline are not included.
+
+ \value IntersectsItemBoundingRect The output list contains both items
+ whose \l{QGraphicsItem::boundingRect()}{bounding rectangle} is
+ fully contained inside the selection area, and items that intersect
+ with the area's outline. This method is commonly used for
+ determining areas that need redrawing.
+
+ \sa QGraphicsScene::items(), QGraphicsScene::collidingItems(),
+ QGraphicsView::items(), QGraphicsItem::collidesWithItem(),
+ QGraphicsItem::collidesWithPath()
+*/
+
+/*!
+ \enum Qt::FillRule
+
+ Specifies which method should be used to fill the paths and polygons.
+
+ \value OddEvenFill Specifies that the region is filled using the
+ odd even fill rule. With this rule, we determine whether a point
+ is inside the shape by using the following method.
+ Draw a horizontal line from the point to a location outside the shape,
+ and count the number of intersections. If the number of intersections
+ is an odd number, the point is inside the shape. This mode is the
+ default.
+
+ \value WindingFill Specifies that the region is filled using the
+ non zero winding rule. With this rule, we determine whether a
+ point is inside the shape by using the following method.
+ Draw a horizontal line from the point to a location outside the shape.
+ Determine whether the direction of the line at each intersection point
+ is up or down. The winding number is determined by summing the
+ direction of each intersection. If the number is non zero, the point
+ is inside the shape. This fill mode can also in most cases be considered
+ as the intersection of closed shapes.
+*/
+
+/*!
+ \enum Qt::PaintUnit
+
+ \compat
+
+ \value PixelUnit
+ \value LoMetricUnit Obsolete
+ \value HiMetricUnit Obsolete
+ \value LoEnglishUnit Obsolete
+ \value HiEnglishUnit Obsolete
+ \value TwipsUnit Obsolete
+*/
+
+/*!
+ \enum Qt::TextFormat
+
+ This enum is used in widgets that can display both plain text and
+ rich text, e.g. QLabel. It is used for deciding whether a text
+ string should be interpreted as one or the other. This is normally
+ done by passing one of the enum values to a setTextFormat()
+ function.
+
+ \value PlainText The text string is interpreted as a plain text
+ string.
+
+ \value RichText The text string is interpreted as a rich text
+ string.
+
+ \value AutoText The text string is interpreted as for
+ Qt::RichText if Qt::mightBeRichText() returns true, otherwise
+ as Qt::PlainText.
+
+ \value LogText A special, limited text format which is only used
+ by Q3TextEdit in an optimized mode.
+*/
+
+/*!
+ \enum Qt::CursorShape
+
+ This enum type defines the various cursors that can be used.
+
+ The standard arrow cursor is the default for widgets in a normal state.
+
+ \value ArrowCursor \inlineimage cursor-arrow.png
+ The standard arrow cursor.
+ \value UpArrowCursor \inlineimage cursor-uparrow.png
+ An arrow pointing upwards toward the top of the screen.
+ \value CrossCursor \inlineimage cursor-cross.png
+ A crosshair cursor, typically used to help the
+ user accurately select a point on the screen.
+ \value WaitCursor \inlineimage cursor-wait.png
+ An hourglass or watch cursor, usually shown during
+ operations that prevent the user from interacting with
+ the application.
+ \value IBeamCursor \inlineimage cursor-ibeam.png
+ A caret or ibeam cursor, indicating that a widget can
+ accept and display text input.
+ \value SizeVerCursor \inlineimage cursor-sizev.png
+ A cursor used for elements that are used to vertically
+ resize top-level windows.
+ \value SizeHorCursor \inlineimage cursor-sizeh.png
+ A cursor used for elements that are used to horizontally
+ resize top-level windows.
+ \value SizeBDiagCursor \inlineimage cursor-sizeb.png
+ A cursor used for elements that are used to diagonally
+ resize top-level windows at their top-right and
+ bottom-left corners.
+ \value SizeFDiagCursor \inlineimage cursor-sizef.png
+ A cursor used for elements that are used to diagonally
+ resize top-level windows at their top-left and
+ bottom-right corners.
+ \value SizeAllCursor \inlineimage cursor-sizeall.png
+ A cursor used for elements that are used to resize
+ top-level windows in any direction.
+ \value BlankCursor A blank/invisible cursor, typically used when the cursor
+ shape needs to be hidden.
+ \value SplitVCursor \inlineimage cursor-vsplit.png
+ A cursor used for vertical splitters, indicating that
+ a handle can be dragged horizontally to adjust the use
+ of available space.
+ \value SplitHCursor \inlineimage cursor-hsplit.png
+ A cursor used for horizontal splitters, indicating that
+ a handle can be dragged vertically to adjust the use
+ of available space.
+ \value PointingHandCursor \inlineimage cursor-hand.png
+ A pointing hand cursor that is typically used for
+ clickable elements such as hyperlinks.
+ \value ForbiddenCursor \inlineimage cursor-forbidden.png
+ A slashed circle cursor, typically used during drag
+ and drop operations to indicate that dragged content
+ cannot be dropped on particular widgets or inside
+ certain regions.
+ \value OpenHandCursor \inlineimage cursor-openhand.png
+ A cursor representing an open hand, typically used to
+ indicate that the area under the cursor is the visible
+ part of a canvas that the user can click and drag in
+ order to scroll around.
+ \value ClosedHandCursor \inlineimage cursor-closedhand.png
+ A cursor representing a closed hand, typically used to
+ indicate that a dragging operation is in progress that
+ involves scrolling.
+ \value WhatsThisCursor \inlineimage cursor-whatsthis.png
+ An arrow with a question mark, typically used to indicate
+ the presence of What's This? help for a widget.
+ \value BusyCursor \inlineimage cursor-wait.png
+ An hourglass or watch cursor, usually shown during
+ operations that allow the user to interact with
+ the application while they are performed in the
+ background.
+ \value BitmapCursor
+ \omitvalue LastCursor
+ \omitvalue CustomCursor
+
+ \omitvalue arrowCursor
+ \omitvalue upArrowCursor
+ \omitvalue crossCursor
+ \omitvalue waitCursor
+ \omitvalue ibeamCursor
+ \omitvalue sizeVerCursor
+ \omitvalue sizeHorCursor
+ \omitvalue sizeBDiagCursor
+ \omitvalue sizeFDiagCursor
+ \omitvalue sizeAllCursor
+ \omitvalue blankCursor
+ \omitvalue splitVCursor
+ \omitvalue splitHCursor
+ \omitvalue pointingHandCursor
+ \omitvalue forbiddenCursor
+ \omitvalue whatsThisCursor
+*/
+
+/*!
+ \typedef Qt::TextFlags
+ \compat
+
+ Use Qt::TextFlag instead.
+*/
+
+/*!
+ \enum Qt::LayoutDirection
+
+ Specifies the direction of Qt's layouts:
+
+ \value LeftToRight Left-to-right layout.
+ \value RightToLeft Right-to-left layout.
+
+ Right-to-left layouts are necessary for certain languages,
+ notably Arabic and Hebrew.
+
+ \sa QApplication::setLayoutDirection(), QWidget::setLayoutDirection()
+*/
+
+/*!
+ \enum Qt::AnchorPoint
+
+ Specifies a side of a layout item that can be anchored. This is used by
+ QGraphicsAnchorLayout.
+
+ \value AnchorLeft The left side of a layout item.
+ \value AnchorHorizontalCenter A "virtual" side that is centered between the left and the
+ right side of a layout item.
+ \value AnchorRight The right side of a layout item.
+ \value AnchorTop The top side of a layout item.
+ \value AnchorVerticalCenter A "virtual" side that is centered between the top and the
+ bottom side of a layout item.
+ \value AnchorBottom The bottom side of a layout item.
+
+ \sa QGraphicsAnchorLayout
+*/
+
+/*!
+ \enum Qt::InputMethodHint
+
+ \value ImhNone No hints.
+ \value ImhHiddenText Characters should be hidden, as is typically used when entering passwords.
+ This is automatically set when setting QLineEdit::echoMode to \c Password.
+ \value ImhDigitsOnly Only number input is allowed.
+ \value ImhUppercaseOnly Only upper case letter input is allowed.
+ \value ImhLowercaseOnly Only lower case letter input is allowed.
+ \value ImhNoAutoUppercase The input method should not try to automatically switch to upper case
+ when a sentence ends.
+ \value ImhPreferNumbers Numbers are preferred (but not required).
+ \value ImhPreferUppercase Upper case letters are preferred (but not required).
+ \value ImhPreferLowercase Lower case letters are preferred (but not required).
+ \value ImhNoPredictiveText Do not use predictive text (i.e. dictionary lookup) while typing.
+ \value ImhDialableCharactersOnly Only characters suitable for phone dialling are allowed.
+
+ \omitvalue ImhFormattedNumbersOnly
+ \omitvalue ImhExclusiveInputMask
+
+ \note If several flags ending with \c Only are ORed together, the resulting character set will
+ consist of the union of the specified sets. For instance specifying \c ImhNumbersOnly and
+ \c ImhUppercaseOnly would yield a set consisting of numbers and uppercase letters.
+
+ \sa QGraphicsItem::inputMethodHints()
+*/
+
+/*!
+ \enum Qt::InputMethodQuery
+
+ \value ImMicroFocus The rectangle covering the area of the input cursor in widget coordinates.
+ \value ImFont The currently used font for text input.
+ \value ImCursorPosition The logical position of the cursor within the text surrounding the input area (see \c ImSurroundingText).
+ \value ImSurroundingText The plain text around the input area, for example the current paragraph.
+ \value ImCurrentSelection The currently selected text.
+ \value ImMaximumTextLength The maximum number of characters that the widget can hold. If there is no limit, QVariant() is returned.
+ \value ImAnchorPosition The position of the selection anchor. This may be less or greater than \c ImCursorPosition, depending on which side of selection the cursor is. If there is no selection, it returns the same as \c ImCursorPosition.
+*/
+
+/*!
+ \enum Qt::ItemDataRole
+
+ Each item in the model has a set of data elements associated with
+ it, each with its own role. The roles are used by the view to indicate
+ to the model which type of data it needs. Custom models should return
+ data in these types.
+
+ The general purpose roles (and the associated types) are:
+
+ \value DisplayRole The key data to be rendered in the form of text. (QString)
+ \value DecorationRole The data to be rendered as a decoration in the form
+ of an icon. (QColor)
+ \value EditRole The data in a form suitable for editing in an
+ editor. (QString)
+ \value ToolTipRole The data displayed in the item's tooltip. (QString)
+ \value StatusTipRole The data displayed in the status bar. (QString)
+ \value WhatsThisRole The data displayed for the item in "What's This?"
+ mode. (QString)
+ \value SizeHintRole The size hint for the item that will be supplied
+ to views. (QSize)
+
+ Roles describing appearance and meta data (with associated types):
+
+ \value FontRole The font used for items rendered with the default
+ delegate. (QFont)
+ \value TextAlignmentRole The alignment of the text for items rendered with the
+ default delegate. (Qt::AlignmentFlag)
+ \value BackgroundRole The background brush used for items rendered with
+ the default delegate. (QBrush)
+ \value BackgroundColorRole This role is obsolete. Use BackgroundRole instead.
+ \value ForegroundRole The foreground brush (text color, typically)
+ used for items rendered with the default delegate.
+ (QBrush)
+ \value TextColorRole This role is obsolete. Use ForegroundRole instead.
+ \value CheckStateRole This role is used to obtain the checked state of
+ an item. (Qt::CheckState)
+
+ Accessibility roles (with associated types):
+
+ \value AccessibleTextRole The text to be used by accessibility
+ extensions and plugins, such as screen
+ readers. (QString)
+ \value AccessibleDescriptionRole A description of the item for accessibility
+ purposes. (QString)
+
+ User roles:
+
+ \value UserRole The first role that can be used for application-specific purposes.
+
+ \omitvalue DisplayPropertyRole
+ \omitvalue DecorationPropertyRole
+ \omitvalue ToolTipPropertyRole
+ \omitvalue StatusTipPropertyRole
+ \omitvalue WhatsThisPropertyRole
+
+ For user roles, it is up to the developer to decide which types to use and ensure that
+ components use the correct types when accessing and setting data.
+*/
+
+/*!
+ \enum Qt::ItemFlag
+
+ This enum describes the properties of an item:
+
+ \value NoItemFlags It does not have any properties set.
+ \value ItemIsSelectable It can be selected.
+ \value ItemIsEditable It can be edited.
+ \value ItemIsDragEnabled It can be dragged.
+ \value ItemIsDropEnabled It can be used as a drop target.
+ \value ItemIsUserCheckable It can be checked or unchecked by the user.
+ \value ItemIsEnabled The user can interact with the item.
+ \value ItemIsTristate The item is checkable with three separate states.
+
+ Note that checkable items need to be given both a suitable set of flags
+ and an initial state, indicating whether the item is checked or not.
+ This is handled automatically for model/view components, but needs
+ to be explicitly set for instances of QListWidgetItem, QTableWidgetItem,
+ and QTreeWidgetItem.
+
+ \sa QAbstractItemModel
+*/
+
+/*!
+ \enum Qt::MatchFlag
+
+ This enum describes the type of matches that can be used when searching
+ for items in a model.
+
+ \value MatchExactly Performs QVariant-based matching.
+ \value MatchFixedString Performs string-based matching.
+ String-based comparisons are case-insensitive unless the
+ \c MatchCaseSensitive flag is also specified.
+ \value MatchContains The search term is contained in the item.
+ \value MatchStartsWith The search term matches the start of the item.
+ \value MatchEndsWith The search term matches the end of the item.
+ \value MatchCaseSensitive The search is case sensitive.
+ \value MatchRegExp Performs string-based matching using a regular
+ expression as the search term.
+ \value MatchWildcard Performs string-based matching using a string with
+ wildcards as the search term.
+ \value MatchWrap Perform a search that wraps around, so that when
+ the search reaches the last item in the model, it begins again at
+ the first item and continues until all items have been examined.
+ \value MatchRecursive Searches the entire hierarchy.
+
+ \sa QString::compare(), QRegExp
+*/
+
+/*!
+ \enum Qt::TextElideMode
+
+ This enum specifies where the ellipsis should appear when
+ displaying texts that don't fit:
+
+ \value ElideLeft The ellipsis should appear at the beginning of the text.
+ \value ElideRight The ellipsis should appear at the end of the text.
+ \value ElideMiddle The ellipsis should appear in the middle of the text.
+ \value ElideNone Ellipsis should NOT appear in the text.
+
+ Qt::ElideMiddle is normally the most appropriate choice for URLs (e.g.,
+ "\l{http://qt.nokia.com/careers/movingto/brisbane/}{http://qt.nok...ovingto/brisbane/}"),
+ whereas Qt::ElideRight is appropriate
+ for other strings (e.g.,
+ "\l{http://qt.nokia.com/doc/qq/qq09-mac-deployment.html}{Deploying Applications on Ma...}").
+
+ \sa QAbstractItemView::textElideMode, QFontMetrics::elidedText(), AlignmentFlag QTabBar::elideMode
+*/
+
+/*!
+ \enum Qt::WindowModality
+
+ \keyword modal
+
+ This enum specifies the behavior of a modal window. A modal window
+ is one that blocks input to other windows. Note that windows that
+ are children of a modal window are not blocked.
+
+ The values are:
+ \value NonModal The window is not modal and does not block input to other windows.
+ \value WindowModal The window is modal to a single window hierarchy and blocks input to its parent window, all grandparent windows, and all siblings of its parent and grandparent windows.
+ \value ApplicationModal The window is modal to the application and blocks input to all windows.
+
+ \sa QWidget::windowModality, QDialog
+*/
+
+/*!
+ \enum Qt::TextInteractionFlag
+
+ This enum specifies how a text displaying widget reacts to user input.
+
+ \value NoTextInteraction No interaction with the text is possible.
+ \value TextSelectableByMouse Text can be selected with the mouse and copied to the clipboard using
+ a context menu or standard keyboard shortcuts.
+ \value TextSelectableByKeyboard Text can be selected with the cursor keys on the keyboard. A text cursor is shown.
+ \value LinksAccessibleByMouse Links can be highlighted and activated with the mouse.
+ \value LinksAccessibleByKeyboard Links can be focused using tab and activated with enter.
+ \value TextEditable The text is fully editable.
+
+ \value TextEditorInteraction The default for a text editor.
+ \value TextBrowserInteraction The default for QTextBrowser.
+*/
+
+/*!
+ \enum Qt::MaskMode
+
+ This enum specifies the behavior of the
+ QPixmap::createMaskFromColor() and QImage::createMaskFromColor()
+ functions.
+
+ \value MaskInColor Creates a mask where all pixels matching the given color are opaque.
+ \value MaskOutColor Creates a mask where all pixels matching the given color are transparent.
+*/
+
+/*!
+ \enum Qt::DockWidgetAreaSizes
+ \internal
+*/
+
+/*!
+ \enum Qt::ToolBarAreaSizes
+ \internal
+*/
+
+/*!
+ \enum Qt::EventPriority
+
+ This enum can be used to specify event priorities.
+
+ \value HighEventPriority Events with this priority are sent before
+ events with NormalEventPriority or LowEventPriority.
+
+ \value NormalEventPriority Events with this priority are sent
+ after events with HighEventPriority, but before events with
+ LowEventPriority.
+
+ \value LowEventPriority Events with this priority are sent after
+ events with HighEventPriority or NormalEventPriority.
+
+ Note that these values are provided purely for convenience, since
+ event priorities can be any value between \c INT_MAX and \c
+ INT_MIN, inclusive. For example, you can define custom priorities
+ as being relative to each other:
+
+ \snippet doc/src/snippets/code/doc_src_qnamespace.qdoc 1
+
+ \sa QCoreApplication::postEvent()
+*/
+/*!
+ \enum Qt::SizeHint
+ \since 4.4
+
+ This enum is used by QGraphicsLayoutItem::sizeHint()
+
+ \value MinimumSize is used to specify the minimum size of a graphics layout item.
+ \value PreferredSize is used to specify the preferred size of a graphics layout item.
+ \value MaximumSize is used to specify the maximum size of a graphics layout item.
+ \value MinimumDescent is used to specify the minimum descent of a text string in a graphics layout item.
+ \omitvalue NSizeHints
+
+ \sa QGraphicsLayoutItem::sizeHint()
+*/
+
+/*!
+ \enum Qt::SizeMode
+ \since 4.4
+
+ This enum is used by QPainter::drawRoundedRect() and QPainterPath::addRoundedRect()
+ functions to specify the radii of rectangle corners with respect to the dimensions
+ of the bounding rectangles specified.
+
+ \value AbsoluteSize Specifies the size using absolute measurements.
+ \value RelativeSize Specifies the size relative to the bounding rectangle,
+ typically using percentage measurements.
+*/
+
+/*!
+ \enum Qt::WindowFrameSection
+ \since 4.4
+
+ This enum is used to describe parts of a window frame. It is returned by
+ QGraphicsWidget::windowFrameSectionAt() to describe what section of the window
+ frame is under the mouse.
+
+ \value NoSection
+ \value LeftSection
+ \value TopLeftSection
+ \value TopSection
+ \value TopRightSection
+ \value RightSection
+ \value BottomRightSection
+ \value BottomSection
+ \value BottomLeftSection
+ \value TitleBarArea
+
+ \sa QGraphicsWidget::windowFrameEvent()
+ \sa QGraphicsWidget::paintWindowFrame()
+ \sa QGraphicsWidget::windowFrameSectionAt()
+
+*/
+
+/*!
+ \enum Qt::TileRule
+ \since 4.6
+
+ This enum describes how to repeat or stretch the parts of an image
+ when drawing.
+
+ \value Stretch Scale the image to fit to the available area.
+
+ \value Repeat Tile the image until there is no more space. May crop
+ the last image.
+
+ \value Round Like Repeat, but scales the images down to ensure that
+ the last image is not cropped.
+*/
+
+/*!
+ \enum Qt::Initialization
+ \internal
+*/
+
+/*!
+ \enum Qt::GestureState
+ \since 4.6
+
+ This enum type describes the state of a gesture.
+
+ \value NoGesture Initial state
+ \value GestureStarted A continuous gesture has started.
+ \value GestureUpdated A gesture continues.
+ \value GestureFinished A gesture has finished.
+
+ \sa QGesture
+*/
diff --git a/src/corelib/global/qt_windows.h b/src/corelib/global/qt_windows.h
index 7dbfc9e..b70480a 100644
--- a/src/corelib/global/qt_windows.h
+++ b/src/corelib/global/qt_windows.h
@@ -53,6 +53,13 @@
#endif
#endif
+#if defined(Q_CC_MINGW)
+// mingw's windows.h does not set _WIN32_WINNT, resulting breaking compilation
+#ifndef WINVER
+#define WINVER 0x500
+#endif
+#endif
+
#include <windows.h>
#ifdef _WIN32_WCE
@@ -60,7 +67,6 @@
#endif
// already defined when compiled with WINVER >= 0x0500
-// and we only use them in Qt::WV_2000 and Qt::WV_98
#ifndef SPI_SETMENUANIMATION
#define SPI_SETMENUANIMATION 0x1003
#endif
@@ -100,14 +106,46 @@
#ifndef SPI_GETKEYBOARDCUES
#define SPI_GETKEYBOARDCUES 0x100A
#endif
+#ifndef SPI_GETGRADIENTCAPTIONS
+#define SPI_GETGRADIENTCAPTIONS 0x1008
+#endif
#ifndef IDC_HAND
#define IDC_HAND MAKEINTRESOURCE(32649)
#endif
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL 0x020A
#endif
+#ifndef WM_MOUSEHWHEEL
+#define WM_MOUSEHWHEEL 0x020E
+#endif
#ifndef ETO_PDY
#define ETO_PDY 0x2000
#endif
+#ifndef COLOR_GRADIENTACTIVECAPTION
+#define COLOR_GRADIENTACTIVECAPTION 27
+#endif
+#ifndef COLOR_GRADIENTINACTIVECAPTION
+#define COLOR_GRADIENTINACTIVECAPTION 28
+#endif
+
+// already defined when compiled with WINVER >= 0x0600
+#ifndef SPI_GETFLATMENU
+#define SPI_GETFLATMENU 0x1022
+#endif
+#ifndef CS_DROPSHADOW
+#define CS_DROPSHADOW 0x00020000
+#endif
+#ifndef CLEARTYPE_QUALITY
+#define CLEARTYPE_QUALITY 5
+#endif
+
+#ifdef Q_WS_WINCE
+#ifndef LR_DEFAULTSIZE
+#define LR_DEFAULTSIZE 0
+#endif
+#ifndef LR_SHARED
+#define LR_SHARED 0
+#endif
+#endif // Q_WS_WINCE
#endif // QT_WINDOWS_H
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index 3690d4b..e58e4ad 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -13,6 +13,7 @@ HEADERS += \
io/qfileinfo_p.h \
io/qiodevice.h \
io/qiodevice_p.h \
+ io/qnoncontiguousbytedevice_p.h \
io/qprocess.h \
io/qprocess_p.h \
io/qtextstream.h \
@@ -38,6 +39,7 @@ SOURCES += \
io/qfile.cpp \
io/qfileinfo.cpp \
io/qiodevice.cpp \
+ io/qnoncontiguousbytedevice.cpp \
io/qprocess.cpp \
io/qtextstream.cpp \
io/qtemporaryfile.cpp \
@@ -62,8 +64,12 @@ win32 {
} else:unix {
SOURCES += io/qfsfileengine_unix.cpp
SOURCES += io/qfsfileengine_iterator_unix.cpp
- SOURCES += io/qprocess_unix.cpp
- mac:SOURCES += io/qsettings_mac.cpp
+ symbian:SOURCES += io/qprocess_symbian.cpp
+ else:SOURCES += io/qprocess_unix.cpp
+ macx-*: {
+ HEADERS += io/qfilesystemwatcher_fsevents_p.h
+ SOURCES += io/qsettings_mac.cpp io/qfilesystemwatcher_fsevents.cpp
+ }
linux-*:{
SOURCES += \
@@ -79,4 +85,10 @@ win32 {
SOURCES += io/qfilesystemwatcher_kqueue.cpp
HEADERS += io/qfilesystemwatcher_kqueue_p.h
}
+
+ symbian {
+ SOURCES += io/qfilesystemwatcher_symbian.cpp
+ HEADERS += io/qfilesystemwatcher_symbian_p.h
+ contains(QT_CONFIG, s60): LIBS += -lplatformenv
+ }
}
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp
index 6cf2245..e86c17d 100644
--- a/src/corelib/io/qabstractfileengine.cpp
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -42,7 +42,7 @@
#include "qabstractfileengine.h"
#include "private/qabstractfileengine_p.h"
#include "qdatetime.h"
-#include "qmutex.h"
+#include "qreadwritelock.h"
#include "qvariant.h"
// built-in handlers
#include "qfsfileengine.h"
@@ -98,14 +98,14 @@ QT_BEGIN_NAMESPACE
All application-wide handlers are stored in this list. The mutex must be
acquired to ensure thread safety.
*/
-Q_GLOBAL_STATIC_WITH_ARGS(QMutex, fileEngineHandlerMutex, (QMutex::Recursive))
+Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, fileEngineHandlerMutex, (QReadWriteLock::Recursive))
static bool qt_abstractfileenginehandlerlist_shutDown = false;
class QAbstractFileEngineHandlerList : public QList<QAbstractFileEngineHandler *>
{
public:
~QAbstractFileEngineHandlerList()
{
- QMutexLocker locker(fileEngineHandlerMutex());
+ QWriteLocker locker(fileEngineHandlerMutex());
qt_abstractfileenginehandlerlist_shutDown = true;
}
};
@@ -122,7 +122,7 @@ Q_GLOBAL_STATIC(QAbstractFileEngineHandlerList, fileEngineHandlers)
*/
QAbstractFileEngineHandler::QAbstractFileEngineHandler()
{
- QMutexLocker locker(fileEngineHandlerMutex());
+ QWriteLocker locker(fileEngineHandlerMutex());
fileEngineHandlers()->prepend(this);
}
@@ -132,7 +132,7 @@ QAbstractFileEngineHandler::QAbstractFileEngineHandler()
*/
QAbstractFileEngineHandler::~QAbstractFileEngineHandler()
{
- QMutexLocker locker(fileEngineHandlerMutex());
+ QWriteLocker locker(fileEngineHandlerMutex());
// Remove this handler from the handler list only if the list is valid.
if (!qt_abstractfileenginehandlerlist_shutDown)
fileEngineHandlers()->removeAll(this);
@@ -166,12 +166,14 @@ QAbstractFileEngineHandler::~QAbstractFileEngineHandler()
*/
QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
{
- QMutexLocker locker(fileEngineHandlerMutex());
+ {
+ QReadLocker locker(fileEngineHandlerMutex());
- // check for registered handlers that can load the file
- for (int i = 0; i < fileEngineHandlers()->size(); i++) {
- if (QAbstractFileEngine *ret = fileEngineHandlers()->at(i)->create(fileName))
- return ret;
+ // check for registered handlers that can load the file
+ for (int i = 0; i < fileEngineHandlers()->size(); i++) {
+ if (QAbstractFileEngine *ret = fileEngineHandlers()->at(i)->create(fileName))
+ return ret;
+ }
}
#ifdef QT_BUILD_CORE_LIB
@@ -252,6 +254,8 @@ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
\value CanonicalPathName Same as CanonicalName, excluding the base name.
\value BundleName Returns the name of the bundle implies BundleType is set.
+ \omitvalue NFileNames
+
\sa fileName(), setFileName()
*/
@@ -352,8 +356,6 @@ QAbstractFileEngine::QAbstractFileEngine(QAbstractFileEnginePrivate &dd) : d_ptr
*/
QAbstractFileEngine::~QAbstractFileEngine()
{
- delete d_ptr;
- d_ptr = 0;
}
/*!
@@ -881,7 +883,6 @@ QAbstractFileEngineIterator::QAbstractFileEngineIterator(QDir::Filters filters,
*/
QAbstractFileEngineIterator::~QAbstractFileEngineIterator()
{
- delete d;
}
/*!
diff --git a/src/corelib/io/qabstractfileengine.h b/src/corelib/io/qabstractfileengine.h
index 5667bc9..44ea23f 100644
--- a/src/corelib/io/qabstractfileengine.h
+++ b/src/corelib/io/qabstractfileengine.h
@@ -100,7 +100,8 @@ public:
LinkName,
CanonicalName,
CanonicalPathName,
- BundleName
+ BundleName,
+ NFileNames = 9
};
enum FileOwner {
OwnerUser,
@@ -193,7 +194,7 @@ protected:
QAbstractFileEngine();
QAbstractFileEngine(QAbstractFileEnginePrivate &);
- QAbstractFileEnginePrivate *d_ptr;
+ QScopedPointer<QAbstractFileEnginePrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(QAbstractFileEngine)
Q_DISABLE_COPY(QAbstractFileEngine)
@@ -237,7 +238,7 @@ private:
friend class QDirIterator;
friend class QDirIteratorPrivate;
void setPath(const QString &path);
- QAbstractFileEngineIteratorPrivate *d;
+ QScopedPointer<QAbstractFileEngineIteratorPrivate> d;
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp
index a165ef9..38c102f 100644
--- a/src/corelib/io/qdatastream.cpp
+++ b/src/corelib/io/qdatastream.cpp
@@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE
to a QIODevice.
\ingroup io
- \mainclass
+
A data stream is a binary stream of encoded information which is
100% independent of the host computer's operating system, CPU or
@@ -362,17 +362,19 @@ QDataStream::~QDataStream()
/*!
\fn QIODevice *QDataStream::device() const
- Returns the I/O device currently set.
+ Returns the I/O device currently set, or 0 if no
+ device is currently set.
- \sa setDevice(), unsetDevice()
+ \sa setDevice()
*/
/*!
void QDataStream::setDevice(QIODevice *d)
- Sets the I/O device to \a d.
+ Sets the I/O device to \a d, which can be 0
+ to unset to current I/O device.
- \sa device(), unsetDevice()
+ \sa device()
*/
void QDataStream::setDevice(QIODevice *d)
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
index 3353a63..0cb21f0 100644
--- a/src/corelib/io/qdatastream.h
+++ b/src/corelib/io/qdatastream.h
@@ -65,9 +65,8 @@ template <typename T> class QSet;
template <class Key, class T> class QHash;
template <class Key, class T> class QMap;
-class QDataStreamPrivate;
-
#ifndef QT_NO_DATASTREAM
+class QDataStreamPrivate;
class Q_CORE_EXPORT QDataStream
{
public:
@@ -83,10 +82,11 @@ public:
Qt_4_2 = 8,
Qt_4_3 = 9,
Qt_4_4 = 10,
- Qt_4_5 = 11
-#if QT_VERSION >= 0x040600
+ Qt_4_5 = 11,
+ Qt_4_6 = Qt_4_5
+#if QT_VERSION >= 0x040700
#error Add the datastream version for this Qt version
- , Qt_4_6 = Qt_4_5
+ Qt_4_7 = Qt_4_6
#endif
};
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index 30ab92c..d548c45 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -52,8 +52,7 @@
/*!
\class QDebug
- \ingroup io
- \mainclass
+
\brief The QDebug class provides an output stream for debugging information.
QDebug is used whenever the developer needs to write out debugging or tracing
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index f3c50eb..a79705c 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -51,6 +51,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qvector.h>
#include <QtCore/qset.h>
+#include <QtCore/qcontiguouscache.h>
QT_BEGIN_HEADER
@@ -79,16 +80,19 @@ public:
inline QDebug &operator=(const QDebug &other);
inline ~QDebug() {
if (!--stream->ref) {
- if(stream->message_output)
- qt_message_output(stream->type, stream->buffer.toLocal8Bit().data());
+ if(stream->message_output) {
+ QT_TRY {
+ qt_message_output(stream->type, stream->buffer.toLocal8Bit().data());
+ } QT_CATCH(std::bad_alloc) { /* We're out of memory - give up. */ }
+ }
delete stream;
}
}
- inline QDebug &space() { stream->space = true; stream->ts << " "; return *this; }
+ inline QDebug &space() { stream->space = true; stream->ts << ' '; return *this; }
inline QDebug &nospace() { stream->space = false; return *this; }
- inline QDebug &maybeSpace() { if (stream->space) stream->ts << " "; return *this; }
+ inline QDebug &maybeSpace() { if (stream->space) stream->ts << ' '; return *this; }
- inline QDebug &operator<<(QChar t) { stream->ts << "\'" << t << "\'"; return maybeSpace(); }
+ inline QDebug &operator<<(QChar t) { stream->ts << '\'' << t << '\''; return maybeSpace(); }
inline QDebug &operator<<(QBool t) { stream->ts << (bool(t) ? "true" : "false"); return maybeSpace(); }
inline QDebug &operator<<(bool t) { stream->ts << (t ? "true" : "false"); return maybeSpace(); }
inline QDebug &operator<<(char t) { stream->ts << t; return maybeSpace(); }
@@ -105,10 +109,10 @@ public:
inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(const char* t) { stream->ts << QString::fromAscii(t); return maybeSpace(); }
- inline QDebug &operator<<(const QString & t) { stream->ts << "\"" << t << "\""; return maybeSpace(); }
+ inline QDebug &operator<<(const QString & t) { stream->ts << '\"' << t << '\"'; return maybeSpace(); }
inline QDebug &operator<<(const QStringRef & t) { return operator<<(t.toString()); }
- inline QDebug &operator<<(const QLatin1String &t) { stream->ts << "\"" << t.latin1() << "\""; return maybeSpace(); }
- inline QDebug &operator<<(const QByteArray & t) { stream->ts << "\"" << t << "\""; return maybeSpace(); }
+ inline QDebug &operator<<(const QLatin1String &t) { stream->ts << '\"' << t.latin1() << '\"'; return maybeSpace(); }
+ inline QDebug &operator<<(const QByteArray & t) { stream->ts << '\"' << t << '\"'; return maybeSpace(); }
inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(QTextStreamFunction f) {
stream->ts << f;
@@ -158,13 +162,13 @@ template <class T>
inline QDebug operator<<(QDebug debug, const QList<T> &list)
#endif
{
- debug.nospace() << "(";
+ debug.nospace() << '(';
for (Q_TYPENAME QList<T>::size_type i = 0; i < list.count(); ++i) {
if (i)
debug << ", ";
debug << list.at(i);
}
- debug << ")";
+ debug << ')';
return debug.space();
}
@@ -191,9 +195,9 @@ inline QDebug operator<<(QDebug debug, const QMap<aKey, aT> &map)
debug.nospace() << "QMap(";
for (typename QMap<aKey, aT>::const_iterator it = map.constBegin();
it != map.constEnd(); ++it) {
- debug << "(" << it.key() << ", " << it.value() << ")";
+ debug << '(' << it.key() << ", " << it.value() << ')';
}
- debug << ")";
+ debug << ')';
return debug.space();
}
@@ -208,8 +212,8 @@ inline QDebug operator<<(QDebug debug, const QHash<aKey, aT> &hash)
debug.nospace() << "QHash(";
for (typename QHash<aKey, aT>::const_iterator it = hash.constBegin();
it != hash.constEnd(); ++it)
- debug << "(" << it.key() << ", " << it.value() << ")";
- debug << ")";
+ debug << '(' << it.key() << ", " << it.value() << ')';
+ debug << ')';
return debug.space();
}
@@ -221,7 +225,7 @@ template <class T1, class T2>
inline QDebug operator<<(QDebug debug, const QPair<T1, T2> &pair)
#endif
{
- debug.nospace() << "QPair(" << pair.first << "," << pair.second << ")";
+ debug.nospace() << "QPair(" << pair.first << ',' << pair.second << ')';
return debug.space();
}
@@ -232,6 +236,24 @@ inline QDebug operator<<(QDebug debug, const QSet<T> &set)
return operator<<(debug, set.toList());
}
+#if defined(FORCE_UREF)
+template <class T>
+inline QDebug &operator<<(QDebug debug, const QContiguousCache<T> &cache)
+#else
+template <class T>
+inline QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache)
+#endif
+{
+ debug.nospace() << "QContiguousCache(";
+ for (int i = cache.firstIndex(); i <= cache.lastIndex(); ++i) {
+ debug << cache[i];
+ if (i != cache.lastIndex())
+ debug << ", ";
+ }
+ debug << ')';
+ return debug.space();
+}
+
#if !defined(QT_NO_DEBUG_STREAM)
Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); }
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 4ba8e96..c0188cc 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -45,6 +45,7 @@
#ifndef QT_NO_DEBUG_STREAM
#include "qdebug.h"
#endif
+#include "qdiriterator.h"
#include "qfsfileengine.h"
#include "qdatetime.h"
#include "qstring.h"
@@ -55,14 +56,16 @@
# include "qresource.h"
#endif
-#include "../kernel/qcoreglobaldata_p.h"
+#include "qvarlengtharray.h"
+
+#include "private/qcoreglobaldata_p.h"
#include <stdlib.h>
QT_BEGIN_NAMESPACE
static QString driveSpec(const QString &path)
{
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
if (path.size() < 2)
return QString();
char c = path.at(0).toAscii();
@@ -83,6 +86,7 @@ class QDirPrivate
QDir *q_ptr;
Q_DECLARE_PUBLIC(QDir)
+ friend struct QScopedPointerDeleter<QDirPrivate>;
protected:
QDirPrivate(QDir*, const QDir *copy=0);
~QDirPrivate();
@@ -90,7 +94,7 @@ protected:
QString initFileEngine(const QString &file);
void updateFileLists() const;
- void sortFileList(QDir::SortFlags, QStringList &, QStringList *, QFileInfoList *) const;
+ void sortFileList(QDir::SortFlags, QFileInfoList &, QStringList *, QFileInfoList *) const;
private:
#ifdef QT3_SUPPORT
@@ -147,7 +151,7 @@ private:
QString path = p;
if ((path.endsWith(QLatin1Char('/')) || path.endsWith(QLatin1Char('\\')))
&& path.length() > 1) {
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
if (!(path.length() == 3 && path.at(1) == QLatin1Char(':')))
#endif
path.truncate(path.length() - 1);
@@ -260,45 +264,56 @@ bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortIt
? f1->filename_cache.localeAwareCompare(f2->filename_cache)
: f1->filename_cache.compare(f2->filename_cache);
}
-
+ if (r == 0) // Enforce an order - the order the items appear in the array
+ r = (&n1) - (&n2);
if (qt_cmp_si_sort_flags & QDir::Reversed)
return r > 0;
return r < 0;
}
-inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QStringList &l,
+inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QFileInfoList &l,
QStringList *names, QFileInfoList *infos) const
{
if(names)
names->clear();
if(infos)
infos->clear();
- if(!l.isEmpty()) {
- QDirSortItem *si= new QDirSortItem[l.count()];
- int i;
- for (i = 0; i < l.size(); ++i) {
- QString path = data->path;
- if (!path.isEmpty() && !path.endsWith(QLatin1Char('/')))
- path += QLatin1Char('/');
- si[i].item = QFileInfo(path + l.at(i));
- }
- if ((sort & QDir::SortByMask) != QDir::Unsorted)
- qStableSort(si, si+i, QDirSortItemComparator(sort));
- // put them back in the list(s)
- for (int j = 0; j<i; j++) {
+ int n = l.size();
+ if(n > 0) {
+ if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
if(infos)
- infos->append(si[j].item);
- if(names)
- names->append(si[j].item.fileName());
+ *infos = l;
+ if(names) {
+ for (int i = 0; i < n; ++i)
+ names->append(l.at(i).fileName());
+ }
+ } else {
+ QScopedArrayPointer<QDirSortItem> si(new QDirSortItem[n]);
+ for (int i = 0; i < n; ++i)
+ si[i].item = l.at(i);
+ qSort(si.data(), si.data()+n, QDirSortItemComparator(sort));
+ // put them back in the list(s)
+ if(infos) {
+ for (int i = 0; i < n; ++i)
+ infos->append(si[i].item);
+ }
+ if(names) {
+ for (int i = 0; i < n; ++i)
+ names->append(si[i].item.fileName());
+ }
}
- delete [] si;
}
}
inline void QDirPrivate::updateFileLists() const
{
if(data->listsDirty) {
- QStringList l = data->fileEngine->entryList(data->filters, data->nameFilters);
+ QFileInfoList l;
+ QDirIterator it(data->path, data->nameFilters, data->filters);
+ while (it.hasNext()) {
+ it.next();
+ l.append(it.fileInfo());
+ }
sortFileList(data->sort, l, &data->files, &data->fileInfos);
data->listsDirty = 0;
}
@@ -318,8 +333,9 @@ void QDirPrivate::detach(bool createFileEngine)
{
qAtomicDetach(data);
if (createFileEngine) {
+ QAbstractFileEngine *newFileEngine = QAbstractFileEngine::create(data->path);
delete data->fileEngine;
- data->fileEngine = QAbstractFileEngine::create(data->path);
+ data->fileEngine = newFileEngine;
}
}
@@ -330,7 +346,7 @@ void QDirPrivate::detach(bool createFileEngine)
\ingroup io
\ingroup shared
\reentrant
- \mainclass
+
A QDir is used to manipulate path names, access information
regarding paths and files, and manipulate the underlying file
@@ -573,8 +589,6 @@ QDir::QDir(const QDir &dir) : d_ptr(new QDirPrivate(this, &dir))
QDir::~QDir()
{
- delete d_ptr;
- d_ptr = 0;
}
/*!
@@ -772,6 +786,8 @@ QString QDir::relativeFilePath(const QString &fileName) const
if (fileDrive.toLower() != dirDrive.toLower()
|| (file.startsWith(QLatin1String("//"))
&& !dir.startsWith(QLatin1String("//"))))
+#elif defined(Q_OS_SYMBIAN)
+ if (fileDrive.toLower() != dirDrive.toLower())
#else
if (fileDrive != dirDrive)
#endif
@@ -787,7 +803,7 @@ QString QDir::relativeFilePath(const QString &fileName) const
int i = 0;
while (i < dirElts.size() && i < fileElts.size() &&
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
dirElts.at(i).toLower() == fileElts.at(i).toLower())
#else
dirElts.at(i) == fileElts.at(i))
@@ -834,7 +850,7 @@ QString QDir::convertSeparators(const QString &pathName)
QString QDir::toNativeSeparators(const QString &pathName)
{
QString n(pathName);
-#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX)
+#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN)
for (int i=0; i<(int)n.length(); i++) {
if (n[i] == QLatin1Char('/'))
n[i] = QLatin1Char('\\');
@@ -858,7 +874,7 @@ QString QDir::toNativeSeparators(const QString &pathName)
QString QDir::fromNativeSeparators(const QString &pathName)
{
QString n(pathName);
-#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX)
+#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN)
for (int i=0; i<(int)n.length(); i++) {
if (n[i] == QLatin1Char('\\'))
n[i] = QLatin1Char('/');
@@ -1302,7 +1318,6 @@ QStringList QDir::entryList(Filters filters, SortFlags sort) const
\sa entryList(), setNameFilters(), setSorting(), setFilter(), isReadable(), exists()
*/
-
QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort) const
{
Q_D(const QDir);
@@ -1344,10 +1359,12 @@ QStringList QDir::entryList(const QStringList &nameFilters, Filters filters,
d->updateFileLists();
return d->data->files;
}
- QStringList l = d->data->fileEngine->entryList(filters, nameFilters);
- if ((sort & QDir::SortByMask) == QDir::Unsorted)
- return l;
-
+ QFileInfoList l;
+ QDirIterator it(d->data->path, nameFilters, filters);
+ while (it.hasNext()) {
+ it.next();
+ l.append(it.fileInfo());
+ }
QStringList ret;
d->sortFileList(sort, l, &ret, 0);
return ret;
@@ -1387,8 +1404,13 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter
d->updateFileLists();
return d->data->fileInfos;
}
+ QFileInfoList l;
+ QDirIterator it(d->data->path, nameFilters, filters);
+ while (it.hasNext()) {
+ it.next();
+ l.append(it.fileInfo());
+ }
QFileInfoList ret;
- QStringList l = d->data->fileEngine->entryList(filters, nameFilters);
d->sortFileList(sort, l, 0, &ret);
return ret;
}
@@ -1520,9 +1542,11 @@ bool QDir::isReadable() const
/*!
\overload
- Returns true if the \e directory exists; otherwise returns false.
- (If a file with the same name is found this function will return
- false).
+ Returns true if the directory exists; otherwise returns false.
+ (If a file with the same name is found this function will return false).
+
+ The overload of this function that accepts an argument is used to test
+ for the presence of files and directories within a directory.
\sa QFileInfo::exists(), QFile::exists()
*/
@@ -1752,8 +1776,11 @@ bool QDir::rename(const QString &oldName, const QString &newName)
/*!
Returns true if the file called \a name exists; otherwise returns
- false. Unless \a name contains an absolute file path, the file
- name is assumed to be relative to the current directory.
+ false.
+
+ Unless \a name contains an absolute file path, the file name is assumed
+ to be relative to the directory itself, so this function is typically used
+ to check for the presence of files within a directory.
\sa QFileInfo::exists(), QFile::exists()
*/
@@ -1800,10 +1827,10 @@ QFileInfoList QDir::drives()
QChar QDir::separator()
{
-#if defined(Q_OS_UNIX)
- return QLatin1Char('/');
-#elif defined (Q_FS_FAT) || defined(Q_WS_WIN)
+#if defined (Q_FS_FAT) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN)
return QLatin1Char('\\');
+#elif defined(Q_OS_UNIX)
+ return QLatin1Char('/');
#elif defined (Q_OS_MAC)
return QLatin1Char(':');
#else
@@ -1903,7 +1930,7 @@ QString QDir::currentPath()
Under non-Windows operating systems the \c HOME environment
variable is used if it exists, otherwise the path returned by the
- rootPath() function is used.
+ rootPath().
\sa home(), currentPath(), rootPath(), tempPath()
*/
@@ -2054,11 +2081,13 @@ QString QDir::cleanPath(const QString &path)
QString name = path;
QChar dir_separator = separator();
if(dir_separator != QLatin1Char('/'))
- name.replace(dir_separator, QLatin1Char('/'));
+ name.replace(dir_separator, QLatin1Char('/'));
int used = 0, levels = 0;
const int len = name.length();
- QVector<QChar> out(len);
+ QVarLengthArray<QChar> outVector(len);
+ QChar *out = outVector.data();
+
const QChar *p = name.unicode();
for(int i = 0, last = -1, iwrite = 0; i < len; i++) {
if(p[i] == QLatin1Char('/')) {
@@ -2123,7 +2152,7 @@ QString QDir::cleanPath(const QString &path)
levels++;
}
} else if(last != -1 && iwrite - last == 1) {
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
eaten = (iwrite > 2);
#else
eaten = true;
@@ -2158,7 +2187,7 @@ QString QDir::cleanPath(const QString &path)
if(used == len)
ret = name;
else
- ret = QString(out.data(), used);
+ ret = QString(out, used);
// Strip away last slash except for root directories
if (ret.endsWith(QLatin1Char('/'))
@@ -2221,7 +2250,7 @@ QStringList QDir::nameFiltersFromString(const QString &nameFilter)
\snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 13
- If the file name contains characters that cannot be part of a valid C++ function name
+ If the file name contains characters that cannot be part of a valid C++ function name
(such as '-'), they have to be replaced by the underscore character ('_').
Note: This macro cannot be used in a namespace. It should be called from
@@ -2413,11 +2442,11 @@ QDebug operator<<(QDebug debug, QDir::Filters filters)
if (filters & QDir::System) flags << QLatin1String("System");
if (filters & QDir::CaseSensitive) flags << QLatin1String("CaseSensitive");
}
- debug << "QDir::Filters(" << qPrintable(flags.join(QLatin1String("|"))) << ")";
+ debug << "QDir::Filters(" << qPrintable(flags.join(QLatin1String("|"))) << ')';
return debug;
}
-QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
+static QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
{
if (sorting == QDir::NoSort) {
debug << "QDir::SortFlags(NoSort)";
@@ -2435,8 +2464,8 @@ QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
if (sorting & QDir::LocaleAware) flags << QLatin1String("LocaleAware");
if (sorting & QDir::Type) flags << QLatin1String("Type");
debug << "QDir::SortFlags(" << qPrintable(type)
- << "|"
- << qPrintable(flags.join(QLatin1String("|"))) << ")";
+ << '|'
+ << qPrintable(flags.join(QLatin1String("|"))) << ')';
}
return debug;
}
@@ -2448,9 +2477,9 @@ QDebug operator<<(QDebug debug, const QDir &dir)
<< qPrintable(dir.nameFilters().join(QLatin1String(",")))
<< "}, "
<< dir.sorting()
- << ","
+ << ','
<< dir.filter()
- << ")";
+ << ')';
return debug.space();
}
diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h
index 2a306b3..91e56eb 100644
--- a/src/corelib/io/qdir.h
+++ b/src/corelib/io/qdir.h
@@ -45,6 +45,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qstringlist.h>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_HEADER
@@ -57,7 +58,7 @@ class QDirPrivate;
class Q_CORE_EXPORT QDir
{
protected:
- QDirPrivate *d_ptr;
+ QScopedPointer<QDirPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(QDir)
public:
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp
index 9057d99..6bbc54a 100644
--- a/src/corelib/io/qdiriterator.cpp
+++ b/src/corelib/io/qdiriterator.cpp
@@ -99,6 +99,18 @@
QT_BEGIN_NAMESPACE
+class QDirIteratorPrivateIteratorStack : public QStack<QAbstractFileEngineIterator *>
+{
+public:
+ ~QDirIteratorPrivateIteratorStack();
+};
+
+QDirIteratorPrivateIteratorStack::~QDirIteratorPrivateIteratorStack()
+{
+ qDeleteAll(*this);
+}
+
+
class QDirIteratorPrivate
{
public:
@@ -106,25 +118,29 @@ public:
QDir::Filters filters, QDirIterator::IteratorFlags flags);
~QDirIteratorPrivate();
- void pushSubDirectory(const QFileInfo &fileInfo, const QStringList &nameFilters,
- QDir::Filters filters);
void advance();
- bool shouldFollowDirectory(const QFileInfo &);
- bool matchesFilters(const QAbstractFileEngineIterator *it) const;
- QSet<QString> visitedLinks;
- QAbstractFileEngine *engine;
- QStack<QAbstractFileEngineIterator *> fileEngineIterators;
- QString path;
- QFileInfo nextFileInfo;
- //This fileinfo is the current that we will return from the public API
+ void pushDirectory(const QFileInfo &fileInfo);
+ void checkAndPushDirectory(const QFileInfo &);
+ bool matchesFilters(const QString &fileName, const QFileInfo &fi) const;
+
+ QScopedPointer<QAbstractFileEngine> engine;
+
+ const QString path;
+ const QStringList nameFilters;
+ const QDir::Filters filters;
+ const QDirIterator::IteratorFlags iteratorFlags;
+
+#ifndef QT_NO_REGEXP
+ QVector<QRegExp> nameRegExps;
+#endif
+
+ QDirIteratorPrivateIteratorStack fileEngineIterators;
QFileInfo currentFileInfo;
- QDirIterator::IteratorFlags iteratorFlags;
- QDir::Filters filters;
- QStringList nameFilters;
- bool followNextDir;
- bool first;
- bool done;
+ QFileInfo nextFileInfo;
+
+ // Loop protection
+ QSet<QString> visitedLinks;
QDirIterator *q;
};
@@ -134,15 +150,24 @@ public:
*/
QDirIteratorPrivate::QDirIteratorPrivate(const QString &path, const QStringList &nameFilters,
QDir::Filters filters, QDirIterator::IteratorFlags flags)
- : engine(0), path(path), iteratorFlags(flags), followNextDir(false), first(true), done(false)
+ : engine(QAbstractFileEngine::create(path))
+ , path(path)
+ , nameFilters(nameFilters.contains(QLatin1String("*")) ? QStringList() : nameFilters)
+ , filters(QDir::NoFilter == filters ? QDir::AllEntries : filters)
+ , iteratorFlags(flags)
{
- if (filters == QDir::NoFilter)
- filters = QDir::AllEntries;
- this->filters = filters;
- this->nameFilters = nameFilters;
+#ifndef QT_NO_REGEXP
+ nameRegExps.reserve(nameFilters.size());
+ for (int i = 0; i < nameFilters.size(); ++i)
+ nameRegExps.append(
+ QRegExp(nameFilters.at(i),
+ (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive,
+ QRegExp::Wildcard));
+#endif
- nextFileInfo.setFile(path);
- pushSubDirectory(nextFileInfo, nameFilters, filters);
+ // Populate fields for hasNext() and next()
+ pushDirectory(QFileInfo(path));
+ advance();
}
/*!
@@ -150,14 +175,12 @@ QDirIteratorPrivate::QDirIteratorPrivate(const QString &path, const QStringList
*/
QDirIteratorPrivate::~QDirIteratorPrivate()
{
- delete engine;
}
/*!
\internal
*/
-void QDirIteratorPrivate::pushSubDirectory(const QFileInfo &fileInfo, const QStringList &nameFilters,
- QDir::Filters filters)
+void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo)
{
QString path = fileInfo.filePath();
@@ -169,7 +192,7 @@ void QDirIteratorPrivate::pushSubDirectory(const QFileInfo &fileInfo, const QStr
if (iteratorFlags & QDirIterator::FollowSymlinks)
visitedLinks << fileInfo.canonicalFilePath();
- if (engine || (engine = QAbstractFileEngine::create(this->path))) {
+ if (engine) {
engine->setFileName(path);
QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters);
if (it) {
@@ -186,70 +209,63 @@ void QDirIteratorPrivate::pushSubDirectory(const QFileInfo &fileInfo, const QStr
*/
void QDirIteratorPrivate::advance()
{
- // Advance to the next entry
- if (followNextDir) {
- // Start by navigating into the current directory.
- QAbstractFileEngineIterator *it = fileEngineIterators.top();
- pushSubDirectory(it->currentFileInfo(), it->nameFilters(), it->filters());
- followNextDir = false;
- }
-
while (!fileEngineIterators.isEmpty()) {
- QAbstractFileEngineIterator *it = fileEngineIterators.top();
// Find the next valid iterator that matches the filters.
- bool foundDirectory = false;
- while (it->hasNext()) {
+ while (fileEngineIterators.top()->hasNext()) {
+ QAbstractFileEngineIterator *it = fileEngineIterators.top();
it->next();
- if (matchesFilters(it)) {
+
+ const QFileInfo info = it->currentFileInfo();
+ checkAndPushDirectory(it->currentFileInfo());
+
+ if (matchesFilters(it->currentFileName(), info)) {
currentFileInfo = nextFileInfo;
- nextFileInfo = it->currentFileInfo();
- // Signal that we want to follow this entry.
- followNextDir = shouldFollowDirectory(nextFileInfo);
+ nextFileInfo = info;
+
//We found a matching entry.
return;
-
- } else if (shouldFollowDirectory(it->currentFileInfo())) {
- pushSubDirectory(it->currentFileInfo(), it->nameFilters(), it->filters());
- foundDirectory = true;
- break;
}
}
- if (!foundDirectory)
- delete fileEngineIterators.pop();
+
+ delete fileEngineIterators.pop();
}
+
currentFileInfo = nextFileInfo;
- done = true;
+ nextFileInfo = QFileInfo();
}
/*!
\internal
*/
-bool QDirIteratorPrivate::shouldFollowDirectory(const QFileInfo &fileInfo)
+void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo)
{
// If we're doing flat iteration, we're done.
if (!(iteratorFlags & QDirIterator::Subdirectories))
- return false;
+ return;
// Never follow non-directory entries
if (!fileInfo.isDir())
- return false;
+ return;
+
+ // Follow symlinks only when asked
+ if (!(iteratorFlags & QDirIterator::FollowSymlinks) && fileInfo.isSymLink())
+ return;
// Never follow . and ..
- if (fileInfo.fileName() == QLatin1String(".") || fileInfo.fileName() == QLatin1String(".."))
- return false;
+ QString fileName = fileInfo.fileName();
+ if (QLatin1String(".") == fileName || QLatin1String("..") == fileName)
+ return;
- // Check symlinks
- if (fileInfo.isSymLink() && !(iteratorFlags & QDirIterator::FollowSymlinks)) {
- // Follow symlinks only if FollowSymlinks was passed
- return false;
- }
+ // No hidden directories unless requested
+ if (!(filters & QDir::AllDirs) && !(filters & QDir::Hidden) && fileInfo.isHidden())
+ return;
// Stop link loops
if (visitedLinks.contains(fileInfo.canonicalFilePath()))
- return false;
+ return;
- return true;
+ pushDirectory(fileInfo);
}
/*!
@@ -262,48 +278,28 @@ bool QDirIteratorPrivate::shouldFollowDirectory(const QFileInfo &fileInfo)
current entry will be returned as part of the directory iteration);
otherwise, false is returned.
*/
-bool QDirIteratorPrivate::matchesFilters(const QAbstractFileEngineIterator *it) const
+bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const
{
- const bool filterPermissions = ((filters & QDir::PermissionMask)
- && (filters & QDir::PermissionMask) != QDir::PermissionMask);
- const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
- const bool skipFiles = !(filters & QDir::Files);
- const bool skipSymlinks = (filters & QDir::NoSymLinks);
- const bool doReadable = !filterPermissions || (filters & QDir::Readable);
- const bool doWritable = !filterPermissions || (filters & QDir::Writable);
- const bool doExecutable = !filterPermissions || (filters & QDir::Executable);
- const bool includeHidden = (filters & QDir::Hidden);
- const bool includeSystem = (filters & QDir::System);
-
-#ifndef QT_NO_REGEXP
- // Prepare name filters
- QList<QRegExp> regexps;
- bool hasNameFilters = !nameFilters.isEmpty() && !(nameFilters.contains(QLatin1String("*")));
- if (hasNameFilters) {
- for (int i = 0; i < nameFilters.size(); ++i) {
- regexps << QRegExp(nameFilters.at(i),
- (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive,
- QRegExp::Wildcard);
- }
- }
-#endif
+ Q_ASSERT(!fileName.isEmpty());
- QString fileName = it->currentFileName();
- if (fileName.isEmpty()) {
- // invalid entry
+ // filter . and ..?
+ const int fileNameSize = fileName.size();
+ const bool dotOrDotDot = fileName[0] == QLatin1Char('.')
+ && ((fileNameSize == 1)
+ ||(fileNameSize == 2 && fileName[1] == QLatin1Char('.')));
+ if ((filters & QDir::NoDotAndDotDot) && dotOrDotDot)
return false;
- }
-
- QFileInfo fi = it->currentFileInfo();
- QString filePath = it->currentFilePath();
+ // name filter
#ifndef QT_NO_REGEXP
// Pass all entries through name filters, except dirs if the AllDirs
- // filter is passed.
- if (hasNameFilters && !((filters & QDir::AllDirs) && fi.isDir())) {
+ if (!nameFilters.isEmpty() && !((filters & QDir::AllDirs) && fi.isDir())) {
bool matched = false;
- for (int i = 0; i < regexps.size(); ++i) {
- if (regexps.at(i).exactMatch(fileName)) {
+ for (QVector<QRegExp>::const_iterator iter = nameRegExps.constBegin(),
+ end = nameRegExps.constEnd();
+ iter != end; ++iter) {
+
+ if (iter->exactMatch(fileName)) {
matched = true;
break;
}
@@ -313,35 +309,40 @@ bool QDirIteratorPrivate::matchesFilters(const QAbstractFileEngineIterator *it)
}
#endif
- bool dotOrDotDot = (fileName == QLatin1String(".") || fileName == QLatin1String(".."));
- if ((filters & QDir::NoDotAndDotDot) && dotOrDotDot)
- return false;
-
- bool isHidden = !dotOrDotDot && fi.isHidden();
- if (!includeHidden && isHidden)
+ // filter hidden
+ const bool includeHidden = (filters & QDir::Hidden);
+ if (!includeHidden && !dotOrDotDot && fi.isHidden())
return false;
- bool isSystem = (!fi.isFile() && !fi.isDir() && !fi.isSymLink())
- || (!fi.exists() && fi.isSymLink());
- if (!includeSystem && isSystem)
+ // filter system files
+ const bool includeSystem = (filters & QDir::System);
+ if (!includeSystem && ((!fi.isFile() && !fi.isDir() && !fi.isSymLink())
+ || (!fi.exists() && fi.isSymLink())))
return false;
- bool alwaysShow = (filters & QDir::TypeMask) == 0
- && ((isHidden && includeHidden)
- || (includeSystem && isSystem));
-
- // Skip files and directories
- if ((filters & QDir::AllDirs) == 0 && skipDirs && fi.isDir()) {
- if (!alwaysShow)
+ // skip directories
+ const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
+ if (skipDirs && fi.isDir()) {
+ if (!((includeHidden && !dotOrDotDot && fi.isHidden())
+ || (includeSystem && !fi.exists() && fi.isSymLink())))
return false;
}
- if ((skipFiles && (fi.isFile() || !fi.exists()))
- || (skipSymlinks && fi.isSymLink())) {
- if (!alwaysShow)
+ // skip files
+ const bool skipFiles = !(filters & QDir::Files);
+ const bool skipSymlinks = (filters & QDir::NoSymLinks);
+ if ((skipFiles && (fi.isFile() || !fi.exists())) || (skipSymlinks && fi.isSymLink())) {
+ if (!((includeHidden && !dotOrDotDot && fi.isHidden())
+ || (includeSystem && !fi.exists() && fi.isSymLink())))
return false;
}
+ // filter permissions
+ const bool filterPermissions = ((filters & QDir::PermissionMask)
+ && (filters & QDir::PermissionMask) != QDir::PermissionMask);
+ const bool doWritable = !filterPermissions || (filters & QDir::Writable);
+ const bool doExecutable = !filterPermissions || (filters & QDir::Executable);
+ const bool doReadable = !filterPermissions || (filters & QDir::Readable);
if (filterPermissions
&& ((doReadable && !fi.isReadable())
|| (doWritable && !fi.isWritable())
@@ -349,11 +350,6 @@ bool QDirIteratorPrivate::matchesFilters(const QAbstractFileEngineIterator *it)
return false;
}
- if (!includeSystem && !dotOrDotDot && ((fi.exists() && !fi.isFile() && !fi.isDir() && !fi.isSymLink())
- || (!fi.exists() && fi.isSymLink()))) {
- return false;
- }
-
return true;
}
@@ -395,7 +391,7 @@ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
\sa hasNext(), next(), IteratorFlags
*/
QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
- : d(new QDirIteratorPrivate(path, QStringList(QLatin1String("*")), filters, flags))
+ : d(new QDirIteratorPrivate(path, QStringList(), filters, flags))
{
d->q = this;
}
@@ -413,7 +409,7 @@ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorF
\sa hasNext(), next(), IteratorFlags
*/
QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
- : d(new QDirIteratorPrivate(path, QStringList(QLatin1String("*")), QDir::NoFilter, flags))
+ : d(new QDirIteratorPrivate(path, QStringList(), QDir::NoFilter, flags))
{
d->q = this;
}
@@ -446,8 +442,6 @@ QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
*/
QDirIterator::~QDirIterator()
{
- qDeleteAll(d->fileEngineIterators);
- delete d;
}
/*!
@@ -462,8 +456,6 @@ QDirIterator::~QDirIterator()
*/
QString QDirIterator::next()
{
- if (!hasNext())
- return QString();
d->advance();
return filePath();
}
@@ -476,11 +468,7 @@ QString QDirIterator::next()
*/
bool QDirIterator::hasNext() const
{
- if (d->first) {
- d->first = false;
- d->advance();
- }
- return !d->done;
+ return !d->fileEngineIterators.isEmpty();
}
/*!
diff --git a/src/corelib/io/qdiriterator.h b/src/corelib/io/qdiriterator.h
index 4037945..b9502f1 100644
--- a/src/corelib/io/qdiriterator.h
+++ b/src/corelib/io/qdiriterator.h
@@ -84,7 +84,7 @@ public:
private:
Q_DISABLE_COPY(QDirIterator)
- QDirIteratorPrivate *d;
+ QScopedPointer<QDirIteratorPrivate> d;
friend class QDir;
};
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index 849d20c..f1e1913 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -52,10 +52,6 @@
# include "qcoreapplication.h"
#endif
-#if !defined(Q_OS_WINCE)
-#include <errno.h>
-#endif
-
#ifdef QT_NO_QOBJECT
#define tr(X) QString::fromLatin1(X)
#endif
@@ -109,6 +105,7 @@ QFilePrivate::openExternalFile(int flags, int fd)
return false;
#else
delete fileEngine;
+ fileEngine = 0;
QFSFileEngine *fe = new QFSFileEngine;
fe->setFileName(fileName);
fileEngine = fe;
@@ -125,6 +122,7 @@ QFilePrivate::openExternalFile(int flags, FILE *fh)
return false;
#else
delete fileEngine;
+ fileEngine = 0;
QFSFileEngine *fe = new QFSFileEngine;
fe->setFileName(fileName);
fileEngine = fe;
@@ -154,17 +152,15 @@ QFilePrivate::setError(QFile::FileError err)
void
QFilePrivate::setError(QFile::FileError err, const QString &errStr)
{
- Q_Q(QFile);
error = err;
- q->setErrorString(errStr);
+ errorString = errStr;
}
void
QFilePrivate::setError(QFile::FileError err, int errNum)
{
- Q_Q(QFile);
error = err;
- q->setErrorString(qt_error_string(errNum));
+ errorString = qt_error_string(errNum);
}
//************* QFile
@@ -174,7 +170,7 @@ QFilePrivate::setError(QFile::FileError err, int errNum)
\brief The QFile class provides an interface for reading from and writing to files.
\ingroup io
- \mainclass
+
\reentrant
QFile is an I/O device for reading and writing text and binary
@@ -410,9 +406,6 @@ QFile::QFile(QFilePrivate &dd, QObject *parent)
QFile::~QFile()
{
close();
-#ifdef QT_NO_QOBJECT
- delete d_ptr;
-#endif
}
/*!
@@ -656,11 +649,7 @@ QFile::remove()
unsetError();
return true;
}
-#if defined(Q_OS_WIN)
- d->setError(QFile::RemoveError, GetLastError());
-#else
- d->setError(QFile::RemoveError, errno);
-#endif
+ d->setError(QFile::RemoveError, fileEngine()->errorString());
}
return false;
}
@@ -708,6 +697,7 @@ QFile::rename(const QString &newName)
d->setError(QFile::RenameError, tr("Destination file exists"));
return false;
}
+ unsetError();
close();
if(error() == QFile::NoError) {
if (fileEngine()->rename(newName)) {
@@ -746,9 +736,10 @@ QFile::rename(const QString &newName)
error = true;
}
}
- if (error)
+ if (error) {
out.remove();
- else {
+ } else {
+ fileEngine()->setFileName(newName);
setPermissions(permissions());
unsetError();
setFileName(newName);
@@ -794,6 +785,9 @@ QFile::rename(const QString &oldName, const QString &newName)
\note To create a valid link on Windows, \a linkName must have a \c{.lnk} file extension.
+ \note On Symbian, no link is created and false is returned if fileName()
+ currently specifies a directory.
+
\sa setFileName()
*/
@@ -810,7 +804,7 @@ QFile::link(const QString &linkName)
unsetError();
return true;
}
- d->setError(QFile::RenameError, errno);
+ d->setError(QFile::RenameError, fileEngine()->errorString());
return false;
}
@@ -858,6 +852,7 @@ QFile::copy(const QString &newName)
d->setError(QFile::CopyError, tr("Destination file exists"));
return false;
}
+ unsetError();
close();
if(error() == QFile::NoError) {
if(fileEngine()->copy(newName)) {
@@ -1255,7 +1250,7 @@ QFile::resize(qint64 sz)
unsetError();
return true;
}
- d->setError(QFile::ResizeError, errno);
+ d->setError(QFile::ResizeError, fileEngine()->errorString());
return false;
}
@@ -1319,7 +1314,7 @@ QFile::setPermissions(Permissions permissions)
unsetError();
return true;
}
- d->setError(QFile::PermissionsError, errno);
+ d->setError(QFile::PermissionsError, fileEngine()->errorString());
return false;
}
@@ -1475,7 +1470,7 @@ bool QFile::seek(qint64 off)
d->setError(err, fileEngine()->errorString());
return false;
}
- d->error = NoError;
+ unsetError();
return true;
}
@@ -1503,7 +1498,7 @@ qint64 QFile::readLineData(char *data, qint64 maxlen)
qint64 QFile::readData(char *data, qint64 len)
{
Q_D(QFile);
- d->error = NoError;
+ unsetError();
if (!d->ensureFlushed())
return -1;
@@ -1585,7 +1580,7 @@ qint64
QFile::writeData(const char *data, qint64 len)
{
Q_D(QFile);
- d->error = NoError;
+ unsetError();
d->lastWasWrite = true;
bool buffered = !(d->openMode & Unbuffered);
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 382f136..5514a74 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -48,73 +48,10 @@
#include "qatomic.h"
#include "qhash.h"
#include "qdir.h"
+#include "qfileinfo_p.h"
QT_BEGIN_NAMESPACE
-class QFileInfoPrivate
-{
-public:
- QFileInfoPrivate(const QFileInfo *copy=0);
- ~QFileInfoPrivate();
-
- void initFileEngine(const QString &);
-
- enum Access {
- ReadAccess,
- WriteAccess,
- ExecuteAccess
- };
- bool hasAccess(Access access) const;
-
- uint getFileFlags(QAbstractFileEngine::FileFlags) const;
- QDateTime &getFileTime(QAbstractFileEngine::FileTime) const;
- QString getFileName(QAbstractFileEngine::FileName) const;
-
- enum { CachedFileFlags=0x01, CachedLinkTypeFlag=0x02, CachedBundleTypeFlag=0x04,
- CachedMTime=0x10, CachedCTime=0x20, CachedATime=0x40,
- CachedSize =0x08 };
- struct Data {
- inline Data()
- : ref(1), fileEngine(0), cache_enabled(1)
- { clear(); }
- inline Data(const Data &copy)
- : ref(1), fileEngine(QAbstractFileEngine::create(copy.fileName)),
- fileName(copy.fileName), cache_enabled(copy.cache_enabled)
- { clear(); }
- inline ~Data() { delete fileEngine; }
- inline void clearFlags() {
- fileFlags = 0;
- cachedFlags = 0;
- if (fileEngine)
- (void)fileEngine->fileFlags(QFSFileEngine::Refresh);
- }
- inline void clear() {
- fileNames.clear();
- clearFlags();
- }
- mutable QAtomicInt ref;
-
- QAbstractFileEngine *fileEngine;
- mutable QString fileName;
- mutable QHash<int, QString> fileNames;
-
- mutable uint cachedFlags : 31;
- mutable uint cache_enabled : 1;
- mutable uint fileFlags;
- mutable qint64 fileSize;
- mutable QDateTime fileTimes[3];
- inline bool getCachedFlag(uint c) const
- { return cache_enabled ? (cachedFlags & c) : 0; }
- inline void setCachedFlag(uint c)
- { if (cache_enabled) cachedFlags |= c; }
- } *data;
- inline void reset() {
- detach();
- data->clear();
- }
- void detach();
-};
-
QFileInfoPrivate::QFileInfoPrivate(const QFileInfo *copy)
{
if(copy) {
@@ -122,7 +59,6 @@ QFileInfoPrivate::QFileInfoPrivate(const QFileInfo *copy)
data = copy->d_func()->data;
} else {
data = new QFileInfoPrivate::Data;
- data->clear();
}
}
@@ -181,11 +117,7 @@ bool QFileInfoPrivate::hasAccess(Access access) const
if (access == ExecuteAccess)
return getFileFlags(QAbstractFileEngine::ExeUserPerm);
- QT_WA( {
- return ::_waccess((TCHAR *)QFSFileEnginePrivate::longFileName(data->fileName).utf16(), mode) == 0;
- } , {
- return QT_ACCESS(QFSFileEnginePrivate::win95Name(data->fileName), mode) == 0;
- } );
+ return ::_waccess((wchar_t*)QFSFileEnginePrivate::longFileName(data->fileName).utf16(), mode) == 0;
#endif
return false;
}
@@ -197,11 +129,11 @@ void QFileInfoPrivate::detach()
QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const
{
- if(data->cache_enabled && data->fileNames.contains((int)name))
- return data->fileNames.value(name);
+ if(data->cache_enabled && !data->fileNames[(int)name].isNull())
+ return data->fileNames[(int)name];
QString ret = data->fileEngine->fileName(name);
if(data->cache_enabled)
- data->fileNames.insert((int)name, ret);
+ data->fileNames[(int)name] = ret;
return ret;
}
@@ -439,8 +371,6 @@ QFileInfo::QFileInfo(const QFileInfo &fileinfo) : d_ptr(new QFileInfoPrivate(&fi
QFileInfo::~QFileInfo()
{
- delete d_ptr;
- d_ptr = 0;
}
/*!
@@ -537,8 +467,7 @@ QFileInfo &QFileInfo::operator=(const QFileInfo &fileinfo)
void QFileInfo::setFile(const QString &file)
{
- Q_D(QFileInfo);
- d->initFileEngine(file);
+ *this = QFileInfo(file);
}
/*!
@@ -555,8 +484,7 @@ void QFileInfo::setFile(const QString &file)
void QFileInfo::setFile(const QFile &file)
{
- Q_D(QFileInfo);
- d->initFileEngine(file.fileName());
+ *this = QFileInfo(file.fileName());
}
/*!
@@ -573,8 +501,7 @@ void QFileInfo::setFile(const QFile &file)
void QFileInfo::setFile(const QDir &dir, const QString &file)
{
- Q_D(QFileInfo);
- d->initFileEngine(dir.filePath(file));
+ *this = QFileInfo(dir.filePath(file));
}
/*!
@@ -921,7 +848,7 @@ QString QFileInfo::suffix() const
\bold{Note:} The QDir returned always corresponds to the object's
parent directory, even if the QFileInfo represents a directory.
-
+
For each of the follwing, dir() returns a QDir for
\c{"~/examples/191697"}.
diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h
index 13f683b..5d6949f 100644
--- a/src/corelib/io/qfileinfo.h
+++ b/src/corelib/io/qfileinfo.h
@@ -44,6 +44,7 @@
#include <QtCore/qfile.h>
#include <QtCore/qlist.h>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_HEADER
@@ -165,7 +166,7 @@ public:
#endif
protected:
- QFileInfoPrivate *d_ptr;
+ QScopedPointer<QFileInfoPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(QFileInfo)
};
diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h
index 343a542..680d884 100644
--- a/src/corelib/io/qfileinfo_p.h
+++ b/src/corelib/io/qfileinfo_p.h
@@ -46,8 +46,8 @@
// W A R N I N G
// -------------
//
-// This file is not part of the Qt API. It exists for the convenience
-// of QIODevice. This header file may change from version to
+// 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.
@@ -76,70 +76,52 @@ public:
QDateTime &getFileTime(QAbstractFileEngine::FileTime) const;
QString getFileName(QAbstractFileEngine::FileName) const;
- enum {
- CachedFileFlags = 0x01,
- CachedLinkTypeFlag = 0x02,
- CachedBundleTypeFlag= 0x04,
- CachedMTime = 0x10,
- CachedCTime = 0x20,
- CachedATime = 0x40,
- CachedSize = 0x08
- };
-
- struct Data
- {
+ enum { CachedFileFlags=0x01, CachedLinkTypeFlag=0x02, CachedBundleTypeFlag=0x04,
+ CachedMTime=0x10, CachedCTime=0x20, CachedATime=0x40,
+ CachedSize =0x08 };
+ struct Data {
inline Data()
- : ref(1), fileEngine(0), cache_enabled(1)
- {
- clear();
- }
-
+ : ref(1), fileEngine(0), cache_enabled(1), fileSize(0)
+ { clear(); }
inline Data(const Data &copy)
: ref(1), fileEngine(QAbstractFileEngine::create(copy.fileName)),
- fileName(copy.fileName), cache_enabled(copy.cache_enabled)
- {
- clear();
- }
-
- inline ~Data()
- {
- delete fileEngine;
- }
-
- inline void clear()
- {
- fileNames.clear();
+ fileName(copy.fileName), cache_enabled(copy.cache_enabled), fileSize(copy.fileSize)
+ { clear(); }
+ inline ~Data() { delete fileEngine; }
+ inline void clearFlags() {
fileFlags = 0;
cachedFlags = 0;
+ if (fileEngine)
+ (void)fileEngine->fileFlags(QFSFileEngine::Refresh);
+ }
+ inline void clear() {
+ clearFlags();
+ for (int i = QAbstractFileEngine::NFileNames - 1 ; i >= 0 ; --i)
+ fileNames[i].clear();
}
-
mutable QAtomicInt ref;
QAbstractFileEngine *fileEngine;
mutable QString fileName;
- mutable QHash<int, QString> fileNames;
+ mutable QString fileNames[QAbstractFileEngine::NFileNames];
+
mutable uint cachedFlags : 31;
mutable uint cache_enabled : 1;
mutable uint fileFlags;
mutable qint64 fileSize;
mutable QDateTime fileTimes[3];
-
inline bool getCachedFlag(uint c) const
{ return cache_enabled ? (cachedFlags & c) : 0; }
-
inline void setCachedFlag(uint c)
{ if (cache_enabled) cachedFlags |= c; }
} *data;
-
inline void reset() {
detach();
data->clear();
}
-
void detach();
};
-
QT_END_NAMESPACE
-#endif
+#endif // QFILEINFO_P_H
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index 0af4c95..c5f98e6 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -58,7 +58,12 @@
# include "qfilesystemwatcher_inotify_p.h"
# include "qfilesystemwatcher_dnotify_p.h"
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
+# if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+# include "qfilesystemwatcher_fsevents_p.h"
+# endif //MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
# include "qfilesystemwatcher_kqueue_p.h"
+#elif defined(Q_OS_SYMBIAN)
+# include "qfilesystemwatcher_symbian_p.h"
#endif
QT_BEGIN_NAMESPACE
@@ -118,7 +123,7 @@ public:
void stop();
-private slots:
+private Q_SLOTS:
void timeout();
};
@@ -243,7 +248,14 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine()
eng = QDnotifyFileSystemWatcherEngine::create();
return eng;
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
- return QKqueueFileSystemWatcherEngine::create();
+# if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
+ return QFSEventsFileSystemWatcherEngine::create();
+ else
+# endif
+ return QKqueueFileSystemWatcherEngine::create();
+#elif defined(Q_OS_SYMBIAN)
+ return new QSymbianFileSystemWatcherEngine;
#else
return 0;
#endif
@@ -376,15 +388,17 @@ void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool re
\note The act of monitoring files and directories for
modifications consumes system resources. This implies there is a
limit to the number of files and directories your process can
- monitor simultaneously. On Mac OS and all BSD variants, for
+ monitor simultaneously. On Mac OS X 10.4 and all BSD variants, for
example, an open file descriptor is required for each monitored
- file. The system limits the number of open file descriptors to 256
+ file. Some system limits the number of open file descriptors to 256
by default. This means that addPath() and addPaths() will fail if
your process tries to add more than 256 files or directories to
the file system monitor. Also note that your process may have
other file descriptors open in addition to the ones for files
being monitored, and these other open descriptors also count in
- the total.
+ the total. Mac OS X 10.5 and up use a different backend and do not
+ suffer from this issue.
+
\sa QFile, QDir
*/
diff --git a/src/corelib/io/qfilesystemwatcher_dnotify.cpp b/src/corelib/io/qfilesystemwatcher_dnotify.cpp
index 58a127a..1ef26cc 100644
--- a/src/corelib/io/qfilesystemwatcher_dnotify.cpp
+++ b/src/corelib/io/qfilesystemwatcher_dnotify.cpp
@@ -59,6 +59,8 @@
#include <fcntl.h>
#include <time.h>
+#include "private/qcore_unix_p.h"
+
#ifdef QT_LINUXBASE
/* LSB doesn't standardize these */
@@ -80,7 +82,7 @@ static void (*qfswd_old_sigio_handler)(int) = 0;
static void (*qfswd_old_sigio_action)(int, siginfo_t *, void *) = 0;
static void qfswd_sigio_monitor(int signum, siginfo_t *i, void *v)
{
- ::write(qfswd_fileChanged_pipe[1], &i->si_fd, sizeof(int));
+ qt_safe_write(qfswd_fileChanged_pipe[1], reinterpret_cast<char*>(&i->si_fd), sizeof(int));
if (qfswd_old_sigio_handler && qfswd_old_sigio_handler != SIG_IGN)
qfswd_old_sigio_handler(signum);
@@ -114,16 +116,14 @@ private:
bool isExecing;
};
-Q_GLOBAL_STATIC(QDnotifySignalThread, dnotifySignal);
+Q_GLOBAL_STATIC(QDnotifySignalThread, dnotifySignal)
QDnotifySignalThread::QDnotifySignalThread()
: isExecing(false)
{
moveToThread(this);
- ::pipe(qfswd_fileChanged_pipe);
- ::fcntl(qfswd_fileChanged_pipe[0], F_SETFL,
- ::fcntl(qfswd_fileChanged_pipe[0], F_GETFL) | O_NONBLOCK);
+ qt_safe_pipe(qfswd_fileChanged_pipe, O_NONBLOCK);
struct sigaction oldAction;
struct sigaction action;
@@ -181,7 +181,7 @@ void QDnotifySignalThread::run()
void QDnotifySignalThread::readFromDnotify()
{
int fd;
- int readrv = ::read(qfswd_fileChanged_pipe[0], &fd,sizeof(int));
+ int readrv = qt_safe_read(qfswd_fileChanged_pipe[0], reinterpret_cast<char*>(&fd), sizeof(int));
// Only expect EAGAIN or EINTR. Other errors are assumed to be impossible.
if(readrv != -1) {
Q_ASSERT(readrv == sizeof(int));
@@ -207,9 +207,9 @@ QDnotifyFileSystemWatcherEngine::~QDnotifyFileSystemWatcherEngine()
for(QHash<int, Directory>::ConstIterator iter = fdToDirectory.constBegin();
iter != fdToDirectory.constEnd();
++iter) {
- ::close(iter->fd);
+ qt_safe_close(iter->fd);
if(iter->parentFd)
- ::close(iter->parentFd);
+ qt_safe_close(iter->parentFd);
}
}
@@ -353,7 +353,7 @@ QStringList QDnotifyFileSystemWatcherEngine::removePaths(const QStringList &path
if(!directory.isMonitored && directory.files.isEmpty()) {
// No longer needed
- ::close(directory.fd);
+ qt_safe_close(directory.fd);
pathToFD.remove(directory.path);
fdToDirectory.remove(fd);
}
@@ -419,9 +419,9 @@ void QDnotifyFileSystemWatcherEngine::refresh(int fd)
}
if(!directory.isMonitored && directory.files.isEmpty()) {
- ::close(directory.fd);
+ qt_safe_close(directory.fd);
if(directory.parentFd) {
- ::close(directory.parentFd);
+ qt_safe_close(directory.parentFd);
parentToFD.remove(directory.parentFd);
}
fdToDirectory.erase(iter);
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.cpp b/src/corelib/io/qfilesystemwatcher_fsevents.cpp
new file mode 100644
index 0000000..182ddd4
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_fsevents.cpp
@@ -0,0 +1,472 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <qplatformdefs.h>
+
+#include "qfilesystemwatcher.h"
+#include "qfilesystemwatcher_fsevents_p.h"
+
+#include <qdebug.h>
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qfileinfo.h>
+#include <qvarlengtharray.h>
+
+#include <mach/mach.h>
+#include <sys/types.h>
+#include <CoreFoundation/CFRunLoop.h>
+#include <CoreFoundation/CFUUID.h>
+#include <CoreServices/CoreServices.h>
+#include <AvailabilityMacros.h>
+#include <private/qcore_mac_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+// Static operator overloading so for the sake of some convieniece.
+// They only live in this compilation unit to avoid polluting Qt in general.
+static bool operator==(const struct ::timespec &left, const struct ::timespec &right)
+{
+ return left.tv_sec == right.tv_sec
+ && left.tv_nsec == right.tv_nsec;
+}
+
+static bool operator==(const struct ::stat64 &left, const struct ::stat64 &right)
+{
+ return left.st_dev == right.st_dev
+ && left.st_mode == right.st_mode
+ && left.st_size == right.st_size
+ && left.st_ino == right.st_ino
+ && left.st_uid == right.st_uid
+ && left.st_gid == right.st_gid
+ && left.st_mtimespec == right.st_mtimespec
+ && left.st_ctimespec == right.st_ctimespec
+ && left.st_flags == right.st_flags;
+}
+
+static bool operator!=(const struct ::stat64 &left, const struct ::stat64 &right)
+{
+ return !(operator==(left, right));
+}
+
+
+static void addPathToHash(PathHash &pathHash, const QString &key, const QFileInfo &fileInfo,
+ const QString &path)
+{
+ PathInfoList &list = pathHash[key];
+ list.push_back(PathInfo(path,
+ fileInfo.absoluteFilePath().normalized(QString::NormalizationForm_D).toUtf8()));
+ pathHash.insert(key, list);
+}
+
+static void removePathFromHash(PathHash &pathHash, const QString &key, const QString &path)
+{
+ PathInfoList &list = pathHash[key];
+ // We make the assumption that the list contains unique paths
+ PathInfoList::iterator End = list.end();
+ PathInfoList::iterator it = list.begin();
+ while (it != End) {
+ if (it->originalPath == path) {
+ list.erase(it);
+ break;
+ }
+ ++it;
+ }
+ if (list.isEmpty())
+ pathHash.remove(key);
+}
+
+static void stopFSStream(FSEventStreamRef stream)
+{
+ if (stream) {
+ FSEventStreamStop(stream);
+ FSEventStreamInvalidate(stream);
+ }
+}
+
+static QString createFSStreamPath(const QString &absolutePath)
+{
+ // The path returned has a trailing slash, so ensure that here.
+ QString string = absolutePath;
+ string.reserve(string.size() + 1);
+ string.append(QLatin1Char('/'));
+ return string;
+}
+
+static void cleanupFSStream(FSEventStreamRef stream)
+{
+ if (stream)
+ FSEventStreamRelease(stream);
+}
+
+const FSEventStreamCreateFlags QtFSEventFlags = (kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagNoDefer /* | kFSEventStreamCreateFlagWatchRoot*/);
+
+const CFTimeInterval Latency = 0.033; // This will do updates 30 times a second which is probably more than you need.
+#endif
+
+QFSEventsFileSystemWatcherEngine::QFSEventsFileSystemWatcherEngine()
+ : fsStream(0), pathsToWatch(0), threadsRunLoop(0)
+{
+}
+
+QFSEventsFileSystemWatcherEngine::~QFSEventsFileSystemWatcherEngine()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ // I assume that at this point, QFileSystemWatcher has already called stop
+ // on me, so I don't need to invalidate or stop my stream, simply
+ // release it.
+ cleanupFSStream(fsStream);
+ if (pathsToWatch)
+ CFRelease(pathsToWatch);
+#endif
+}
+
+QFSEventsFileSystemWatcherEngine *QFSEventsFileSystemWatcherEngine::create()
+{
+ return new QFSEventsFileSystemWatcherEngine();
+}
+
+QStringList QFSEventsFileSystemWatcherEngine::addPaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ stop();
+ QMutexLocker locker(&mutex);
+ QStringList failedToAdd;
+ // if we have a running FSStreamEvent, we have to kill it, we'll re-add the stream soon.
+ FSEventStreamEventId idToCheck;
+ if (fsStream) {
+ idToCheck = FSEventStreamGetLatestEventId(fsStream);
+ cleanupFSStream(fsStream);
+ } else {
+ idToCheck = kFSEventStreamEventIdSinceNow;
+ }
+
+ // Brain-dead approach, but works. FSEvents actually can already read sub-trees, but since it's
+ // work to figure out if we are doing a double register, we just register it twice as FSEvents
+ // seems smart enough to only deliver one event. We also duplicate directory entries in here
+ // (e.g., if you watch five files in the same directory, you get that directory included in the
+ // array 5 times). This stupidity also makes remove work correctly though. I'll freely admit
+ // that we could make this a bit smarter. If you do, check the auto-tests, they should catch at
+ // least a couple of the issues.
+ QCFType<CFMutableArrayRef> tmpArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ for (int i = 0; i < paths.size(); ++i) {
+ const QString &path = paths.at(i);
+
+ QFileInfo fileInfo(path);
+ if (!fileInfo.exists()) {
+ failedToAdd.append(path);
+ continue;
+ }
+
+ if (fileInfo.isDir()) {
+ if (directories->contains(path)) {
+ failedToAdd.append(path);
+ continue;
+ } else {
+ directories->append(path);
+ // Full file path for dirs.
+ QCFString cfpath(createFSStreamPath(fileInfo.absoluteFilePath()));
+ addPathToHash(dirPathInfoHash, cfpath, fileInfo, path);
+ CFArrayAppendValue(tmpArray, cfpath);
+ }
+ } else {
+ if (files->contains(path)) {
+ failedToAdd.append(path);
+ continue;
+ } else {
+ // Just the absolute path (minus it's filename) for files.
+ QCFString cfpath(createFSStreamPath(fileInfo.absolutePath()));
+ files->append(path);
+ addPathToHash(filePathInfoHash, cfpath, fileInfo, path);
+ CFArrayAppendValue(tmpArray, cfpath);
+ }
+ }
+ }
+ if (CFArrayGetCount(tmpArray) > 0) {
+ if (pathsToWatch) {
+ CFArrayAppendArray(tmpArray, pathsToWatch, CFRangeMake(0, CFArrayGetCount(pathsToWatch)));
+ CFRelease(pathsToWatch);
+ }
+ pathsToWatch = CFArrayCreateCopy(kCFAllocatorDefault, tmpArray);
+ }
+ FSEventStreamContext context = { 0, this, 0, 0, 0 };
+ fsStream = FSEventStreamCreate(kCFAllocatorDefault,
+ QFSEventsFileSystemWatcherEngine::fseventsCallback,
+ &context, pathsToWatch,
+ idToCheck, Latency, QtFSEventFlags);
+ warmUpFSEvents();
+
+ return failedToAdd;
+#else
+ Q_UNUSED(paths);
+ Q_UNUSED(files);
+ Q_UNUSED(directories);
+ return QStringList();
+#endif
+}
+
+void QFSEventsFileSystemWatcherEngine::warmUpFSEvents()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ // This function assumes that the mutex has already been grabbed before calling it.
+ // It exits with the mutex still locked (Q_ASSERT(mutex.isLocked()) ;-).
+ start();
+ waitCondition.wait(&mutex);
+#endif
+}
+
+QStringList QFSEventsFileSystemWatcherEngine::removePaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ stop();
+ QMutexLocker locker(&mutex);
+ // short circuit for smarties that call remove before add and we have nothing.
+ if (pathsToWatch == 0)
+ return paths;
+ QStringList failedToRemove;
+ // if we have a running FSStreamEvent, we have to stop it, we'll re-add the stream soon.
+ FSEventStreamEventId idToCheck;
+ if (fsStream) {
+ idToCheck = FSEventStreamGetLatestEventId(fsStream);
+ cleanupFSStream(fsStream);
+ fsStream = 0;
+ } else {
+ idToCheck = kFSEventStreamEventIdSinceNow;
+ }
+
+ CFIndex itemCount = CFArrayGetCount(pathsToWatch);
+ QCFType<CFMutableArrayRef> tmpArray = CFArrayCreateMutableCopy(kCFAllocatorDefault, itemCount,
+ pathsToWatch);
+ CFRelease(pathsToWatch);
+ pathsToWatch = 0;
+ for (int i = 0; i < paths.size(); ++i) {
+ // Get the itemCount at the beginning to avoid any overruns during the iteration.
+ itemCount = CFArrayGetCount(tmpArray);
+ const QString &path = paths.at(i);
+ QFileInfo fi(path);
+ QCFString cfpath(createFSStreamPath(fi.absolutePath()));
+
+ CFIndex index = CFArrayGetFirstIndexOfValue(tmpArray, CFRangeMake(0, itemCount), cfpath);
+ if (index != -1) {
+ CFArrayRemoveValueAtIndex(tmpArray, index);
+ files->removeAll(path);
+ removePathFromHash(filePathInfoHash, cfpath, path);
+ } else {
+ // Could be a directory we are watching instead.
+ QCFString cfdirpath(createFSStreamPath(fi.absoluteFilePath()));
+ index = CFArrayGetFirstIndexOfValue(tmpArray, CFRangeMake(0, itemCount), cfdirpath);
+ if (index != -1) {
+ CFArrayRemoveValueAtIndex(tmpArray, index);
+ directories->removeAll(path);
+ removePathFromHash(dirPathInfoHash, cfpath, path);
+ } else {
+ failedToRemove.append(path);
+ }
+ }
+ }
+ itemCount = CFArrayGetCount(tmpArray);
+ if (itemCount != 0) {
+ pathsToWatch = CFArrayCreateCopy(kCFAllocatorDefault, tmpArray);
+
+ FSEventStreamContext context = { 0, this, 0, 0, 0 };
+ fsStream = FSEventStreamCreate(kCFAllocatorDefault,
+ QFSEventsFileSystemWatcherEngine::fseventsCallback,
+ &context, pathsToWatch, idToCheck, Latency, QtFSEventFlags);
+ warmUpFSEvents();
+ }
+ return failedToRemove;
+#else
+ Q_UNUSED(paths);
+ Q_UNUSED(files);
+ Q_UNUSED(directories);
+ return QStringList();
+#endif
+}
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+void QFSEventsFileSystemWatcherEngine::updateList(PathInfoList &list, bool directory, bool emitSignals)
+{
+ PathInfoList::iterator End = list.end();
+ PathInfoList::iterator it = list.begin();
+ while (it != End) {
+ struct ::stat64 newInfo;
+ if (::stat64(it->absolutePath, &newInfo) == 0) {
+ if (emitSignals) {
+ if (newInfo != it->savedInfo) {
+ it->savedInfo = newInfo;
+ if (directory)
+ emit directoryChanged(it->originalPath, false);
+ else
+ emit fileChanged(it->originalPath, false);
+ }
+ } else {
+ it->savedInfo = newInfo;
+ }
+ } else {
+ if (errno == ENOENT) {
+ if (emitSignals) {
+ if (directory)
+ emit directoryChanged(it->originalPath, true);
+ else
+ emit fileChanged(it->originalPath, true);
+ }
+ it = list.erase(it);
+ continue;
+ } else {
+ qWarning("%s:%d:QFSEventsFileSystemWatcherEngine: stat error on %s:%s",
+ __FILE__, __LINE__, qPrintable(it->originalPath), strerror(errno));
+
+ }
+ }
+ ++it;
+ }
+}
+
+void QFSEventsFileSystemWatcherEngine::updateHash(PathHash &pathHash)
+{
+ PathHash::iterator HashEnd = pathHash.end();
+ PathHash::iterator it = pathHash.begin();
+ const bool IsDirectory = (&pathHash == &dirPathInfoHash);
+ while (it != HashEnd) {
+ updateList(it.value(), IsDirectory, false);
+ if (it.value().isEmpty())
+ it = pathHash.erase(it);
+ else
+ ++it;
+ }
+}
+#endif
+
+void QFSEventsFileSystemWatcherEngine::fseventsCallback(ConstFSEventStreamRef ,
+ void *clientCallBackInfo, size_t numEvents,
+ void *eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId [])
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ QFSEventsFileSystemWatcherEngine *watcher = static_cast<QFSEventsFileSystemWatcherEngine *>(clientCallBackInfo);
+ QMutexLocker locker(&watcher->mutex);
+ CFArrayRef paths = static_cast<CFArrayRef>(eventPaths);
+ for (size_t i = 0; i < numEvents; ++i) {
+ const QString path = QCFString::toQString(
+ static_cast<CFStringRef>(CFArrayGetValueAtIndex(paths, i)));
+ const FSEventStreamEventFlags pathFlags = eventFlags[i];
+ // There are several flags that may be passed, but we really don't care about them ATM.
+ // Here they are and why we don't care.
+ // kFSEventStreamEventFlagHistoryDone--(very unlikely to be gotten, but even then, not much changes).
+ // kFSEventStreamEventFlagMustScanSubDirs--Likely means the data is very much out of date, we
+ // aren't coalescing our directories, so again not so much of an issue
+ // kFSEventStreamEventFlagRootChanged | kFSEventStreamEventFlagMount | kFSEventStreamEventFlagUnmount--
+ // These three flags indicate something has changed, but the stat will likely show this, so
+ // there's not really much to worry about.
+ // (btw, FSEvents is not the correct way of checking for mounts/unmounts,
+ // there are real CarbonCore events for that.)
+ Q_UNUSED(pathFlags);
+ if (watcher->filePathInfoHash.contains(path))
+ watcher->updateList(watcher->filePathInfoHash[path], false, true);
+
+ if (watcher->dirPathInfoHash.contains(path))
+ watcher->updateList(watcher->dirPathInfoHash[path], true, true);
+ }
+#else
+ Q_UNUSED(clientCallBackInfo);
+ Q_UNUSED(numEvents);
+ Q_UNUSED(eventPaths);
+ Q_UNUSED(eventFlags);
+#endif
+}
+
+void QFSEventsFileSystemWatcherEngine::stop()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ QMutexLocker locker(&mutex);
+ stopFSStream(fsStream);
+ if (threadsRunLoop) {
+ CFRunLoopStop(threadsRunLoop);
+ waitForStop.wait(&mutex);
+ }
+#endif
+}
+
+void QFSEventsFileSystemWatcherEngine::updateFiles()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ QMutexLocker locker(&mutex);
+ updateHash(filePathInfoHash);
+ updateHash(dirPathInfoHash);
+ if (filePathInfoHash.isEmpty() && dirPathInfoHash.isEmpty()) {
+ // Everything disappeared before we got to start, don't bother.
+ stop();
+ cleanupFSStream(fsStream);
+ }
+ waitCondition.wakeAll();
+#endif
+}
+
+void QFSEventsFileSystemWatcherEngine::run()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ threadsRunLoop = CFRunLoopGetCurrent();
+ FSEventStreamScheduleWithRunLoop(fsStream, threadsRunLoop, kCFRunLoopDefaultMode);
+ bool startedOK = FSEventStreamStart(fsStream);
+ // It's recommended by Apple that you only update the files after you've started
+ // the stream, because otherwise you might miss an update in between starting it.
+ updateFiles();
+#ifdef QT_NO_DEBUG
+ Q_UNUSED(startedOK);
+#else
+ Q_ASSERT(startedOK);
+#endif
+ // If for some reason we called stop up above (and invalidated our stream), this call will return
+ // immediately.
+ CFRunLoopRun();
+ threadsRunLoop = 0;
+ QMutexLocker locker(&mutex);
+ waitForStop.wakeAll();
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents_p.h b/src/corelib/io/qfilesystemwatcher_fsevents_p.h
new file mode 100644
index 0000000..317c149
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_fsevents_p.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef FILEWATCHER_FSEVENTS_P_H
+#define FILEWATCHER_FSEVENTS_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 "qfilesystemwatcher_p.h"
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qlinkedlist.h>
+#include <private/qcore_mac_p.h>
+#include <sys/stat.h>
+
+typedef struct __FSEventStream *FSEventStreamRef;
+typedef const struct __FSEventStream *ConstFSEventStreamRef;
+typedef const struct __CFArray *CFArrayRef;
+typedef UInt32 FSEventStreamEventFlags;
+typedef uint64_t FSEventStreamEventId;
+
+QT_BEGIN_NAMESPACE
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+// Yes, I use a stat64 element here. QFileInfo requires too much knowledge about implementation
+// details to be used as a long-standing record. Since I'm going to have to store this information, I can
+// do the stat myself too.
+struct PathInfo {
+ PathInfo(const QString &path, const QByteArray &absPath)
+ : originalPath(path), absolutePath(absPath) {}
+ QString originalPath; // The path we need to emit
+ QByteArray absolutePath; // The path we need to stat.
+ struct ::stat64 savedInfo; // All the info for the path so we can compare it.
+};
+typedef QLinkedList<PathInfo> PathInfoList;
+typedef QHash<QString, PathInfoList> PathHash;
+#endif
+
+class QFSEventsFileSystemWatcherEngine : public QFileSystemWatcherEngine
+{
+ Q_OBJECT
+public:
+ ~QFSEventsFileSystemWatcherEngine();
+
+ static QFSEventsFileSystemWatcherEngine *create();
+
+ QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
+ QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories);
+
+ void stop();
+
+private:
+ QFSEventsFileSystemWatcherEngine();
+ void warmUpFSEvents();
+ void updateFiles();
+
+ static void fseventsCallback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents,
+ void *eventPaths, const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[]);
+ void run();
+ FSEventStreamRef fsStream;
+ CFArrayRef pathsToWatch;
+ CFRunLoopRef threadsRunLoop;
+ QMutex mutex;
+ QWaitCondition waitCondition;
+ QWaitCondition waitForStop;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ PathHash filePathInfoHash;
+ PathHash dirPathInfoHash;
+ void updateHash(PathHash &pathHash);
+ void updateList(PathInfoList &list, bool directory, bool emitSignals);
+#endif
+};
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp
index 630b86b..8a4e09b 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify.cpp
+++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp
@@ -44,6 +44,8 @@
#ifndef QT_NO_FILESYSTEMWATCHER
+#include "private/qcore_unix_p.h"
+
#include <qdebug.h>
#include <qfile.h>
#include <qfileinfo.h>
@@ -62,62 +64,80 @@
# define __NR_inotify_init 291
# define __NR_inotify_add_watch 292
# define __NR_inotify_rm_watch 293
+# define __NR_inotify_init1 332
#elif defined(__x86_64__)
# define __NR_inotify_init 253
# define __NR_inotify_add_watch 254
# define __NR_inotify_rm_watch 255
+# define __NR_inotify_init1 294
#elif defined(__powerpc__) || defined(__powerpc64__)
# define __NR_inotify_init 275
# define __NR_inotify_add_watch 276
# define __NR_inotify_rm_watch 277
+# define __NR_inotify_init1 318
#elif defined (__ia64__)
# define __NR_inotify_init 1277
# define __NR_inotify_add_watch 1278
# define __NR_inotify_rm_watch 1279
+# define __NR_inotify_init1 1318
#elif defined (__s390__) || defined (__s390x__)
# define __NR_inotify_init 284
# define __NR_inotify_add_watch 285
# define __NR_inotify_rm_watch 286
+# define __NR_inotify_init1 324
#elif defined (__alpha__)
# define __NR_inotify_init 444
# define __NR_inotify_add_watch 445
# define __NR_inotify_rm_watch 446
+// no inotify_init1 for the Alpha
#elif defined (__sparc__) || defined (__sparc64__)
# define __NR_inotify_init 151
# define __NR_inotify_add_watch 152
# define __NR_inotify_rm_watch 156
+# define __NR_inotify_init1 322
#elif defined (__arm__)
# define __NR_inotify_init 316
# define __NR_inotify_add_watch 317
# define __NR_inotify_rm_watch 318
+# define __NR_inotify_init1 360
#elif defined (__sh__)
# define __NR_inotify_init 290
# define __NR_inotify_add_watch 291
# define __NR_inotify_rm_watch 292
+# define __NR_inotify_init1 332
#elif defined (__sh64__)
# define __NR_inotify_init 318
# define __NR_inotify_add_watch 319
# define __NR_inotify_rm_watch 320
+# define __NR_inotify_init1 360
#elif defined (__mips__)
# define __NR_inotify_init 284
# define __NR_inotify_add_watch 285
# define __NR_inotify_rm_watch 286
+# define __NR_inotify_init1 329
#elif defined (__hppa__)
# define __NR_inotify_init 269
# define __NR_inotify_add_watch 270
# define __NR_inotify_rm_watch 271
+# define __NR_inotify_init1 314
#elif defined (__avr32__)
# define __NR_inotify_init 240
# define __NR_inotify_add_watch 241
# define __NR_inotify_rm_watch 242
+// no inotify_init1 for AVR32
#elif defined (__mc68000__)
# define __NR_inotify_init 284
# define __NR_inotify_add_watch 285
# define __NR_inotify_rm_watch 286
+# define __NR_inotify_init1 328
#else
# error "This architecture is not supported. Please talk to qt-bugs@trolltech.com"
#endif
+#if !defined(IN_CLOEXEC) && defined(O_CLOEXEC) && defined(__NR_inotify_init1)
+# define IN_CLOEXEC O_CLOEXEC
+#endif
+
QT_BEGIN_NAMESPACE
#ifdef QT_LINUXBASE
@@ -140,6 +160,13 @@ static inline int inotify_rm_watch(int fd, __u32 wd)
return syscall(__NR_inotify_rm_watch, fd, wd);
}
+#ifdef IN_CLOEXEC
+static inline int inotify_init1(int flags)
+{
+ return syscall(__NR_inotify_init1, flags);
+}
+#endif
+
// the following struct and values are documented in linux/inotify.h
extern "C" {
@@ -185,9 +212,16 @@ QT_BEGIN_NAMESPACE
QInotifyFileSystemWatcherEngine *QInotifyFileSystemWatcherEngine::create()
{
- int fd = inotify_init();
- if (fd <= 0)
- return 0;
+ register int fd = -1;
+#ifdef IN_CLOEXEC
+ fd = inotify_init1(IN_CLOEXEC);
+#endif
+ if (fd == -1) {
+ fd = inotify_init();
+ if (fd == -1)
+ return 0;
+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+ }
return new QInotifyFileSystemWatcherEngine(fd);
}
diff --git a/src/corelib/io/qfilesystemwatcher_kqueue.cpp b/src/corelib/io/qfilesystemwatcher_kqueue.cpp
index f4f44e8..2a9473f 100644
--- a/src/corelib/io/qfilesystemwatcher_kqueue.cpp
+++ b/src/corelib/io/qfilesystemwatcher_kqueue.cpp
@@ -43,6 +43,7 @@
#include "qfilesystemwatcher.h"
#include "qfilesystemwatcher_kqueue_p.h"
+#include "private/qcore_unix_p.h"
#include <qdebug.h>
#include <qfile.h>
@@ -124,9 +125,9 @@ QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths,
QString path = it.next();
int fd;
#if defined(O_EVTONLY)
- fd = ::open(QFile::encodeName(path), O_EVTONLY);
+ fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY);
#else
- fd = ::open(QFile::encodeName(path), O_RDONLY);
+ fd = qt_safe_open(QFile::encodeName(path), O_RDONLY);
#endif
if (fd == -1) {
perror("QKqueueFileSystemWatcherEngine::addPaths: open");
diff --git a/src/corelib/io/qfilesystemwatcher_p.h b/src/corelib/io/qfilesystemwatcher_p.h
index 714a8e7..cb9c846 100644
--- a/src/corelib/io/qfilesystemwatcher_p.h
+++ b/src/corelib/io/qfilesystemwatcher_p.h
@@ -69,13 +69,14 @@ class QFileSystemWatcherEngine : public QThread
Q_OBJECT
protected:
- inline QFileSystemWatcherEngine()
+ inline QFileSystemWatcherEngine(bool move = true)
{
- moveToThread(this);
+ if (move)
+ moveToThread(this);
}
public:
- // fills \a files and \a directires with the \a paths it could
+ // fills \a files and \a directories with the \a paths it could
// watch, and returns a list of paths this engine could not watch
virtual QStringList addPaths(const QStringList &paths,
QStringList *files,
diff --git a/src/corelib/io/qfilesystemwatcher_symbian.cpp b/src/corelib/io/qfilesystemwatcher_symbian.cpp
new file mode 100644
index 0000000..1d60752
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_symbian.cpp
@@ -0,0 +1,291 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfilesystemwatcher.h"
+#include "qfilesystemwatcher_symbian_p.h"
+#include "qfileinfo.h"
+#include "qdebug.h"
+#include "private/qcore_symbian_p.h"
+#include <QDir>
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+
+QT_BEGIN_NAMESPACE
+
+QNotifyChangeEvent::QNotifyChangeEvent(RFs &fs, const TDesC &file,
+ QSymbianFileSystemWatcherEngine *e, bool aIsDir,
+ TInt aPriority) :
+ CActive(aPriority),
+ isDir(aIsDir),
+ fsSession(fs),
+ watchedPath(file),
+ engine(e),
+ failureCount(0)
+{
+ if (isDir) {
+ fsSession.NotifyChange(ENotifyEntry, iStatus, file);
+ } else {
+ fsSession.NotifyChange(ENotifyAll, iStatus, file);
+ }
+ CActiveScheduler::Add(this);
+ SetActive();
+}
+
+QNotifyChangeEvent::~QNotifyChangeEvent()
+{
+ Cancel();
+}
+
+void QNotifyChangeEvent::RunL()
+{
+ if(iStatus.Int() == KErrNone) {
+ failureCount = 0;
+ } else {
+ qWarning("QNotifyChangeEvent::RunL() - Failed to order change notifications: %d", iStatus.Int());
+ failureCount++;
+ }
+
+ // Re-request failed notification once, but if it won't start working,
+ // we can't do much besides just not request any more notifications.
+ if (failureCount < 2) {
+ if (isDir) {
+ fsSession.NotifyChange(ENotifyEntry, iStatus, watchedPath);
+ } else {
+ fsSession.NotifyChange(ENotifyAll, iStatus, watchedPath);
+ }
+ SetActive();
+
+ if (!failureCount) {
+ QT_TRYCATCH_LEAVING(engine->emitPathChanged(this));
+ }
+ }
+}
+
+void QNotifyChangeEvent::DoCancel()
+{
+ fsSession.NotifyChangeCancel(iStatus);
+}
+
+QSymbianFileSystemWatcherEngine::QSymbianFileSystemWatcherEngine() :
+ watcherStarted(false)
+{
+ moveToThread(this);
+}
+
+QSymbianFileSystemWatcherEngine::~QSymbianFileSystemWatcherEngine()
+{
+ stop();
+}
+
+QStringList QSymbianFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *files,
+ QStringList *directories)
+{
+ QMutexLocker locker(&mutex);
+ QStringList p = paths;
+
+ if (!startWatcher()) {
+ qWarning("Could not start QSymbianFileSystemWatcherEngine thread");
+
+ return p;
+ }
+
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+ QString path = it.next();
+ QFileInfo fi(path);
+ if (!fi.exists())
+ continue;
+
+ bool isDir = fi.isDir();
+ if (isDir) {
+ if (directories->contains(path))
+ continue;
+ } else {
+ if (files->contains(path))
+ continue;
+ }
+
+ // Use absolute filepath as relative paths seem to have some issues.
+ QString filePath = fi.absoluteFilePath();
+ if (isDir && filePath.at(filePath.size() - 1) != QChar(L'/')) {
+ filePath += QChar(L'/');
+ }
+
+ currentEvent = NULL;
+ QMetaObject::invokeMethod(this,
+ "addNativeListener",
+ Qt::QueuedConnection,
+ Q_ARG(QString, filePath));
+
+ syncCondition.wait(&mutex);
+
+ if (currentEvent) {
+ currentEvent->isDir = isDir;
+
+ activeObjectToPath.insert(currentEvent, path);
+ it.remove();
+
+ if (isDir)
+ directories->append(path);
+ else
+ files->append(path);
+ }
+ }
+
+ return p;
+}
+
+QStringList QSymbianFileSystemWatcherEngine::removePaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+ QMutexLocker locker(&mutex);
+
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+ QString path = it.next();
+
+ currentEvent = activeObjectToPath.key(path);
+ if (!currentEvent)
+ continue;
+ activeObjectToPath.remove(currentEvent);
+
+ QMetaObject::invokeMethod(this,
+ "removeNativeListener",
+ Qt::QueuedConnection);
+
+ syncCondition.wait(&mutex);
+
+ it.remove();
+
+ files->removeAll(path);
+ directories->removeAll(path);
+ }
+
+ if (activeObjectToPath.size() == 0)
+ stop();
+
+ return p;
+}
+
+void QSymbianFileSystemWatcherEngine::emitPathChanged(QNotifyChangeEvent *e)
+{
+ QMutexLocker locker(&mutex);
+
+ QString path = activeObjectToPath.value(e);
+ QFileInfo fi(path);
+
+ if (e->isDir)
+ emit directoryChanged(path, !fi.exists());
+ else
+ emit fileChanged(path, !fi.exists());
+}
+
+void QSymbianFileSystemWatcherEngine::stop()
+{
+ QMetaObject::invokeMethod(this, "quit");
+ wait();
+}
+
+// This method must be called inside mutex
+bool QSymbianFileSystemWatcherEngine::startWatcher()
+{
+ bool retval = true;
+
+ if (!watcherStarted) {
+ setStackSize(0x5000);
+ start();
+ syncCondition.wait(&mutex);
+
+ if (errorCode != KErrNone) {
+ retval = false;
+ } else {
+ watcherStarted = true;
+ }
+ }
+ return retval;
+}
+
+
+void QSymbianFileSystemWatcherEngine::run()
+{
+ // Initialize file session
+
+ mutex.lock();
+ syncCondition.wakeOne();
+ mutex.unlock();
+
+ if (errorCode == KErrNone) {
+ exec();
+
+ foreach(QNotifyChangeEvent *e, activeObjectToPath.keys()) {
+ e->Cancel();
+ delete e;
+ }
+
+ activeObjectToPath.clear();
+ watcherStarted = false;
+ }
+}
+
+void QSymbianFileSystemWatcherEngine::addNativeListener(const QString &directoryPath)
+{
+ QMutexLocker locker(&mutex);
+ QString nativeDir(QDir::toNativeSeparators(directoryPath));
+ TPtrC ptr(qt_QString2TPtrC(nativeDir));
+ currentEvent = new QNotifyChangeEvent(qt_s60GetRFs(), ptr, this, directoryPath.endsWith(QChar(L'/'), Qt::CaseSensitive));
+ syncCondition.wakeOne();
+}
+
+void QSymbianFileSystemWatcherEngine::removeNativeListener()
+{
+ QMutexLocker locker(&mutex);
+ currentEvent->Cancel();
+ delete currentEvent;
+ currentEvent = NULL;
+ syncCondition.wakeOne();
+}
+
+
+QT_END_NAMESPACE
+#endif // QT_NO_FILESYSTEMWATCHER
diff --git a/src/corelib/io/qfilesystemwatcher_symbian_p.h b/src/corelib/io/qfilesystemwatcher_symbian_p.h
new file mode 100644
index 0000000..cf9e1da
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_symbian_p.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMWATCHER_SYMBIAN_P_H
+#define QFILESYSTEMWATCHER_SYMBIAN_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 "qfilesystemwatcher_p.h"
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+#include "qhash.h"
+#include "qmutex.h"
+#include "qwaitcondition.h"
+
+#include <e32base.h>
+#include <f32file.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSymbianFileSystemWatcherEngine;
+
+class QNotifyChangeEvent : public CActive
+{
+public:
+ QNotifyChangeEvent(RFs &fsSession, const TDesC &file, QSymbianFileSystemWatcherEngine *engine,
+ bool aIsDir, TInt aPriority = EPriorityStandard);
+ ~QNotifyChangeEvent();
+
+ bool isDir;
+
+private:
+ void RunL();
+ void DoCancel();
+
+ RFs &fsSession;
+ TPath watchedPath;
+ QSymbianFileSystemWatcherEngine *engine;
+
+ int failureCount;
+};
+
+class QSymbianFileSystemWatcherEngine : public QFileSystemWatcherEngine
+{
+ Q_OBJECT
+
+public:
+ QSymbianFileSystemWatcherEngine();
+ ~QSymbianFileSystemWatcherEngine();
+
+ QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
+ QStringList removePaths(const QStringList &paths, QStringList *files,
+ QStringList *directories);
+
+ void stop();
+
+protected:
+ void run();
+
+public Q_SLOTS:
+ void addNativeListener(const QString &directoryPath);
+ void removeNativeListener();
+
+private:
+ friend class QNotifyChangeEvent;
+ void emitPathChanged(QNotifyChangeEvent *e);
+
+ bool startWatcher();
+
+ QHash<QNotifyChangeEvent*, QString> activeObjectToPath;
+ QMutex mutex;
+ QWaitCondition syncCondition;
+ int errorCode;
+ bool watcherStarted;
+ QNotifyChangeEvent *currentEvent;
+};
+
+#endif // QT_NO_FILESYSTEMWATCHER
+
+QT_END_NAMESPACE
+
+#endif // QFILESYSTEMWATCHER_WIN_P_H
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index 2fafbab..355a6e9 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -53,25 +53,268 @@
QT_BEGIN_NAMESPACE
+void QWindowsFileSystemWatcherEngine::stop()
+{
+ foreach(QWindowsFileSystemWatcherEngineThread *thread, threads)
+ thread->stop();
+}
+
QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine()
- : msg(0)
+ : QFileSystemWatcherEngine(false)
{
- HANDLE h = QT_WA_INLINE(CreateEventW(0, false, false, 0),
- CreateEventA(0, false, false, 0));
- if (h != INVALID_HANDLE_VALUE) {
- handles.reserve(MAXIMUM_WAIT_OBJECTS);
- handles.append(h);
- }
}
QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine()
{
- if (handles.isEmpty())
+ if (threads.isEmpty())
return;
- stop();
- wait();
+ foreach(QWindowsFileSystemWatcherEngineThread *thread, threads) {
+ thread->stop();
+ thread->wait();
+ delete thread;
+ }
+}
+
+QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+ // qDebug()<<"Adding"<<paths.count()<<"to existing"<<(files->count() + directories->count())<<"watchers";
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+ QString path = it.next();
+ QString normalPath = path;
+ if ((normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\')))
+#ifdef Q_OS_WINCE
+ && normalPath.size() > 1)
+#else
+ )
+#endif
+ normalPath.chop(1);
+ QFileInfo fileInfo(normalPath.toLower());
+ if (!fileInfo.exists())
+ continue;
+
+ bool isDir = fileInfo.isDir();
+ if (isDir) {
+ if (directories->contains(path))
+ continue;
+ } else {
+ if (files->contains(path))
+ continue;
+ }
+
+ // qDebug()<<"Looking for a thread/handle for"<<normalPath;
+
+ const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath();
+ const uint flags = isDir
+ ? (FILE_NOTIFY_CHANGE_DIR_NAME
+ | FILE_NOTIFY_CHANGE_FILE_NAME)
+ : (FILE_NOTIFY_CHANGE_DIR_NAME
+ | FILE_NOTIFY_CHANGE_FILE_NAME
+ | FILE_NOTIFY_CHANGE_ATTRIBUTES
+ | FILE_NOTIFY_CHANGE_SIZE
+ | FILE_NOTIFY_CHANGE_LAST_WRITE
+ | FILE_NOTIFY_CHANGE_SECURITY);
+
+ QWindowsFileSystemWatcherEngine::PathInfo pathInfo;
+ pathInfo.absolutePath = absolutePath;
+ pathInfo.isDir = isDir;
+ pathInfo.path = path;
+ pathInfo = fileInfo;
+
+ // Look for a thread
+ QWindowsFileSystemWatcherEngineThread *thread = 0;
+ QWindowsFileSystemWatcherEngine::Handle handle;
+ QList<QWindowsFileSystemWatcherEngineThread *>::const_iterator jt, end;
+ end = threads.constEnd();
+ for(jt = threads.constBegin(); jt != end; ++jt) {
+ thread = *jt;
+ QMutexLocker locker(&(thread->mutex));
+
+ handle = thread->handleForDir.value(absolutePath);
+ if (handle.handle != INVALID_HANDLE_VALUE && handle.flags == flags) {
+ // found a thread now insert...
+ // qDebug()<<" Found a thread"<<thread;
+
+ QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h
+ = thread->pathInfoForHandle[handle.handle];
+ if (!h.contains(fileInfo.absoluteFilePath())) {
+ thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo);
+ if (isDir)
+ directories->append(path);
+ else
+ files->append(path);
+ }
+ it.remove();
+ thread->wakeup();
+ break;
+ }
+ }
+
+ // no thread found, first create a handle
+ if (handle.handle == INVALID_HANDLE_VALUE || handle.flags != flags) {
+ // qDebug()<<" No thread found";
+ // Volume and folder paths need a trailing slash for proper notification
+ // (e.g. "c:" -> "c:/").
+ const QString effectiveAbsolutePath =
+ isDir ? (absolutePath + QLatin1Char('/')) : absolutePath;
+
+ handle.handle = FindFirstChangeNotification((wchar_t*) QDir::toNativeSeparators(effectiveAbsolutePath).utf16(), false, flags);
+ handle.flags = flags;
+ if (handle.handle == INVALID_HANDLE_VALUE)
+ continue;
+
+ // now look for a thread to insert
+ bool found = false;
+ foreach(QWindowsFileSystemWatcherEngineThread *thread, threads) {
+ QMutexLocker(&(thread->mutex));
+ if (thread->handles.count() < MAXIMUM_WAIT_OBJECTS) {
+ // qDebug() << " Added handle" << handle.handle << "for" << absolutePath << "to watch" << fileInfo.absoluteFilePath();
+ // qDebug()<< " to existing thread"<<thread;
+ thread->handles.append(handle.handle);
+ thread->handleForDir.insert(absolutePath, handle);
+
+ thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo);
+ if (isDir)
+ directories->append(path);
+ else
+ files->append(path);
+
+ it.remove();
+ found = true;
+ thread->wakeup();
+ break;
+ }
+ }
+ if (!found) {
+ QWindowsFileSystemWatcherEngineThread *thread = new QWindowsFileSystemWatcherEngineThread();
+ //qDebug()<<" ###Creating new thread"<<thread<<"("<<(threads.count()+1)<<"threads)";
+ thread->handles.append(handle.handle);
+ thread->handleForDir.insert(absolutePath, handle);
+
+ thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo);
+ if (isDir)
+ directories->append(path);
+ else
+ files->append(path);
+
+ connect(thread, SIGNAL(fileChanged(const QString &, bool)),
+ this, SIGNAL(fileChanged(const QString &, bool)));
+ connect(thread, SIGNAL(directoryChanged(const QString &, bool)),
+ this, SIGNAL(directoryChanged(const QString &, bool)));
+
+ thread->msg = '@';
+ thread->start();
+ threads.append(thread);
+ it.remove();
+ }
+ }
+ }
+ return p;
+}
+
+QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+ // qDebug()<<"removePaths"<<paths;
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+ QString path = it.next();
+ QString normalPath = path;
+ if (normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\')))
+ normalPath.chop(1);
+ QFileInfo fileInfo(normalPath.toLower());
+ // qDebug()<<"removing"<<normalPath;
+ QString absolutePath = fileInfo.absoluteFilePath();
+ QList<QWindowsFileSystemWatcherEngineThread *>::iterator jt, end;
+ end = threads.end();
+ for(jt = threads.begin(); jt!= end; ++jt) {
+ QWindowsFileSystemWatcherEngineThread *thread = *jt;
+ if (*jt == 0)
+ continue;
+
+ QMutexLocker locker(&(thread->mutex));
+
+ QWindowsFileSystemWatcherEngine::Handle handle = thread->handleForDir.value(absolutePath);
+ if (handle.handle == INVALID_HANDLE_VALUE) {
+ // perhaps path is a file?
+ absolutePath = fileInfo.absolutePath();
+ handle = thread->handleForDir.value(absolutePath);
+ }
+ if (handle.handle != INVALID_HANDLE_VALUE) {
+ QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h =
+ thread->pathInfoForHandle[handle.handle];
+ if (h.remove(fileInfo.absoluteFilePath())) {
+ // ###
+ files->removeAll(path);
+ directories->removeAll(path);
+
+ if (h.isEmpty()) {
+ // qDebug() << "Closing handle" << handle.handle;
+ FindCloseChangeNotification(handle.handle); // This one might generate a notification
+
+ int indexOfHandle = thread->handles.indexOf(handle.handle);
+ Q_ASSERT(indexOfHandle != -1);
+ thread->handles.remove(indexOfHandle);
+
+ thread->handleForDir.remove(absolutePath);
+ // h is now invalid
+
+ it.remove();
+
+ if (thread->handleForDir.isEmpty()) {
+ // qDebug()<<"Stopping thread "<<thread;
+ locker.unlock();
+ thread->stop();
+ thread->wait();
+ locker.relock();
+ // We can't delete the thread until the mutex locker is
+ // out of scope
+ }
+ }
+ }
+ // Found the file, go to next one
+ break;
+ }
+ }
+ }
+
+ // Remove all threads that we stopped
+ QList<QWindowsFileSystemWatcherEngineThread *>::iterator jt, end;
+ end = threads.end();
+ for(jt = threads.begin(); jt != end; ++jt) {
+ if (!(*jt)->isRunning()) {
+ delete *jt;
+ *jt = 0;
+ }
+ }
+
+ threads.removeAll(0);
+ return p;
+}
+
+///////////
+// QWindowsFileSystemWatcherEngineThread
+///////////
+QWindowsFileSystemWatcherEngineThread::QWindowsFileSystemWatcherEngineThread()
+ : msg(0)
+{
+ if (HANDLE h = CreateEvent(0, false, false, 0)) {
+ handles.reserve(MAXIMUM_WAIT_OBJECTS);
+ handles.append(h);
+ }
+ moveToThread(this);
+}
+
+
+QWindowsFileSystemWatcherEngineThread::~QWindowsFileSystemWatcherEngineThread()
+{
CloseHandle(handles.at(0));
handles[0] = INVALID_HANDLE_VALUE;
@@ -82,13 +325,13 @@ QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine()
}
}
-void QWindowsFileSystemWatcherEngine::run()
+void QWindowsFileSystemWatcherEngineThread::run()
{
QMutexLocker locker(&mutex);
forever {
QVector<HANDLE> handlesCopy = handles;
locker.unlock();
- // qDebug() << "QWindowsFileSystemWatcherEngine: waiting on" << handlesCopy.count() << "handles";
+ // qDebug() << "QWindowsFileSystemWatcherThread"<<this<<"waiting on" << handlesCopy.count() << "handles";
DWORD r = WaitForMultipleObjects(handlesCopy.count(), handlesCopy.constData(), false, INFINITE);
locker.relock();
do {
@@ -96,7 +339,7 @@ void QWindowsFileSystemWatcherEngine::run()
int m = msg;
msg = 0;
if (m == 'q') {
- // qDebug() << "thread told to quit";
+ // qDebug() << "thread"<<this<<"told to quit";
return;
}
if (m != '@') {
@@ -111,15 +354,15 @@ void QWindowsFileSystemWatcherEngine::run()
// When removing a path, FindCloseChangeNotification might actually fire a notification
// for some reason, so we must check if the handle exist in the handles vector
if (handles.contains(handle)) {
- // qDebug("Acknowledged handle: %d, %p", at, handle);
+ // qDebug()<<"thread"<<this<<"Acknowledged handle:"<<at<<handle;
if (!FindNextChangeNotification(handle)) {
- qErrnoWarning("QFileSystemWatcher: FindNextChangeNotification failed");
+ qErrnoWarning("QFileSystemWatcher: FindNextChangeNotification failed!!");
}
- QHash<QString, PathInfo> &h = pathInfoForHandle[handle];
- QMutableHashIterator<QString, PathInfo> it(h);
+ QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h = pathInfoForHandle[handle];
+ QMutableHashIterator<QString, QWindowsFileSystemWatcherEngine::PathInfo> it(h);
while (it.hasNext()) {
- QHash<QString, PathInfo>::iterator x = it.next();
+ QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo>::iterator x = it.next();
QString absolutePath = x.value().absolutePath;
QFileInfo fileInfo(x.value().path);
// qDebug() << "checking" << x.key();
@@ -164,166 +407,14 @@ void QWindowsFileSystemWatcherEngine::run()
}
}
-QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
- QStringList *files,
- QStringList *directories)
-{
- if (handles.isEmpty() || handles.count() == MAXIMUM_WAIT_OBJECTS)
- return paths;
-
- QMutexLocker locker(&mutex);
-
- QStringList p = paths;
- QMutableListIterator<QString> it(p);
- while (it.hasNext()) {
- QString path = it.next();
- QString normalPath = path;
- if ((normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\')))
-#ifdef Q_OS_WINCE
- && normalPath.size() > 1)
-#else
- )
-#endif
- normalPath.chop(1);
- QFileInfo fileInfo(normalPath.toLower());
- if (!fileInfo.exists())
- continue;
-
- bool isDir = fileInfo.isDir();
- if (isDir) {
- if (directories->contains(path))
- continue;
- } else {
- if (files->contains(path))
- continue;
- }
-
- const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath();
- const uint flags = isDir
- ? (FILE_NOTIFY_CHANGE_DIR_NAME
- | FILE_NOTIFY_CHANGE_FILE_NAME)
- : (FILE_NOTIFY_CHANGE_DIR_NAME
- | FILE_NOTIFY_CHANGE_FILE_NAME
- | FILE_NOTIFY_CHANGE_ATTRIBUTES
- | FILE_NOTIFY_CHANGE_SIZE
- | FILE_NOTIFY_CHANGE_LAST_WRITE
- | FILE_NOTIFY_CHANGE_SECURITY);
-
- Handle handle = handleForDir.value(absolutePath);
- if (handle.handle == INVALID_HANDLE_VALUE || handle.flags != flags) {
- // Volume and folder paths need a trailing slash for proper notification
- // (e.g. "c:" -> "c:/").
- const QString effectiveAbsolutePath =
- isDir ? (absolutePath + QLatin1Char('/')) : absolutePath;
-
- QT_WA({
- handle.handle = FindFirstChangeNotificationW((TCHAR *) QDir::toNativeSeparators(effectiveAbsolutePath).utf16(),
- false, flags);
- },{
- handle.handle = FindFirstChangeNotificationA(QDir::toNativeSeparators(effectiveAbsolutePath).toLocal8Bit(),
- false, flags);
- })
- handle.flags = flags;
- if (handle.handle == INVALID_HANDLE_VALUE)
- continue;
- // qDebug() << "Added handle" << handle << "for" << absolutePath << "to watch" << fileInfo.absoluteFilePath();
- handles.append(handle.handle);
- handleForDir.insert(absolutePath, handle);
- }
-
- PathInfo pathInfo;
- pathInfo.absolutePath = absolutePath;
- pathInfo.isDir = isDir;
- pathInfo.path = path;
- pathInfo = fileInfo;
- QHash<QString, PathInfo> &h = pathInfoForHandle[handle.handle];
- if (!h.contains(fileInfo.absoluteFilePath())) {
- pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo);
- if (isDir)
- directories->append(path);
- else
- files->append(path);
- }
-
- it.remove();
- }
-
- if (!isRunning()) {
- msg = '@';
- start();
- } else {
- wakeup();
- }
-
- return p;
-}
-
-QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &paths,
- QStringList *files,
- QStringList *directories)
-{
- QMutexLocker locker(&mutex);
-
- QStringList p = paths;
- QMutableListIterator<QString> it(p);
- while (it.hasNext()) {
- QString path = it.next();
- QString normalPath = path;
- if (normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\')))
- normalPath.chop(1);
- QFileInfo fileInfo(normalPath.toLower());
-
- QString absolutePath = fileInfo.absoluteFilePath();
- Handle handle = handleForDir.value(absolutePath);
- if (handle.handle == INVALID_HANDLE_VALUE) {
- // perhaps path is a file?
- absolutePath = fileInfo.absolutePath();
- handle = handleForDir.value(absolutePath);
- if (handle.handle == INVALID_HANDLE_VALUE)
- continue;
- }
-
- QHash<QString, PathInfo> &h = pathInfoForHandle[handle.handle];
- if (h.remove(fileInfo.absoluteFilePath())) {
- // ###
- files->removeAll(path);
- directories->removeAll(path);
-
- if (h.isEmpty()) {
- // qDebug() << "Closing handle" << handle;
- FindCloseChangeNotification(handle.handle); // This one might generate a notification
-
- int indexOfHandle = handles.indexOf(handle.handle);
- Q_ASSERT(indexOfHandle != -1);
- handles.remove(indexOfHandle);
-
- handleForDir.remove(absolutePath);
- // h is now invalid
-
- it.remove();
- }
- }
- }
-
- if (handleForDir.isEmpty()) {
- stop();
- locker.unlock();
- wait();
- locker.relock();
- } else {
- wakeup();
- }
-
- return p;
-}
-void QWindowsFileSystemWatcherEngine::stop()
+void QWindowsFileSystemWatcherEngineThread::stop()
{
msg = 'q';
SetEvent(handles.at(0));
}
-void QWindowsFileSystemWatcherEngine::wakeup()
+void QWindowsFileSystemWatcherEngineThread::wakeup()
{
msg = '@';
SetEvent(handles.at(0));
diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h
index 26536ca..2654aa9 100644
--- a/src/corelib/io/qfilesystemwatcher_win_p.h
+++ b/src/corelib/io/qfilesystemwatcher_win_p.h
@@ -57,7 +57,7 @@
#ifndef QT_NO_FILESYSTEMWATCHER
-#include <windows.h>
+#include <qt_windows.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qfile.h>
@@ -68,27 +68,24 @@
QT_BEGIN_NAMESPACE
+class QWindowsFileSystemWatcherEngineThread;
+
+// Even though QWindowsFileSystemWatcherEngine is derived of QThread
+// via QFileSystemWatcher, it does not start a thread.
+// Instead QWindowsFileSystemWatcher creates QWindowsFileSystemWatcherEngineThreads
+// to do the actually watching.
class QWindowsFileSystemWatcherEngine : public QFileSystemWatcherEngine
{
Q_OBJECT
-
public:
QWindowsFileSystemWatcherEngine();
~QWindowsFileSystemWatcherEngine();
- void run();
-
QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories);
void stop();
-private:
- void wakeup();
-
- QMutex mutex;
- QVector<HANDLE> handles;
- int msg;
class Handle
{
@@ -97,13 +94,12 @@ private:
uint flags;
Handle()
- : handle(INVALID_HANDLE_VALUE), flags(0u)
+ : handle(INVALID_HANDLE_VALUE), flags(0u)
{ }
Handle(const Handle &other)
- : handle(other.handle), flags(other.flags)
+ : handle(other.handle), flags(other.flags)
{ }
};
- QHash<QString, Handle> handleForDir;
class PathInfo {
public:
@@ -118,7 +114,7 @@ private:
QDateTime lastModified;
PathInfo &operator=(const QFileInfo &fileInfo)
- {
+ {
ownerId = fileInfo.ownerId();
groupId = fileInfo.groupId();
permissions = fileInfo.permissions();
@@ -134,8 +130,35 @@ private:
|| lastModified != fileInfo.lastModified());
}
};
- QHash<HANDLE, QHash<QString, PathInfo> > pathInfoForHandle;
+private:
+ QList<QWindowsFileSystemWatcherEngineThread *> threads;
+
+};
+
+class QWindowsFileSystemWatcherEngineThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ QWindowsFileSystemWatcherEngineThread();
+ ~QWindowsFileSystemWatcherEngineThread();
+ void run();
+ void stop();
+ void wakeup();
+
+ QMutex mutex;
+ QVector<HANDLE> handles;
+ int msg;
+
+ QHash<QString, QWindowsFileSystemWatcherEngine::Handle> handleForDir;
+
+ QHash<HANDLE, QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> > pathInfoForHandle;
+
+Q_SIGNALS:
+ void fileChanged(const QString &path, bool removed);
+ void directoryChanged(const QString &path, bool removed);
};
+
#endif // QT_NO_FILESYSTEMWATCHER
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index b28acb9..b9e4061 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -44,12 +44,16 @@
#include "qdatetime.h"
#include "qdiriterator.h"
#include "qset.h"
+#include <QtCore/qdebug.h>
#ifndef QT_NO_FSFILEENGINE
#if !defined(Q_OS_WINCE)
#include <errno.h>
#endif
+#if defined(Q_OS_UNIX)
+#include "private/qcore_unix_p.h"
+#endif
#include <stdio.h>
QT_BEGIN_NAMESPACE
@@ -105,7 +109,7 @@ void QFSFileEnginePrivate::init()
{
is_sequential = 0;
tried_stat = 0;
-#ifdef Q_OS_UNIX
+#if !defined(Q_OS_WINCE)
need_lstat = 1;
is_link = 0;
#endif
@@ -568,7 +572,7 @@ bool QFSFileEnginePrivate::seekFdFh(qint64 pos)
} else {
// Unbuffered stdio mode.
if (QT_LSEEK(fd, pos, SEEK_SET) == -1) {
- qWarning("QFile::at: Cannot set file position %lld", pos);
+ qWarning() << "QFile::at: Cannot set file position" << pos;
q->setError(QFile::PositionError, qt_error_string(errno));
return false;
}
diff --git a/src/corelib/io/qfsfileengine_iterator.cpp b/src/corelib/io/qfsfileengine_iterator.cpp
index ecddaba..9bc0c19 100644
--- a/src/corelib/io/qfsfileengine_iterator.cpp
+++ b/src/corelib/io/qfsfileengine_iterator.cpp
@@ -79,4 +79,3 @@ QFileInfo QFSFileEngineIterator::currentFileInfo() const
QT_END_NAMESPACE
#endif // QT_NO_FSFILEENGINE
-
diff --git a/src/corelib/io/qfsfileengine_iterator_p.h b/src/corelib/io/qfsfileengine_iterator_p.h
index dfc7b75..96e650c 100644
--- a/src/corelib/io/qfsfileengine_iterator_p.h
+++ b/src/corelib/io/qfsfileengine_iterator_p.h
@@ -89,4 +89,4 @@ QT_END_NAMESPACE
#endif // QT_NO_FSFILEENGINE
-#endif
+#endif // QFSFILEENGINE_ITERATOR_P_H
diff --git a/src/corelib/io/qfsfileengine_iterator_unix.cpp b/src/corelib/io/qfsfileengine_iterator_unix.cpp
index ba17984..56f6a9f 100644
--- a/src/corelib/io/qfsfileengine_iterator_unix.cpp
+++ b/src/corelib/io/qfsfileengine_iterator_unix.cpp
@@ -53,16 +53,16 @@ class QFSFileEngineIteratorPlatformSpecificData
public:
inline QFSFileEngineIteratorPlatformSpecificData()
: dir(0), dirEntry(0), done(false)
-#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN)
, mt_file(0)
#endif
- { }
+ {}
DIR *dir;
dirent *dirEntry;
bool done;
-#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN)
// for readdir_r
dirent *mt_file;
#endif
@@ -75,7 +75,7 @@ void QFSFileEngineIterator::advance()
if (!platform->dir)
return;
-#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN)
if (::readdir_r(platform->dir, platform->mt_file, &platform->dirEntry) != 0)
platform->done = true;
#else
@@ -86,7 +86,7 @@ void QFSFileEngineIterator::advance()
::closedir(platform->dir);
platform->dir = 0;
platform->done = true;
-#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN)
delete [] platform->mt_file;
platform->mt_file = 0;
#endif
@@ -102,7 +102,7 @@ void QFSFileEngineIterator::deletePlatformSpecifics()
{
if (platform->dir) {
::closedir(platform->dir);
-#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN)
delete [] platform->mt_file;
platform->mt_file = 0;
#endif
@@ -123,7 +123,7 @@ bool QFSFileEngineIterator::hasNext() const
if ((int) maxPathName == -1)
maxPathName = FILENAME_MAX;
maxPathName += sizeof(dirent) + 1;
-#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN)
if (that->platform->mt_file)
delete [] that->platform->mt_file;
that->platform->mt_file = (dirent *)new char[maxPathName];
diff --git a/src/corelib/io/qfsfileengine_iterator_win.cpp b/src/corelib/io/qfsfileengine_iterator_win.cpp
index 4c6a39a..725370a 100644
--- a/src/corelib/io/qfsfileengine_iterator_win.cpp
+++ b/src/corelib/io/qfsfileengine_iterator_win.cpp
@@ -39,14 +39,11 @@
**
****************************************************************************/
-#include "qdebug.h"
#include "qfsfileengine_iterator_p.h"
#include "qfsfileengine_p.h"
#include "qplatformdefs.h"
#include <QtCore/qvariant.h>
-#include <QtCore/qmutex.h>
-#include <private/qmutexpool_p.h>
QT_BEGIN_NAMESPACE
@@ -56,7 +53,7 @@ public:
inline QFSFileEngineIteratorPlatformSpecificData()
: uncShareIndex(-1), findFileHandle(INVALID_HANDLE_VALUE),
done(false), uncFallback(false)
- { }
+ {}
QFSFileEngineIterator *it;
@@ -68,7 +65,6 @@ public:
bool done;
bool uncFallback;
- void advance();
void saveCurrentFileName();
};
@@ -79,11 +75,7 @@ void QFSFileEngineIteratorPlatformSpecificData::saveCurrentFileName()
it->currentEntry = uncShares.at(uncShareIndex - 1);
} else {
// Local directory
- QT_WA({
- it->currentEntry = QString::fromUtf16((unsigned short *)findData.cFileName);
- } , {
- it->currentEntry = QString::fromLocal8Bit((const char *)findData.cFileName);
- });
+ it->currentEntry = QString::fromWCharArray(findData.cFileName);
}
}
@@ -97,17 +89,10 @@ void QFSFileEngineIterator::advance()
if (platform->uncFallback) {
++platform->uncShareIndex;
} else if (platform->findFileHandle != INVALID_HANDLE_VALUE) {
- QT_WA({
- if (!FindNextFile(platform->findFileHandle, &platform->findData)) {
- platform->done = true;
- FindClose(platform->findFileHandle);
- }
- } , {
- if (!FindNextFileA(platform->findFileHandle, (WIN32_FIND_DATAA *)&platform->findData)) {
- platform->done = true;
- FindClose(platform->findFileHandle);
- }
- });
+ if (!FindNextFile(platform->findFileHandle, &platform->findData)) {
+ platform->done = true;
+ FindClose(platform->findFileHandle);
+ }
}
}
@@ -127,10 +112,10 @@ bool QFSFileEngineIterator::hasNext() const
{
if (platform->done)
return false;
-
+
if (platform->uncFallback)
return platform->uncShareIndex > 0 && platform->uncShareIndex <= platform->uncShares.size();
-
+
if (platform->findFileHandle == INVALID_HANDLE_VALUE) {
QString path = this->path();
// Local directory
@@ -141,15 +126,8 @@ bool QFSFileEngineIterator::hasNext() const
path.append(QLatin1Char('/'));
path.append(QLatin1String("*.*"));
- QT_WA({
- QString fileName = QFSFileEnginePrivate::longFileName(path);
- platform->findFileHandle = FindFirstFileW((TCHAR *)fileName.utf16(),
- &platform->findData);
- }, {
- // Cast is safe, since char is at end of WIN32_FIND_DATA
- platform->findFileHandle = FindFirstFileA(QFSFileEnginePrivate::win95Name(path),
- (WIN32_FIND_DATAA*)&platform->findData);
- });
+ QString fileName = QFSFileEnginePrivate::longFileName(path);
+ platform->findFileHandle = FindFirstFile((const wchar_t *)fileName.utf16(), &platform->findData);
if (platform->findFileHandle == INVALID_HANDLE_VALUE) {
if (path.startsWith(QLatin1String("//"))) {
@@ -169,7 +147,7 @@ bool QFSFileEngineIterator::hasNext() const
platform->done = true;
}
} else {
- platform->done = true;
+ platform->done = true;
}
}
diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h
index 62c0e3d..3d2a87b 100644
--- a/src/corelib/io/qfsfileengine_p.h
+++ b/src/corelib/io/qfsfileengine_p.h
@@ -72,7 +72,6 @@ class QFSFileEnginePrivate : public QAbstractFileEnginePrivate
public:
#ifdef Q_WS_WIN
- static QByteArray win95Name(const QString &path);
static QString longFileName(const QString &path);
#endif
static QString canonicalized(const QString &path);
@@ -138,10 +137,11 @@ public:
mutable uint is_sequential : 2;
mutable uint could_stat : 1;
mutable uint tried_stat : 1;
-#ifdef Q_OS_UNIX
+#if !defined(Q_OS_WINCE)
mutable uint need_lstat : 1;
mutable uint is_link : 1;
#endif
+
bool doStat() const;
bool isSymlink() const;
@@ -151,8 +151,7 @@ public:
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
static void resolveLibs();
- static bool resolveUNCLibs_NT();
- static bool resolveUNCLibs_9x();
+ static bool resolveUNCLibs();
static bool uncListSharesOnServer(const QString &server, QStringList *list);
#endif
@@ -163,7 +162,6 @@ protected:
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
QAbstractFileEngine::FileFlags getPermissions() const;
- QString getLink() const;
#endif
};
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index c7eb1fa..022211c 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -42,21 +42,24 @@
#include "qplatformdefs.h"
#include "qabstractfileengine.h"
#include "private/qfsfileengine_p.h"
+#include "private/qcore_unix_p.h"
#ifndef QT_NO_FSFILEENGINE
-#ifndef QT_NO_REGEXP
-# include "qregexp.h"
-#endif
#include "qfile.h"
#include "qdir.h"
#include "qdatetime.h"
-#include "qdebug.h"
#include "qvarlengtharray.h"
#include <sys/mman.h>
#include <stdlib.h>
#include <limits.h>
+#if defined(Q_OS_SYMBIAN)
+# include <syslimits.h>
+# include <f32file.h>
+# include <pathinfo.h>
+# include "private/qcore_symbian_p.h"
+#endif
#include <errno.h>
#if !defined(QWS) && defined(Q_OS_MAC)
# include <private/qcore_mac_p.h>
@@ -64,32 +67,58 @@
QT_BEGIN_NAMESPACE
+
+#if defined(Q_OS_SYMBIAN)
+/*!
+ \internal
+
+ Returns true if supplied path is a relative path
+*/
+static bool isRelativePathSymbian(const QString& fileName)
+{
+ return !(fileName.startsWith(QLatin1Char('/'))
+ || (fileName.length() >= 2
+ && ((fileName.at(0).isLetter() && fileName.at(1) == QLatin1Char(':'))
+ || (fileName.at(0) == QLatin1Char('/') && fileName.at(1) == QLatin1Char('/')))));
+}
+#endif
+
/*!
\internal
Returns the stdlib open string corresponding to a QIODevice::OpenMode.
*/
-static QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QString &fileName = QString())
+static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QString &fileName)
{
QByteArray mode;
if ((flags & QIODevice::ReadOnly) && !(flags & QIODevice::Truncate)) {
mode = "rb";
if (flags & QIODevice::WriteOnly) {
- if (!fileName.isEmpty() &&QFile::exists(fileName))
- mode = "rb+";
- else
+ QT_STATBUF statBuf;
+ if (!fileName.isEmpty()
+ && QT_STAT(QFile::encodeName(fileName), &statBuf) == 0
+ && (statBuf.st_mode & S_IFMT) == S_IFREG) {
+ mode += "+";
+ } else {
mode = "wb+";
+ }
}
} else if (flags & QIODevice::WriteOnly) {
mode = "wb";
if (flags & QIODevice::ReadOnly)
- mode += "+";
+ mode += '+';
}
if (flags & QIODevice::Append) {
mode = "ab";
if (flags & QIODevice::ReadOnly)
- mode += "+";
+ mode += '+';
}
+
+#if defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0207
+ // must be glibc >= 2.7
+ mode += 'e';
+#endif
+
return mode;
}
@@ -98,7 +127,7 @@ static QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QString &
Returns the stdio open flags corresponding to a QIODevice::OpenMode.
*/
-static int openModeToOpenFlags(QIODevice::OpenMode mode)
+static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
{
int oflags = QT_OPEN_RDONLY;
#ifdef QT_LARGEFILE_SUPPORT
@@ -118,12 +147,6 @@ static int openModeToOpenFlags(QIODevice::OpenMode mode)
oflags |= QT_OPEN_TRUNC;
}
-#ifdef O_CLOEXEC
- // supported on Linux >= 2.6.23; avoids one extra system call
- // and avoids a race condition: if another thread forks, we could
- // end up leaking a file descriptor...
- oflags |= O_CLOEXEC;
-#endif
return oflags;
}
@@ -133,7 +156,7 @@ static int openModeToOpenFlags(QIODevice::OpenMode mode)
Sets the file descriptor to close on exec. That is, the file
descriptor is not inherited by child processes.
*/
-static bool setCloseOnExec(int fd)
+static inline bool setCloseOnExec(int fd)
{
return fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) != -1;
}
@@ -177,11 +200,6 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
}
}
-#ifndef O_CLOEXEC
- // not needed on Linux >= 2.6.23
- setCloseOnExec(fd); // ignore failure
-#endif
-
// Seek to the end when in Append mode.
if (flags & QFile::Append) {
int ret;
@@ -373,25 +391,60 @@ bool QFSFileEnginePrivate::nativeIsSequential() const
bool QFSFileEngine::remove()
{
Q_D(QFSFileEngine);
- return unlink(d->nativeFilePath.constData()) == 0;
+ bool ret = unlink(d->nativeFilePath.constData()) == 0;
+ if (!ret)
+ setError(QFile::RemoveError, qt_error_string(errno));
+ return ret;
}
-bool QFSFileEngine::copy(const QString &)
+bool QFSFileEngine::copy(const QString &newName)
{
+#if defined(Q_OS_SYMBIAN)
+ Q_D(QFSFileEngine);
+ RFs rfs = qt_s60GetRFs();
+ CFileMan* fm = NULL;
+ QString oldNative(QDir::toNativeSeparators(d->filePath));
+ TPtrC oldPtr(qt_QString2TPtrC(oldNative));
+ QFileInfo fi(newName);
+ QString absoluteNewName = fi.absoluteFilePath();
+ QString newNative(QDir::toNativeSeparators(absoluteNewName));
+ TPtrC newPtr(qt_QString2TPtrC(newNative));
+ TRAPD (err,
+ fm = CFileMan::NewL(rfs);
+ RFile rfile;
+ err = rfile.Open(rfs, oldPtr, EFileShareReadersOrWriters);
+ if (err == KErrNone) {
+ err = fm->Copy(rfile, newPtr);
+ rfile.Close();
+ }
+ ) // End TRAP
+ delete fm;
+ // ### Add error reporting on failure
+ return (err == KErrNone);
+#else
+ Q_UNUSED(newName);
// ### Add copy code for Unix here
+ setError(QFile::UnspecifiedError, QLatin1String("Not implemented!"));
return false;
+#endif
}
bool QFSFileEngine::rename(const QString &newName)
{
Q_D(QFSFileEngine);
- return ::rename(d->nativeFilePath.constData(), QFile::encodeName(newName).constData()) == 0;
+ bool ret = ::rename(d->nativeFilePath.constData(), QFile::encodeName(newName).constData()) == 0;
+ if (!ret)
+ setError(QFile::RenameError, qt_error_string(errno));
+ return ret;
}
bool QFSFileEngine::link(const QString &newName)
{
Q_D(QFSFileEngine);
- return ::symlink(d->nativeFilePath.constData(), QFile::encodeName(newName).constData()) == 0;
+ bool ret = ::symlink(d->nativeFilePath.constData(), QFile::encodeName(newName).constData()) == 0;
+ if (!ret)
+ setError(QFile::RenameError, qt_error_string(errno));
+ return ret;
}
qint64 QFSFileEnginePrivate::nativeSize() const
@@ -404,6 +457,9 @@ bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) con
QString dirName = name;
if (createParentDirectories) {
dirName = QDir::cleanPath(dirName);
+#if defined(Q_OS_SYMBIAN)
+ dirName = QDir::toNativeSeparators(dirName);
+#endif
for(int oldslash = -1, slash=0; slash != -1; oldslash = slash) {
slash = dirName.indexOf(QDir::separator(), oldslash+1);
if (slash == -1) {
@@ -417,18 +473,18 @@ bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) con
if (QT_STAT(chunk, &st) != -1) {
if ((st.st_mode & S_IFMT) != S_IFDIR)
return false;
- } else if (::mkdir(chunk, 0777) != 0) {
- return false;
+ } else if (QT_MKDIR(chunk, 0777) != 0) {
+ return false;
}
}
}
return true;
}
#if defined(Q_OS_DARWIN) // Mac X doesn't support trailing /'s
- if (dirName[dirName.length() - 1] == QLatin1Char('/'))
- dirName = dirName.left(dirName.length() - 1);
+ if (dirName.endsWith(QLatin1Char('/')))
+ dirName.chop(1);
#endif
- return (::mkdir(QFile::encodeName(dirName), 0777) == 0);
+ return (QT_MKDIR(QFile::encodeName(dirName), 0777) == 0);
}
bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
@@ -436,6 +492,9 @@ bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) co
QString dirName = name;
if (recurseParentDirectories) {
dirName = QDir::cleanPath(dirName);
+#if defined(Q_OS_SYMBIAN)
+ dirName = QDir::toNativeSeparators(dirName);
+#endif
for(int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
QByteArray chunk = QFile::encodeName(dirName.left(slash));
QT_STATBUF st;
@@ -456,13 +515,17 @@ bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) co
bool QFSFileEngine::caseSensitive() const
{
+#if defined(Q_OS_SYMBIAN)
+ return false;
+#else
return true;
+#endif
}
bool QFSFileEngine::setCurrentPath(const QString &path)
{
int r;
- r = ::chdir(QFile::encodeName(path));
+ r = QT_CHDIR(QFile::encodeName(path));
return r >= 0;
}
@@ -470,6 +533,16 @@ QString QFSFileEngine::currentPath(const QString &)
{
QString result;
QT_STATBUF st;
+#if defined(Q_OS_SYMBIAN)
+ char nativeCurrentName[PATH_MAX+1];
+ if (::getcwd(nativeCurrentName, PATH_MAX))
+ result = QDir::fromNativeSeparators(QFile::decodeName(QByteArray(nativeCurrentName)));
+ if (result.isEmpty()) {
+# if defined(QT_DEBUG)
+ qWarning("QFSFileEngine::currentPath: getcwd() failed");
+# endif
+ } else
+#endif
if (QT_STAT(".", &st) == 0) {
#if defined(__GLIBC__) && !defined(PATH_MAX)
char *currentName = ::get_current_dir_name();
@@ -477,18 +550,26 @@ QString QFSFileEngine::currentPath(const QString &)
result = QFile::decodeName(QByteArray(currentName));
::free(currentName);
}
-#else
+#elif !defined(Q_OS_SYMBIAN)
char currentName[PATH_MAX+1];
if (::getcwd(currentName, PATH_MAX))
result = QFile::decodeName(QByteArray(currentName));
-#endif
-#if defined(QT_DEBUG)
+# if defined(QT_DEBUG)
if (result.isNull())
- qWarning("QDir::currentPath: getcwd() failed");
+ qWarning("QFSFileEngine::currentPath: getcwd() failed");
+# endif
#endif
} else {
-#if defined(QT_DEBUG)
- qWarning("QDir::currentPath: stat(\".\") failed");
+#if defined(Q_OS_SYMBIAN)
+ // If current dir returned by Open C doesn't exist,
+ // try to create it (can happen with application private dirs)
+ // Ignore mkdir failures; we want to be consistent with Open C
+ // current path regardless.
+ QT_MKDIR(QFile::encodeName(nativeCurrentName), 0777);
+#else
+# if defined(QT_DEBUG)
+ qWarning("QFSFileEngine::currentPath: stat(\".\") failed");
+# endif
#endif
}
return result;
@@ -496,46 +577,93 @@ QString QFSFileEngine::currentPath(const QString &)
QString QFSFileEngine::homePath()
{
+#if defined(Q_OS_SYMBIAN)
+ QString home = rootPath();
+#else
QString home = QFile::decodeName(qgetenv("HOME"));
if (home.isNull())
home = rootPath();
+#endif
return home;
}
QString QFSFileEngine::rootPath()
{
- return QString::fromLatin1("/");
+#if defined(Q_OS_SYMBIAN)
+# ifdef Q_WS_S60
+ TFileName symbianPath = PathInfo::PhoneMemoryRootPath();
+ return QDir::cleanPath(QDir::fromNativeSeparators(qt_TDesC2QString(symbianPath)));
+# else
+# warning No fallback implementation of QFSFileEngine::rootPath()
+ return QLatin1String();
+# endif
+#else
+ return QLatin1String("/");
+#endif
}
QString QFSFileEngine::tempPath()
{
+#if defined(Q_OS_SYMBIAN)
+# ifdef Q_WS_S60
+ TFileName symbianPath = PathInfo::PhoneMemoryRootPath();
+ QString temp = QDir::fromNativeSeparators(qt_TDesC2QString(symbianPath));
+ temp += QLatin1String( "temp/");
+
+ // Just to verify that folder really exist on hardware
+ QT_MKDIR(QFile::encodeName(temp), 0777);
+# else
+# warning No fallback implementation of QFSFileEngine::tempPath()
+ return QString();
+# endif
+#else
QString temp = QFile::decodeName(qgetenv("TMPDIR"));
if (temp.isEmpty())
- temp = QString::fromLatin1("/tmp/");
+ temp = QLatin1String("/tmp/");
+#endif
return temp;
}
QFileInfoList QFSFileEngine::drives()
{
QFileInfoList ret;
- ret.append(rootPath());
+#if defined(Q_OS_SYMBIAN)
+ TDriveList driveList;
+ RFs rfs = qt_s60GetRFs();
+ TInt err = rfs.DriveList(driveList);
+ if (err == KErrNone) {
+ char driveName[] = "A:/";
+
+ for (char i = 0; i < KMaxDrives; i++) {
+ if (driveList[i]) {
+ driveName[0] = 'A' + i;
+ ret.append(QFileInfo(QLatin1String(driveName)));
+ }
+ }
+ } else {
+ qWarning("QFSFileEngine::drives: Getting drives failed");
+ }
+#else
+ ret.append(QFileInfo(rootPath()));
+#endif
return ret;
}
bool QFSFileEnginePrivate::doStat() const
{
- if (tried_stat == 0) {
- QFSFileEnginePrivate *that = const_cast<QFSFileEnginePrivate*>(this);
+ if (!tried_stat) {
+ tried_stat = true;
+ could_stat = false;
+
if (fh && nativeFilePath.isEmpty()) {
// ### actually covers two cases: d->fh and when the file is not open
- that->could_stat = (QT_FSTAT(fileno(fh), &st) == 0);
+ could_stat = (QT_FSTAT(QT_FILENO(fh), &st) == 0);
} else if (fd == -1) {
// ### actually covers two cases: d->fh and when the file is not open
- that->could_stat = (QT_STAT(nativeFilePath.constData(), &st) == 0);
+ could_stat = (QT_STAT(nativeFilePath.constData(), &st) == 0);
} else {
- that->could_stat = (QT_FSTAT(fd, &st) == 0);
+ could_stat = (QT_FSTAT(fd, &st) == 0);
}
- that->tried_stat = 1;
}
return could_stat;
}
@@ -543,14 +671,30 @@ bool QFSFileEnginePrivate::doStat() const
bool QFSFileEnginePrivate::isSymlink() const
{
if (need_lstat) {
- QFSFileEnginePrivate *that = const_cast<QFSFileEnginePrivate *>(this);
- that->need_lstat = false;
+ need_lstat = false;
+
QT_STATBUF st; // don't clobber our main one
- that->is_link = (QT_LSTAT(nativeFilePath.constData(), &st) == 0) ? S_ISLNK(st.st_mode) : false;
+ is_link = (QT_LSTAT(nativeFilePath.constData(), &st) == 0) ? S_ISLNK(st.st_mode) : false;
}
return is_link;
}
+#if defined(Q_OS_SYMBIAN)
+static bool _q_isSymbianHidden(const QString &path, bool isDir)
+{
+ RFs rfs = qt_s60GetRFs();
+ QFileInfo fi(path);
+ QString absPath = fi.absoluteFilePath();
+ if (isDir && !absPath.endsWith(QLatin1Char('/')))
+ absPath.append(QLatin1Char('/'));
+ QString native(QDir::toNativeSeparators(absPath));
+ TPtrC ptr(qt_QString2TPtrC(native));
+ TUint attributes;
+ TInt err = rfs.Att(ptr, attributes);
+ return (err == KErrNone && (attributes & KEntryAttHidden));
+}
+#endif
+
#if !defined(QWS) && defined(Q_OS_MAC)
static bool _q_isMacHidden(const QString &path)
{
@@ -558,24 +702,8 @@ static bool _q_isMacHidden(const QString &path)
FSRef fsRef;
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
- err = FSPathMakeRefWithOptions(reinterpret_cast<const UInt8 *>(QFile::encodeName(QDir::cleanPath(path)).constData()),
- kFSPathMakeRefDoNotFollowLeafSymlink, &fsRef, 0);
- } else
-#endif
- {
- QFileInfo fi(path);
- FSRef parentRef;
- err = FSPathMakeRef(reinterpret_cast<const UInt8 *>(fi.absoluteDir().absolutePath().toUtf8().constData()),
- &parentRef, 0);
- if (err == noErr) {
- QString fileName = fi.fileName();
- err = FSMakeFSRefUnicode(&parentRef, fileName.length(),
- reinterpret_cast<const UniChar *>(fileName.unicode()),
- kTextEncodingUnknown, &fsRef);
- }
- }
+ err = FSPathMakeRefWithOptions(reinterpret_cast<const UInt8 *>(QFile::encodeName(QDir::cleanPath(path)).constData()),
+ kFSPathMakeRefDoNotFollowLeafSymlink, &fsRef, 0);
if (err != noErr)
return false;
@@ -597,7 +725,7 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const
{
Q_D(const QFSFileEngine);
// Force a stat, so that we're guaranteed to get up-to-date results
- if (type & QAbstractFileEngine::FileFlag(QAbstractFileEngine::Refresh)) {
+ if (type & Refresh) {
d->tried_stat = 0;
d->need_lstat = 1;
}
@@ -657,11 +785,11 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const
else if (exists && (d->st.st_mode & S_IFMT) == S_IFDIR)
ret |= DirectoryType;
#if !defined(QWS) && defined(Q_OS_MAC)
- if((ret & DirectoryType) && (type & BundleType)) {
+ if ((ret & DirectoryType) && (type & BundleType)) {
QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(d->filePath),
kCFURLPOSIXPathStyle, true);
UInt32 type, creator;
- if(CFBundleGetPackageInfoInDirectory(url, &type, &creator))
+ if (CFBundleGetPackageInfoInDirectory(url, &type, &creator))
ret |= BundleType;
}
#endif
@@ -671,18 +799,150 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const
ret |= LocalDiskFlag;
if (exists)
ret |= ExistsFlag;
- if (fileName(BaseName)[0] == QLatin1Char('.')
-#if !defined(QWS) && defined(Q_OS_MAC)
- || _q_isMacHidden(d->filePath)
-#endif
- )
- ret |= HiddenFlag;
- if (d->filePath == QLatin1String("/"))
+#if defined(Q_OS_SYMBIAN)
+ if (d->filePath == QLatin1String("/")
+ || (d->filePath.length() == 3 && d->filePath.at(0).isLetter()
+ && d->filePath.at(1) == QLatin1Char(':') && d->filePath.at(2) == QLatin1Char('/'))) {
+ ret |= RootFlag;
+ } else {
+ // In Symbian, all symlinks have hidden attribute for some reason;
+ // lets make them visible for better compatibility with other platforms.
+ // If somebody actually wants a hidden link, then they are out of luck.
+ if (!d->isSymlink() && _q_isSymbianHidden(d->filePath, ret & DirectoryType))
+ ret |= HiddenFlag;
+ }
+#else
+ if (d->filePath == QLatin1String("/")) {
ret |= RootFlag;
+ } else {
+ QString baseName = fileName(BaseName);
+ if ((baseName.size() > 1
+ && baseName.at(0) == QLatin1Char('.') && baseName.at(1) != QLatin1Char('.'))
+# if !defined(QWS) && defined(Q_OS_MAC)
+ || _q_isMacHidden(d->filePath)
+# endif
+ ) {
+ ret |= HiddenFlag;
+ }
+ }
+#endif
}
return ret;
}
+#if defined(Q_OS_SYMBIAN)
+QString QFSFileEngine::fileName(FileName file) const
+{
+ Q_D(const QFSFileEngine);
+ const QLatin1Char slashChar('/');
+ if(file == BaseName) {
+ int slash = d->filePath.lastIndexOf(slashChar);
+ if(slash == -1) {
+ int colon = d->filePath.lastIndexOf(QLatin1Char(':'));
+ if(colon != -1)
+ return d->filePath.mid(colon + 1);
+ return d->filePath;
+ }
+ return d->filePath.mid(slash + 1);
+ } else if(file == PathName) {
+ if(!d->filePath.size())
+ return d->filePath;
+
+ int slash = d->filePath.lastIndexOf(slashChar);
+ if(slash == -1) {
+ if(d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':'))
+ return d->filePath.left(2);
+ return QLatin1String(".");
+ } else {
+ if(!slash)
+ return QLatin1String("/");
+ if(slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':'))
+ slash++;
+ return d->filePath.left(slash);
+ }
+ } else if(file == AbsoluteName || file == AbsolutePathName) {
+ QString ret;
+ if (!isRelativePathSymbian(d->filePath)) {
+ if (d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':')
+ && d->filePath.at(2) != slashChar || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt
+ d->filePath.startsWith(slashChar) // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt
+ ) {
+ ret = QString(QDir::currentPath().left(2) + QDir::fromNativeSeparators(d->filePath));
+ } else {
+ ret = d->filePath;
+ }
+ } else {
+ ret = QDir::cleanPath(QDir::currentPath() + slashChar + d->filePath);
+ }
+
+ // The path should be absolute at this point.
+ // From the docs :
+ // Absolute paths begin with the directory separator "/"
+ // (optionally preceded by a drive specification under Windows).
+ if (ret.at(0) != slashChar) {
+ Q_ASSERT(ret.length() >= 2);
+ Q_ASSERT(ret.at(0).isLetter());
+ Q_ASSERT(ret.at(1) == QLatin1Char(':'));
+
+ // Force uppercase drive letters.
+ ret[0] = ret.at(0).toUpper();
+ }
+
+ if (file == AbsolutePathName) {
+ int slash = ret.lastIndexOf(slashChar);
+ if (slash < 0)
+ return ret;
+ else if (ret.at(0) != slashChar && slash == 2)
+ return ret.left(3); // include the slash
+ else
+ return ret.left(slash > 0 ? slash : 1);
+ }
+ return ret;
+ } else if(file == CanonicalName || file == CanonicalPathName) {
+ if (!(fileFlags(ExistsFlag) & ExistsFlag))
+ return QString();
+
+ QString ret = QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName));
+ if (file == CanonicalPathName && !ret.isEmpty()) {
+ int slash = ret.lastIndexOf(slashChar);
+ if (slash == -1)
+ ret = QDir::fromNativeSeparators(QDir::currentPath());
+ else if (slash == 0)
+ ret = QLatin1String("/");
+ ret = ret.left(slash);
+ }
+ return ret;
+ } else if(file == LinkName) {
+ if (d->isSymlink()) {
+ char s[PATH_MAX+1];
+ int len = readlink(d->nativeFilePath.constData(), s, PATH_MAX);
+ if (len > 0) {
+ s[len] = '\0';
+ QString ret = QFile::decodeName(QByteArray(s));
+
+ if (isRelativePathSymbian(ret)) {
+ if (!isRelativePathSymbian(d->filePath)) {
+ ret.prepend(d->filePath.left(d->filePath.lastIndexOf(slashChar))
+ + slashChar);
+ } else {
+ ret.prepend(QDir::currentPath() + slashChar);
+ }
+ }
+ ret = QDir::cleanPath(ret);
+ if (ret.size() > 1 && ret.endsWith(slashChar))
+ ret.chop(1);
+ return ret;
+ }
+ }
+ return QString();
+ } else if(file == BundleName) {
+ return QString();
+ }
+ return d->filePath;
+}
+
+#else
+
QString QFSFileEngine::fileName(FileName file) const
{
Q_D(const QFSFileEngine);
@@ -690,9 +950,9 @@ QString QFSFileEngine::fileName(FileName file) const
#if !defined(QWS) && defined(Q_OS_MAC)
QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(d->filePath),
kCFURLPOSIXPathStyle, true);
- if(CFDictionaryRef dict = CFBundleCopyInfoDictionaryForURL(url)) {
- if(CFTypeRef name = (CFTypeRef)CFDictionaryGetValue(dict, kCFBundleNameKey)) {
- if(CFGetTypeID(name) == CFStringGetTypeID())
+ if (CFDictionaryRef dict = CFBundleCopyInfoDictionaryForURL(url)) {
+ if (CFTypeRef name = (CFTypeRef)CFDictionaryGetValue(dict, kCFBundleNameKey)) {
+ if (CFGetTypeID(name) == CFStringGetTypeID())
return QCFString::toQString((CFStringRef)name);
}
}
@@ -723,7 +983,7 @@ QString QFSFileEngine::fileName(FileName file) const
bool isDir = ret.endsWith(QLatin1Char('/'));
ret = QDir::cleanPath(ret);
if (isDir)
- ret += QLatin1String("/");
+ ret += QLatin1Char('/');
if (file == AbsolutePathName) {
int slash = ret.lastIndexOf(QLatin1Char('/'));
if (slash == -1)
@@ -738,7 +998,7 @@ QString QFSFileEngine::fileName(FileName file) const
return QString();
QString ret = QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName));
- if (!ret.isEmpty() && file == CanonicalPathName) {
+ if (file == CanonicalPathName && !ret.isEmpty()) {
int slash = ret.lastIndexOf(QLatin1Char('/'));
if (slash == -1)
ret = QDir::currentPath();
@@ -756,11 +1016,7 @@ QString QFSFileEngine::fileName(FileName file) const
int size = PATH_CHUNK_SIZE;
while (1) {
- s = (char *) ::realloc(s, size);
- if (s == 0) {
- len = -1;
- break;
- }
+ s = q_check_ptr((char *) ::realloc(s, size));
len = ::readlink(d->nativeFilePath.constData(), s, size);
if (len < 0) {
::free(s);
@@ -787,7 +1043,7 @@ QString QFSFileEngine::fileName(FileName file) const
s[len] = '\0';
ret += QFile::decodeName(QByteArray(s));
#if defined(__GLIBC__) && !defined(PATH_MAX)
- ::free(s);
+ ::free(s);
#endif
if (!ret.startsWith(QLatin1Char('/'))) {
@@ -824,14 +1080,16 @@ QString QFSFileEngine::fileName(FileName file) const
}
return d->filePath;
}
+#endif // Q_OS_SYMBIAN
bool QFSFileEngine::isRelativePath() const
{
Q_D(const QFSFileEngine);
- int len = d->filePath.length();
- if (len == 0)
- return true;
- return d->filePath[0] != QLatin1Char('/');
+#if defined(Q_OS_SYMBIAN)
+ return isRelativePathSymbian(d->filePath);
+#else
+ return d->filePath.length() ? d->filePath[0] != QLatin1Char('/') : true;
+#endif
}
uint QFSFileEngine::ownerId(FileOwner own) const
@@ -867,6 +1125,7 @@ QString QFSFileEngine::owner(FileOwner own) const
if (pw)
return QFile::decodeName(QByteArray(pw->pw_name));
} else if (own == OwnerGroup) {
+#if !defined(Q_OS_SYMBIAN)
struct group *gr = 0;
#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
size_max = sysconf(_SC_GETGR_R_SIZE_MAX);
@@ -884,12 +1143,12 @@ QString QFSFileEngine::owner(FileOwner own) const
|| errno != ERANGE)
break;
}
-
#else
gr = getgrgid(ownerId(own));
#endif
if (gr)
return QFile::decodeName(QByteArray(gr->gr_name));
+#endif
}
return QString();
}
@@ -897,6 +1156,7 @@ QString QFSFileEngine::owner(FileOwner own) const
bool QFSFileEngine::setPermissions(uint perms)
{
Q_D(QFSFileEngine);
+ bool ret = false;
mode_t mode = 0;
if (perms & ReadOwnerPerm)
mode |= S_IRUSR;
@@ -923,16 +1183,27 @@ bool QFSFileEngine::setPermissions(uint perms)
if (perms & ExeOtherPerm)
mode |= S_IXOTH;
if (d->fd != -1)
- return !fchmod(d->fd, mode);
- return !::chmod(d->nativeFilePath.constData(), mode);
+ ret = fchmod(d->fd, mode) == 0;
+ else
+ ret = ::chmod(d->nativeFilePath.constData(), mode) == 0;
+ if (!ret)
+ setError(QFile::PermissionsError, qt_error_string(errno));
+ return ret;
}
bool QFSFileEngine::setSize(qint64 size)
{
Q_D(QFSFileEngine);
+ bool ret = false;
if (d->fd != -1)
- return !QT_FTRUNCATE(d->fd, size);
- return !QT_TRUNCATE(d->nativeFilePath.constData(), size);
+ ret = QT_FTRUNCATE(d->fd, size) == 0;
+ else if (d->fh)
+ ret = QT_FTRUNCATE(QT_FILENO(d->fh), size) == 0;
+ else
+ ret = QT_TRUNCATE(d->nativeFilePath.constData(), size) == 0;
+ if (!ret)
+ setError(QFile::ResizeError, qt_error_string(errno));
+ return ret;
}
QDateTime QFSFileEngine::fileTime(FileTime time) const
@@ -954,14 +1225,14 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
{
Q_Q(QFSFileEngine);
Q_UNUSED(flags);
- if (offset < 0) {
- q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
- return 0;
- }
if (openMode == QIODevice::NotOpen) {
q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
return 0;
}
+ if (offset < 0) {
+ q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
+ return 0;
+ }
int access = 0;
if (openMode & QIODevice::ReadOnly) access |= PROT_READ;
if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE;
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index 6c5ccfa..5ff0716 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -47,10 +47,6 @@
#include "qfile.h"
#include "qdir.h"
-#include "qtemporaryfile.h"
-#ifndef QT_NO_REGEXP
-# include "qregexp.h"
-#endif
#include "private/qmutexpool_p.h"
#include "qvarlengtharray.h"
#include "qdatetime.h"
@@ -59,6 +55,7 @@
#if !defined(Q_OS_WINCE)
# include <sys/types.h>
# include <direct.h>
+# include <winioctl.h>
#else
# include <types.h>
#endif
@@ -92,6 +89,45 @@ typedef INT_PTR intptr_t;
# define INVALID_FILE_ATTRIBUTES (DWORD (-1))
#endif
+#if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) && !defined(Q_OS_WINCE)
+typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
+# define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
+# ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
+# define MAXIMUM_REPARSE_DATA_BUFFER_SIZE 16384
+# endif
+# ifndef IO_REPARSE_TAG_SYMLINK
+# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
+# endif
+# ifndef FSCTL_GET_REPARSE_POINT
+# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
+# endif
+#endif
+
QT_BEGIN_NAMESPACE
static QString readLink(const QString &link);
@@ -109,33 +145,24 @@ static QString qfsPrivateCurrentDir = QLatin1String("");
QT_BEGIN_INCLUDE_NAMESPACE
typedef DWORD (WINAPI *PtrGetNamedSecurityInfoW)(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*);
static PtrGetNamedSecurityInfoW ptrGetNamedSecurityInfoW = 0;
-typedef DECLSPEC_IMPORT BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE);
+typedef BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE);
static PtrLookupAccountSidW ptrLookupAccountSidW = 0;
-typedef DECLSPEC_IMPORT BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*);
-static PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = 0;
typedef VOID (WINAPI *PtrBuildTrusteeWithSidW)(PTRUSTEE_W, PSID);
static PtrBuildTrusteeWithSidW ptrBuildTrusteeWithSidW = 0;
-typedef VOID (WINAPI *PtrBuildTrusteeWithNameW)(PTRUSTEE_W, unsigned short*);
-static PtrBuildTrusteeWithNameW ptrBuildTrusteeWithNameW = 0;
typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACCESS_MASK);
static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0;
-typedef DECLSPEC_IMPORT PVOID (WINAPI *PtrFreeSid)(PSID);
-static PtrFreeSid ptrFreeSid = 0;
static TRUSTEE_W currentUserTrusteeW;
+static TRUSTEE_W worldTrusteeW;
-typedef BOOL (WINAPI *PtrOpenProcessToken)(HANDLE, DWORD, PHANDLE );
-static PtrOpenProcessToken ptrOpenProcessToken = 0;
-typedef BOOL (WINAPI *PtrGetUserProfileDirectoryW)( HANDLE, LPWSTR, LPDWORD);
+typedef BOOL (WINAPI *PtrGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD);
static PtrGetUserProfileDirectoryW ptrGetUserProfileDirectoryW = 0;
-typedef BOOL (WINAPI *PtrSetFilePointerEx)(HANDLE, LARGE_INTEGER, PLARGE_INTEGER, DWORD);
-static PtrSetFilePointerEx ptrSetFilePointerEx = 0;
QT_END_INCLUDE_NAMESPACE
void QFSFileEnginePrivate::resolveLibs()
{
static bool triedResolve = false;
- if(!triedResolve) {
+ if (!triedResolve) {
// need to resolve the security info functions
// protect initialization
@@ -143,7 +170,7 @@ void QFSFileEnginePrivate::resolveLibs()
QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
// check triedResolve again, since another thread may have already
// done the initialization
- if(triedResolve) {
+ if (triedResolve) {
// another thread did initialize the security function pointers,
// so we shouldn't do it again.
return;
@@ -152,193 +179,100 @@ void QFSFileEnginePrivate::resolveLibs()
triedResolve = true;
#if !defined(Q_OS_WINCE)
- if(QSysInfo::WindowsVersion & QSysInfo::WV_NT_based) {
- HINSTANCE advapiHnd = LoadLibraryW(L"advapi32");
- if (advapiHnd) {
- ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW");
- ptrLookupAccountSidW = (PtrLookupAccountSidW)GetProcAddress(advapiHnd, "LookupAccountSidW");
- ptrAllocateAndInitializeSid = (PtrAllocateAndInitializeSid)GetProcAddress(advapiHnd, "AllocateAndInitializeSid");
- ptrBuildTrusteeWithSidW = (PtrBuildTrusteeWithSidW)GetProcAddress(advapiHnd, "BuildTrusteeWithSidW");
- ptrBuildTrusteeWithNameW = (PtrBuildTrusteeWithNameW)GetProcAddress(advapiHnd, "BuildTrusteeWithNameW");
- ptrGetEffectiveRightsFromAclW = (PtrGetEffectiveRightsFromAclW)GetProcAddress(advapiHnd, "GetEffectiveRightsFromAclW");
- ptrFreeSid = (PtrFreeSid)GetProcAddress(advapiHnd, "FreeSid");
- }
- if (ptrBuildTrusteeWithNameW) {
- HINSTANCE versionHnd = LoadLibraryW(L"version");
- if (versionHnd) {
- typedef DWORD (WINAPI *PtrGetFileVersionInfoSizeW)(LPWSTR lptstrFilename,LPDWORD lpdwHandle);
- PtrGetFileVersionInfoSizeW ptrGetFileVersionInfoSizeW = (PtrGetFileVersionInfoSizeW)GetProcAddress(versionHnd, "GetFileVersionInfoSizeW");
- typedef BOOL (WINAPI *PtrGetFileVersionInfoW)(LPWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData);
- PtrGetFileVersionInfoW ptrGetFileVersionInfoW = (PtrGetFileVersionInfoW)GetProcAddress(versionHnd, "GetFileVersionInfoW");
- typedef BOOL (WINAPI *PtrVerQueryValueW)(const LPVOID pBlock,LPWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen);
- PtrVerQueryValueW ptrVerQueryValueW = (PtrVerQueryValueW)GetProcAddress(versionHnd, "VerQueryValueW");
- if(ptrGetFileVersionInfoSizeW && ptrGetFileVersionInfoW && ptrVerQueryValueW) {
- DWORD fakeHandle;
- DWORD versionSize = ptrGetFileVersionInfoSizeW(L"secur32.dll", &fakeHandle);
- if(versionSize) {
- LPVOID versionData;
- versionData = malloc(versionSize);
- if(ptrGetFileVersionInfoW(L"secur32.dll", 0, versionSize, versionData)) {
- UINT puLen;
- VS_FIXEDFILEINFO *pLocalInfo;
- if(ptrVerQueryValueW(versionData, L"\\", (void**)&pLocalInfo, &puLen)) {
- WORD wVer1, wVer2, wVer3, wVer4;
- wVer1 = HIWORD(pLocalInfo->dwFileVersionMS);
- wVer2 = LOWORD(pLocalInfo->dwFileVersionMS);
- wVer3 = HIWORD(pLocalInfo->dwFileVersionLS);
- wVer4 = LOWORD(pLocalInfo->dwFileVersionLS);
- // It will not work with secur32.dll version 5.0.2195.2862
- if(!(wVer1 == 5 && wVer2 == 0 && wVer3 == 2195 && (wVer4 == 2862 || wVer4 == 4587))) {
- HINSTANCE userHnd = LoadLibraryW(L"secur32");
- if (userHnd) {
- typedef BOOL (WINAPI *PtrGetUserNameExW)(EXTENDED_NAME_FORMAT nameFormat, ushort* lpBuffer, LPDWORD nSize);
- PtrGetUserNameExW ptrGetUserNameExW = (PtrGetUserNameExW)GetProcAddress(userHnd, "GetUserNameExW");
- if(ptrGetUserNameExW) {
- static TCHAR buffer[258];
- DWORD bufferSize = 257;
- ptrGetUserNameExW(NameSamCompatible, (ushort*)buffer, &bufferSize);
- ptrBuildTrusteeWithNameW(&currentUserTrusteeW, (ushort*)buffer);
- }
- FreeLibrary(userHnd);
- }
- }
- }
- }
- free(versionData);
- }
- }
- FreeLibrary(versionHnd);
- }
+ HINSTANCE advapiHnd = LoadLibraryW(L"advapi32");
+ if (advapiHnd) {
+ ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW");
+ ptrLookupAccountSidW = (PtrLookupAccountSidW)GetProcAddress(advapiHnd, "LookupAccountSidW");
+ ptrBuildTrusteeWithSidW = (PtrBuildTrusteeWithSidW)GetProcAddress(advapiHnd, "BuildTrusteeWithSidW");
+ ptrGetEffectiveRightsFromAclW = (PtrGetEffectiveRightsFromAclW)GetProcAddress(advapiHnd, "GetEffectiveRightsFromAclW");
+ }
+ if (ptrBuildTrusteeWithSidW) {
+ // Create TRUSTEE for current user
+ HANDLE hnd = ::GetCurrentProcess();
+ HANDLE token = 0;
+ if (::OpenProcessToken(hnd, TOKEN_QUERY, &token)) {
+ TOKEN_USER tu;
+ DWORD retsize;
+ if (::GetTokenInformation(token, TokenUser, &tu, sizeof(tu), &retsize))
+ ptrBuildTrusteeWithSidW(&currentUserTrusteeW, tu.User.Sid);
+ ::CloseHandle(token);
}
- ptrOpenProcessToken = (PtrOpenProcessToken)GetProcAddress(advapiHnd, "OpenProcessToken");
- HINSTANCE userenvHnd = LoadLibraryW(L"userenv");
- if (userenvHnd) {
- ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW");
+
+ typedef BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*);
+ PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = (PtrAllocateAndInitializeSid)GetProcAddress(advapiHnd, "AllocateAndInitializeSid");
+ typedef PVOID (WINAPI *PtrFreeSid)(PSID);
+ PtrFreeSid ptrFreeSid = (PtrFreeSid)GetProcAddress(advapiHnd, "FreeSid");
+ if (ptrAllocateAndInitializeSid && ptrFreeSid) {
+ // Create TRUSTEE for Everyone (World)
+ SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY };
+ PSID pWorld = 0;
+ if (ptrAllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pWorld))
+ ptrBuildTrusteeWithSidW(&worldTrusteeW, pWorld);
+ ptrFreeSid(pWorld);
}
- HINSTANCE kernelHnd = LoadLibraryW(L"kernel32");
- if (kernelHnd)
- ptrSetFilePointerEx = (PtrSetFilePointerEx)GetProcAddress(kernelHnd, "SetFilePointerEx");
}
+ HINSTANCE userenvHnd = LoadLibraryW(L"userenv");
+ if (userenvHnd)
+ ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW");
#endif
}
}
#endif // QT_NO_LIBRARY
// UNC functions NT
-typedef DWORD (WINAPI *PtrNetShareEnum_NT)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD);
-static PtrNetShareEnum_NT ptrNetShareEnum_NT = 0;
-typedef DWORD (WINAPI *PtrNetApiBufferFree_NT)(LPVOID);
-static PtrNetApiBufferFree_NT ptrNetApiBufferFree_NT = 0;
-typedef struct _SHARE_INFO_1_NT {
+typedef DWORD (WINAPI *PtrNetShareEnum)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD);
+static PtrNetShareEnum ptrNetShareEnum = 0;
+typedef DWORD (WINAPI *PtrNetApiBufferFree)(LPVOID);
+static PtrNetApiBufferFree ptrNetApiBufferFree = 0;
+typedef struct _SHARE_INFO_1 {
LPWSTR shi1_netname;
DWORD shi1_type;
LPWSTR shi1_remark;
-} SHARE_INFO_1_NT;
+} SHARE_INFO_1;
-bool QFSFileEnginePrivate::resolveUNCLibs_NT()
+bool QFSFileEnginePrivate::resolveUNCLibs()
{
static bool triedResolve = false;
if (!triedResolve) {
#ifndef QT_NO_THREAD
QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
if (triedResolve) {
- return ptrNetShareEnum_NT && ptrNetApiBufferFree_NT;
+ return ptrNetShareEnum && ptrNetApiBufferFree;
}
#endif
triedResolve = true;
#if !defined(Q_OS_WINCE)
HINSTANCE hLib = LoadLibraryW(L"Netapi32");
if (hLib) {
- ptrNetShareEnum_NT = (PtrNetShareEnum_NT)GetProcAddress(hLib, "NetShareEnum");
- if (ptrNetShareEnum_NT)
- ptrNetApiBufferFree_NT = (PtrNetApiBufferFree_NT)GetProcAddress(hLib, "NetApiBufferFree");
- }
-#endif
- }
- return ptrNetShareEnum_NT && ptrNetApiBufferFree_NT;
-}
-
-// UNC functions 9x
-typedef DWORD (WINAPI *PtrNetShareEnum_9x)(const char FAR *, short, char FAR *, unsigned short, unsigned short FAR *, unsigned short FAR *);
-static PtrNetShareEnum_9x ptrNetShareEnum_9x = 0;
-#ifdef LM20_NNLEN
-# define LM20_NNLEN_9x LM20_NNLEN
-#else
-# define LM20_NNLEN_9x 12
-#endif
-typedef struct _SHARE_INFO_1_9x {
- char shi1_netname[LM20_NNLEN_9x+1];
- char shi1_pad1;
- unsigned short shi1_type;
- char FAR* shi1_remark;
-} SHARE_INFO_1_9x;
-
-bool QFSFileEnginePrivate::resolveUNCLibs_9x()
-{
- static bool triedResolve = false;
- if (!triedResolve) {
-#ifndef QT_NO_THREAD
- QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
- if (triedResolve) {
- return ptrNetShareEnum_9x;
+ ptrNetShareEnum = (PtrNetShareEnum)GetProcAddress(hLib, "NetShareEnum");
+ if (ptrNetShareEnum)
+ ptrNetApiBufferFree = (PtrNetApiBufferFree)GetProcAddress(hLib, "NetApiBufferFree");
}
#endif
- triedResolve = true;
-#if !defined(Q_OS_WINCE)
- HINSTANCE hLib = LoadLibraryA("Svrapi");
- if (hLib)
- ptrNetShareEnum_9x = (PtrNetShareEnum_9x)GetProcAddress(hLib, "NetShareEnum");
-#endif
}
- return ptrNetShareEnum_9x;
+ return ptrNetShareEnum && ptrNetApiBufferFree;
}
bool QFSFileEnginePrivate::uncListSharesOnServer(const QString &server, QStringList *list)
{
- if (resolveUNCLibs_NT()) {
- SHARE_INFO_1_NT *BufPtr, *p;
+ if (resolveUNCLibs()) {
+ SHARE_INFO_1 *BufPtr, *p;
DWORD res;
- DWORD er=0,tr=0,resume=0, i;
+ DWORD er = 0, tr = 0, resume = 0, i;
do {
- res = ptrNetShareEnum_NT((wchar_t*)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr, &resume);
+ res = ptrNetShareEnum((wchar_t*)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr, &resume);
if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) {
- p=BufPtr;
+ p = BufPtr;
for (i = 1; i <= er; ++i) {
if (list && p->shi1_type == 0)
- list->append(QString::fromUtf16((unsigned short *)p->shi1_netname));
+ list->append(QString::fromWCharArray(p->shi1_netname));
p++;
}
}
- ptrNetApiBufferFree_NT(BufPtr);
- } while (res==ERROR_MORE_DATA);
+ ptrNetApiBufferFree(BufPtr);
+ } while (res == ERROR_MORE_DATA);
return res == ERROR_SUCCESS;
-
- } else if (resolveUNCLibs_9x()) {
- SHARE_INFO_1_9x *pBuf = 0;
- short cbBuffer;
- unsigned short nEntriesRead = 0;
- unsigned short nTotalEntries = 0;
- short numBuffs = 20;
- DWORD nStatus = 0;
- do {
- cbBuffer = numBuffs * sizeof(SHARE_INFO_1_9x);
- pBuf = (SHARE_INFO_1_9x *)malloc(cbBuffer);
- if (pBuf) {
- nStatus = ptrNetShareEnum_9x(server.toLocal8Bit().constData(), 1, (char FAR *)pBuf, cbBuffer, &nEntriesRead, &nTotalEntries);
- if ((nStatus == ERROR_SUCCESS)) {
- for (int i = 0; i < nEntriesRead; ++i) {
- if (list && pBuf[i].shi1_type == 0)
- list->append(QString::fromLocal8Bit(pBuf[i].shi1_netname));
- }
- free(pBuf);
- break;
- }
- free(pBuf);
- numBuffs *=2;
- }
- } while (nStatus == ERROR_MORE_DATA);
- return nStatus == ERROR_SUCCESS;
}
return false;
}
@@ -357,20 +291,22 @@ static bool isUncRoot(const QString &server)
return localPath.isEmpty();
}
-static bool isUncPath(const QString &path)
+#if !defined(Q_OS_WINCE)
+static inline bool isUncPath(const QString &path)
{
- // Starts with // or \\, but not \\. or //.
- return (path.startsWith(QLatin1String("//"))
- || path.startsWith(QLatin1String("\\\\")))
- && (path.size() > 2 && path.at(2) != QLatin1Char('.'));
+ // Starts with \\, but not \\.
+ return (path.startsWith(QLatin1String("\\\\"))
+ && path.size() > 2 && path.at(2) != QLatin1Char('.'));
}
+#endif
-static bool isRelativePath(const QString &path)
+static inline bool isRelativePath(const QString &path)
{
+ // drive, e.g. "a:", or UNC root, e.q. "//"
return !(path.startsWith(QLatin1Char('/'))
|| (path.length() >= 2
&& ((path.at(0).isLetter() && path.at(1) == QLatin1Char(':'))
- || (path.at(0) == QLatin1Char('/') && path.at(1) == QLatin1Char('/'))))); // drive, e.g. a:
+ || (path.at(0) == QLatin1Char('/') && path.at(1) == QLatin1Char('/')))));
}
static QString fixIfRelativeUncPath(const QString &path)
@@ -389,98 +325,48 @@ static bool uncShareExists(const QString &server)
QStringList parts = server.split(QLatin1Char('\\'), QString::SkipEmptyParts);
if (parts.count()) {
QStringList shares;
- if (QFSFileEnginePrivate::uncListSharesOnServer(QLatin1String("\\\\") + parts.at(0), &shares)) {
- if (parts.count() >= 2)
- return shares.contains(parts.at(1), Qt::CaseInsensitive);
- else
- return true;
- }
+ if (QFSFileEnginePrivate::uncListSharesOnServer(QLatin1String("\\\\") + parts.at(0), &shares))
+ return parts.count() >= 2 ? shares.contains(parts.at(1), Qt::CaseInsensitive) : true;
}
return false;
}
-#if !defined(Q_OS_WINCE)
-// If you change this function, remember to also change the UNICODE version
-static QString nativeAbsoluteFilePathA(const QString &path)
+static inline bool isDriveRoot(const QString &path)
{
- QString ret;
- QVarLengthArray<char, MAX_PATH> buf(MAX_PATH);
- char *fileName = 0;
- QByteArray ba = path.toLocal8Bit();
- DWORD retLen = GetFullPathNameA(ba.constData(), buf.size(), buf.data(), &fileName);
- if (retLen > (DWORD)buf.size()) {
- buf.resize(retLen);
- retLen = GetFullPathNameA(ba.constData(), buf.size(), buf.data(), &fileName);
- }
- if (retLen != 0)
- ret = QString::fromLocal8Bit(buf.data(), retLen);
- return ret;
+ return (path.length() == 3
+ && path.at(0).isLetter() && path.at(1) == QLatin1Char(':')
+ && path.at(2) == QLatin1Char('/'));
}
-#endif
-// If you change this function, remember to also change the NON-UNICODE version
-static QString nativeAbsoluteFilePathW(const QString &path)
+static QString nativeAbsoluteFilePath(const QString &path)
{
- QString ret;
+ QString absPath;
#if !defined(Q_OS_WINCE)
- QVarLengthArray<wchar_t, MAX_PATH> buf(MAX_PATH);
+ QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1));
wchar_t *fileName = 0;
- DWORD retLen = GetFullPathNameW((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
+ DWORD retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
if (retLen > (DWORD)buf.size()) {
buf.resize(retLen);
- retLen = GetFullPathNameW((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
+ retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
}
if (retLen != 0)
- ret = QString::fromUtf16((unsigned short *)buf.data(), retLen);
+ absPath = QString::fromWCharArray(buf.data(), retLen);
#else
- if (path.startsWith(QLatin1String("/")) || path.startsWith(QLatin1String("\\")))
- ret = QDir::toNativeSeparators(path);
+ if (path.startsWith(QLatin1Char('/')) || path.startsWith(QLatin1Char('\\')))
+ absPath = QDir::toNativeSeparators(path);
else
- ret = QDir::toNativeSeparators(QDir::cleanPath(qfsPrivateCurrentDir + QLatin1Char('/') + path));
+ absPath = QDir::toNativeSeparators(QDir::cleanPath(qfsPrivateCurrentDir + QLatin1Char('/') + path));
#endif
- return ret;
-}
-
-static QString nativeAbsoluteFilePath(const QString &path)
-{
- QString absPath = QT_WA_INLINE(nativeAbsoluteFilePathW(path), nativeAbsoluteFilePathA(path));
// This is really ugly, but GetFullPathName strips off whitespace at the end.
// If you for instance write ". " in the lineedit of QFileDialog,
// (which is an invalid filename) this function will strip the space off and viola,
// the file is later reported as existing. Therefore, we re-add the whitespace that
// was at the end of path in order to keep the filename invalid.
- int i = path.size() - 1;
- while (i >= 0 && path.at(i) == QLatin1Char(' ')) --i;
- int extraws = path.size() - 1 - i;
- if (extraws >= 0) {
- while (extraws) {
- absPath.append(QLatin1Char(' '));
- --extraws;
- }
- }
+ if (!path.isEmpty() && path.at(path.size() - 1) == QLatin1Char(' '))
+ absPath.append(QLatin1Char(' '));
return absPath;
}
-QByteArray QFSFileEnginePrivate::win95Name(const QString &path)
-{
- QString ret(path);
- if(path.length() > 1 && path[0] == QLatin1Char('/') && path[1] == QLatin1Char('/')) {
- // Win95 cannot handle slash-slash needs slosh-slosh.
- ret[0] = QLatin1Char('\\');
- ret[1] = QLatin1Char('\\');
- int n = ret.indexOf(QLatin1Char('/'));
- if(n >= 0)
- ret[n] = QLatin1Char('\\');
- } else if(path.length() > 3 && path[2] == QLatin1Char('/') && path[3] == QLatin1Char('/')) {
- ret[2] = QLatin1Char('\\');
- ret.remove(3, 1);
- int n = ret.indexOf(QLatin1Char('/'));
- if(n >= 0)
- ret[n] = QLatin1Char('\\');
- }
- return ret.toLocal8Bit();
-}
-
/*!
\internal
*/
@@ -493,7 +379,7 @@ QString QFSFileEnginePrivate::longFileName(const QString &path)
#if !defined(Q_OS_WINCE)
QString prefix = QLatin1String("\\\\?\\");
if (isUncPath(absPath)) {
- prefix = QLatin1String("\\\\?\\UNC\\");
+ prefix.append(QLatin1String("UNC\\")); // "\\\\?\\UNC\\"
absPath.remove(0, 2);
}
return prefix + absPath;
@@ -507,13 +393,8 @@ QString QFSFileEnginePrivate::longFileName(const QString &path)
*/
void QFSFileEnginePrivate::nativeInitFileName()
{
- QT_WA({
- QString path = longFileName(QDir::toNativeSeparators(fixIfRelativeUncPath(filePath)));
- nativeFilePath = QByteArray((const char *)path.utf16(), path.size() * 2 + 1);
- }, {
- QString path = fixIfRelativeUncPath(filePath);
- nativeFilePath = win95Name(path).replace('/', '\\');
- });
+ QString path = longFileName(QDir::toNativeSeparators(fixIfRelativeUncPath(filePath)));
+ nativeFilePath = QByteArray((const char *)path.utf16(), path.size() * 2 + 1);
}
/*
@@ -535,27 +416,16 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
// WriteOnly can create files, ReadOnly cannot.
- DWORD creationDisp = (openMode & QIODevice::WriteOnly)
- ? OPEN_ALWAYS : OPEN_EXISTING;
+ DWORD creationDisp = (openMode & QIODevice::WriteOnly) ? OPEN_ALWAYS : OPEN_EXISTING;
// Create the file handle.
- QT_WA({
- fileHandle = CreateFileW((TCHAR *)nativeFilePath.constData(),
- accessRights,
- shareMode,
- &securityAtts,
- creationDisp,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- }, {
- fileHandle = CreateFileA(nativeFilePath.constData(),
- accessRights,
- shareMode,
- &securityAtts,
- creationDisp,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- });
+ fileHandle = CreateFile((const wchar_t*)nativeFilePath.constData(),
+ accessRights,
+ shareMode,
+ &securityAtts,
+ creationDisp,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
// Bail out on error.
if (fileHandle == INVALID_HANDLE_VALUE) {
@@ -591,6 +461,9 @@ bool QFSFileEnginePrivate::nativeClose()
q->setError(QFile::UnspecifiedError, qt_error_string());
ok = false;
}
+#ifdef Q_USE_DEPRECATED_MAP_API
+ fileMapHandle = INVALID_HANDLE_VALUE;
+#endif
fileHandle = INVALID_HANDLE_VALUE;
cachedFd = -1; // gets closed by CloseHandle above
@@ -641,15 +514,31 @@ qint64 QFSFileEnginePrivate::nativeSize() const
// Not-open mode, where the file name is known: We'll check the
// file system directly.
if (openMode == QIODevice::NotOpen && !nativeFilePath.isEmpty()) {
- bool ok = false;
WIN32_FILE_ATTRIBUTE_DATA attribData;
- QT_WA({
- ok = ::GetFileAttributesExW((TCHAR *)nativeFilePath.constData(),
- GetFileExInfoStandard, &attribData);
- } , {
- ok = ::GetFileAttributesExA(nativeFilePath.constData(),
+ bool ok = ::GetFileAttributesEx((const wchar_t*)nativeFilePath.constData(),
GetFileExInfoStandard, &attribData);
- });
+ if (!ok) {
+ int errorCode = GetLastError();
+ if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
+ QByteArray path = nativeFilePath;
+ // path for the FindFirstFile should not end with a trailing slash
+ while (path.endsWith('\\'))
+ path.chop(1);
+
+ // FindFirstFile can not handle drives
+ if (!path.endsWith(':')) {
+ WIN32_FIND_DATA findData;
+ HANDLE hFind = ::FindFirstFile((const wchar_t*)path.constData(),
+ &findData);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ ::FindClose(hFind);
+ ok = true;
+ attribData.nFileSizeHigh = findData.nFileSizeHigh;
+ attribData.nFileSizeLow = findData.nFileSizeLow;
+ }
+ }
+ }
+ }
if (ok) {
qint64 size = attribData.nFileSizeHigh;
size <<= 32;
@@ -711,34 +600,27 @@ qint64 QFSFileEnginePrivate::nativePos() const
if (fileHandle == INVALID_HANDLE_VALUE)
return 0;
-#if !defined(QT_NO_LIBRARY)
- QFSFileEnginePrivate::resolveLibs();
- if (!ptrSetFilePointerEx) {
-#endif
- DWORD newFilePointer = SetFilePointer(fileHandle, 0, NULL, FILE_CURRENT);
- if (newFilePointer == 0xFFFFFFFF) {
- thatQ->setError(QFile::UnspecifiedError, qt_error_string());
- return 0;
- }
-
- // Note: returns <4GB; does not work with large files. This is the
- // case for MOC, UIC, qmake and other bootstrapped tools, and for
- // Win9x/ME.
- return qint64(newFilePointer);
-#if !defined(QT_NO_LIBRARY)
- }
-
- // This approach supports large files.
+#if !defined(Q_OS_WINCE)
LARGE_INTEGER currentFilePos;
LARGE_INTEGER offset;
- offset.LowPart = 0;
- offset.HighPart = 0;
- if (!ptrSetFilePointerEx(fileHandle, offset, &currentFilePos, FILE_CURRENT)) {
+ offset.QuadPart = 0;
+ if (!::SetFilePointerEx(fileHandle, offset, &currentFilePos, FILE_CURRENT)) {
thatQ->setError(QFile::UnspecifiedError, qt_error_string());
return 0;
}
return qint64(currentFilePos.QuadPart);
+#else
+ LARGE_INTEGER filepos;
+ filepos.HighPart = 0;
+ DWORD newFilePointer = SetFilePointer(fileHandle, 0, &filepos.HighPart, FILE_CURRENT);
+ if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
+ thatQ->setError(QFile::UnspecifiedError, qt_error_string());
+ return 0;
+ }
+
+ filepos.LowPart = newFilePointer;
+ return filepos.QuadPart;
#endif
}
@@ -747,40 +629,32 @@ qint64 QFSFileEnginePrivate::nativePos() const
*/
bool QFSFileEnginePrivate::nativeSeek(qint64 pos)
{
- Q_Q(const QFSFileEngine);
- QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q);
+ Q_Q(QFSFileEngine);
if (fh || fd != -1) {
// stdlib / stdio mode.
return seekFdFh(pos);
}
-#if !defined(QT_NO_LIBRARY)
- QFSFileEnginePrivate::resolveLibs();
- if (!ptrSetFilePointerEx) {
-#endif
- LONG seekToPos = LONG(pos); // <- lossy
- DWORD newFilePointer = SetFilePointer(fileHandle, seekToPos, NULL, FILE_BEGIN);
- if (newFilePointer == 0xFFFFFFFF) {
- thatQ->setError(QFile::UnspecifiedError, qt_error_string());
- return false;
- }
-
- // Note: does not work with large files. This is the case for MOC,
- // UIC, qmake and other bootstrapped tools, and for Win9x/ME.
- return true;
-#if !defined(QT_NO_LIBRARY)
- }
-
- // This approach supports large files.
+#if !defined(Q_OS_WINCE)
LARGE_INTEGER currentFilePos;
LARGE_INTEGER offset;
- offset.LowPart = (unsigned int)(quint64(pos) & Q_UINT64_C(0xffffffff));
- offset.HighPart = (unsigned int)((quint64(pos) >> 32) & Q_UINT64_C(0xffffffff));
- if (ptrSetFilePointerEx(fileHandle, offset, &currentFilePos, FILE_BEGIN) == 0) {
- thatQ->setError(QFile::UnspecifiedError, qt_error_string());
+ offset.QuadPart = pos;
+ if (!::SetFilePointerEx(fileHandle, offset, &currentFilePos, FILE_BEGIN)) {
+ q->setError(QFile::UnspecifiedError, qt_error_string());
+ return false;
+ }
+
+ return true;
+#else
+ DWORD newFilePointer;
+ LARGE_INTEGER *li = reinterpret_cast<LARGE_INTEGER*>(&pos);
+ newFilePointer = SetFilePointer(fileHandle, li->LowPart, &li->HighPart, FILE_BEGIN);
+ if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
+ q->setError(QFile::PositionError, qt_error_string());
return false;
}
+
return true;
#endif
}
@@ -949,35 +823,30 @@ bool QFSFileEnginePrivate::nativeIsSequential() const
bool QFSFileEngine::remove()
{
Q_D(QFSFileEngine);
- QT_WA({
- return ::DeleteFileW((TCHAR*)QFSFileEnginePrivate::longFileName(d->filePath).utf16()) != 0;
- } , {
- return ::DeleteFileA(QFSFileEnginePrivate::win95Name(d->filePath)) != 0;
- });
+ bool ret = ::DeleteFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16()) != 0;
+ if (!ret)
+ setError(QFile::RemoveError, qt_error_string());
+ return ret;
}
bool QFSFileEngine::copy(const QString &copyName)
{
Q_D(QFSFileEngine);
- QT_WA({
- return ::CopyFileW((TCHAR*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(),
- (TCHAR*)QFSFileEnginePrivate::longFileName(copyName).utf16(), true) != 0;
- } , {
- return ::CopyFileA(QFSFileEnginePrivate::win95Name(d->filePath),
- QFSFileEnginePrivate::win95Name(copyName), true) != 0;
- });
+ bool ret = ::CopyFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(),
+ (wchar_t*)QFSFileEnginePrivate::longFileName(copyName).utf16(), true) != 0;
+ if (!ret)
+ setError(QFile::CopyError, qt_error_string());
+ return ret;
}
bool QFSFileEngine::rename(const QString &newName)
{
Q_D(QFSFileEngine);
- QT_WA({
- return ::MoveFileW((TCHAR*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(),
- (TCHAR*)QFSFileEnginePrivate::longFileName(newName).utf16()) != 0;
- } , {
- return ::MoveFileA(QFSFileEnginePrivate::win95Name(d->filePath),
- QFSFileEnginePrivate::win95Name(newName)) != 0;
- });
+ bool ret = ::MoveFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(),
+ (wchar_t*)QFSFileEnginePrivate::longFileName(newName).utf16()) != 0;
+ if (!ret)
+ setError(QFile::RenameError, qt_error_string());
+ return ret;
}
static inline bool mkDir(const QString &path)
@@ -1001,34 +870,40 @@ static inline bool mkDir(const QString &path)
if (platformId == 1 && QFSFileEnginePrivate::longFileName(path).size() > 256)
return false;
#endif
- QT_WA({
- return ::CreateDirectoryW((TCHAR*)QFSFileEnginePrivate::longFileName(path).utf16(), 0);
- } , {
- return ::CreateDirectoryA(QFSFileEnginePrivate::win95Name(QFileInfo(path).absoluteFilePath()), 0);
- });
+ return ::CreateDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), 0);
}
static inline bool rmDir(const QString &path)
{
- QT_WA({
- return ::RemoveDirectoryW((TCHAR*)QFSFileEnginePrivate::longFileName(path).utf16());
- } , {
- return ::RemoveDirectoryA(QFSFileEnginePrivate::win95Name(QFileInfo(path).absoluteFilePath()));
- });
+ return ::RemoveDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16());
}
-static inline bool isDirPath(const QString &dirPath, bool *existed)
+static bool isDirPath(const QString &dirPath, bool *existed)
{
QString path = dirPath;
- if (path.length() == 2 &&path.at(1) == QLatin1Char(':'))
+ if (path.length() == 2 && path.at(1) == QLatin1Char(':'))
path += QLatin1Char('\\');
- DWORD fileAttrib = INVALID_FILE_ATTRIBUTES;
- QT_WA({
- fileAttrib = ::GetFileAttributesW((TCHAR*)QFSFileEnginePrivate::longFileName(path).utf16());
- } , {
- fileAttrib = ::GetFileAttributesA(QFSFileEnginePrivate::win95Name(QFileInfo(path).absoluteFilePath()));
- });
+ DWORD fileAttrib = ::GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16());
+ if (fileAttrib == INVALID_FILE_ATTRIBUTES) {
+ int errorCode = GetLastError();
+ if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
+ // path for the FindFirstFile should not end with a trailing slash
+ while (path.endsWith(QLatin1Char('\\')))
+ path.chop(1);
+
+ // FindFirstFile can not handle drives
+ if (!path.endsWith(QLatin1Char(':'))) {
+ WIN32_FIND_DATA findData;
+ HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(),
+ &findData);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ ::FindClose(hFind);
+ fileAttrib = findData.dwFileAttributes;
+ }
+ }
+ }
+ }
if (existed)
*existed = fileAttrib != INVALID_FILE_ATTRIBUTES;
@@ -1061,16 +936,20 @@ bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) con
for (int slash=0; slash != -1; oldslash = slash) {
slash = dirName.indexOf(QDir::separator(), oldslash+1);
if (slash == -1) {
- if(oldslash == dirName.length())
+ if (oldslash == dirName.length())
break;
slash = dirName.length();
}
if (slash) {
QString chunk = dirName.left(slash);
bool existed = false;
- if (!isDirPath(chunk, &existed) && !existed) {
- if (!mkDir(chunk))
+ if (!isDirPath(chunk, &existed)) {
+ if (!existed) {
+ if (!mkDir(chunk))
+ return false;
+ } else {
return false;
+ }
}
}
}
@@ -1110,16 +989,10 @@ bool QFSFileEngine::setCurrentPath(const QString &path)
return false;
#if !defined(Q_OS_WINCE)
- int r;
- QT_WA({
- r = ::SetCurrentDirectoryW((WCHAR*)path.utf16());
- } , {
- r = ::SetCurrentDirectoryA(QFSFileEnginePrivate::win95Name(path));
- });
- return r != 0;
+ return ::SetCurrentDirectory((wchar_t*)path.utf16()) != 0;
#else
- qfsPrivateCurrentDir = QFSFileEnginePrivate::longFileName(path);
- return true;
+ qfsPrivateCurrentDir = QFSFileEnginePrivate::longFileName(path);
+ return true;
#endif
}
@@ -1132,48 +1005,34 @@ QString QFSFileEngine::currentPath(const QString &fileName)
fileName.at(0).isLetter() && fileName.at(1) == QLatin1Char(':')) {
int drv = fileName.toUpper().at(0).toLatin1() - 'A' + 1;
if (_getdrive() != drv) {
- QT_WA({
- TCHAR buf[PATH_MAX];
- ::_wgetdcwd(drv, buf, PATH_MAX);
- ret.setUtf16((ushort*)buf, uint(::wcslen(buf)));
- }, {
- char buf[PATH_MAX];
- ::_getdcwd(drv, buf, PATH_MAX);
- ret = QString::fromLatin1(buf);
- });
+ wchar_t buf[PATH_MAX];
+ ::_wgetdcwd(drv, buf, PATH_MAX);
+ ret = QString::fromWCharArray(buf);
}
}
if (ret.isEmpty()) {
//just the pwd
- QT_WA({
- DWORD size = 0;
- WCHAR currentName[PATH_MAX];
- size = ::GetCurrentDirectoryW(PATH_MAX, currentName);
- if (size !=0) {
- if (size > PATH_MAX) {
- WCHAR * newCurrentName = new WCHAR[size];
- if (::GetCurrentDirectoryW(PATH_MAX, newCurrentName) != 0)
- ret = QString::fromUtf16((ushort*)newCurrentName);
- delete [] newCurrentName;
- } else {
- ret = QString::fromUtf16((ushort*)currentName);
- }
+ DWORD size = 0;
+ wchar_t currentName[PATH_MAX];
+ size = ::GetCurrentDirectory(PATH_MAX, currentName);
+ if (size != 0) {
+ if (size > PATH_MAX) {
+ wchar_t *newCurrentName = new wchar_t[size];
+ if (::GetCurrentDirectory(PATH_MAX, newCurrentName) != 0)
+ ret = QString::fromWCharArray(newCurrentName);
+ delete [] newCurrentName;
+ } else {
+ ret = QString::fromWCharArray(currentName);
}
- } , {
- DWORD size = 0;
- char currentName[PATH_MAX];
- size = ::GetCurrentDirectoryA(PATH_MAX, currentName);
- if (size !=0)
- ret = QString::fromLocal8Bit(currentName);
- });
+ }
}
if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
return QDir::fromNativeSeparators(ret);
#else
- Q_UNUSED(fileName);
- if (qfsPrivateCurrentDir.isEmpty())
- qfsPrivateCurrentDir = QCoreApplication::applicationDirPath();
+ Q_UNUSED(fileName);
+ if (qfsPrivateCurrentDir.isEmpty())
+ qfsPrivateCurrentDir = QCoreApplication::applicationDirPath();
return QDir::fromNativeSeparators(qfsPrivateCurrentDir);
#endif
@@ -1183,45 +1042,37 @@ QString QFSFileEngine::homePath()
{
QString ret;
#if !defined(QT_NO_LIBRARY)
- QT_WA (
- {
- QFSFileEnginePrivate::resolveLibs();
- if (ptrOpenProcessToken && ptrGetUserProfileDirectoryW) {
- HANDLE hnd = ::GetCurrentProcess();
- HANDLE token = 0;
- BOOL ok = ::ptrOpenProcessToken(hnd, TOKEN_QUERY, &token);
- if (ok) {
- DWORD dwBufferSize = 0;
- // First call, to determine size of the strings (with '\0').
- ok = ::ptrGetUserProfileDirectoryW(token, NULL, &dwBufferSize);
- if (!ok && dwBufferSize != 0) { // We got the required buffer size
- wchar_t *userDirectory = new wchar_t[dwBufferSize];
- // Second call, now we can fill the allocated buffer.
- ok = ::ptrGetUserProfileDirectoryW(token, userDirectory, &dwBufferSize);
- if (ok)
- ret = QString::fromUtf16((ushort*)userDirectory);
-
- delete [] userDirectory;
- }
- ::CloseHandle(token);
- }
- }
- }
- ,
- {
- // GetUserProfileDirectory is only available from NT 4.0,
- // so fall through for Win98 and friends version.
- })
+ QFSFileEnginePrivate::resolveLibs();
+ if (ptrGetUserProfileDirectoryW) {
+ HANDLE hnd = ::GetCurrentProcess();
+ HANDLE token = 0;
+ BOOL ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &token);
+ if (ok) {
+ DWORD dwBufferSize = 0;
+ // First call, to determine size of the strings (with '\0').
+ ok = ::ptrGetUserProfileDirectoryW(token, NULL, &dwBufferSize);
+ if (!ok && dwBufferSize != 0) { // We got the required buffer size
+ wchar_t *userDirectory = new wchar_t[dwBufferSize];
+ // Second call, now we can fill the allocated buffer.
+ ok = ::ptrGetUserProfileDirectoryW(token, userDirectory, &dwBufferSize);
+ if (ok)
+ ret = QString::fromWCharArray(userDirectory);
+
+ delete [] userDirectory;
+ }
+ ::CloseHandle(token);
+ }
+ }
#endif
- if(ret.isEmpty() || !QFile::exists(ret)) {
+ if (ret.isEmpty() || !QFile::exists(ret)) {
ret = QString::fromLocal8Bit(qgetenv("USERPROFILE").constData());
- if(ret.isEmpty() || !QFile::exists(ret)) {
+ if (ret.isEmpty() || !QFile::exists(ret)) {
ret = QString::fromLocal8Bit(qgetenv("HOMEDRIVE").constData()) + QString::fromLocal8Bit(qgetenv("HOMEPATH").constData());
- if(ret.isEmpty() || !QFile::exists(ret)) {
+ if (ret.isEmpty() || !QFile::exists(ret)) {
ret = QString::fromLocal8Bit(qgetenv("HOME").constData());
- if(ret.isEmpty() || !QFile::exists(ret)) {
+ if (ret.isEmpty() || !QFile::exists(ret)) {
#if defined(Q_OS_WINCE)
- ret = QString::fromLatin1("\\My Documents");
+ ret = QLatin1String("\\My Documents");
if (!QFile::exists(ret))
#endif
ret = rootPath();
@@ -1235,12 +1086,12 @@ QString QFSFileEngine::homePath()
QString QFSFileEngine::rootPath()
{
#if defined(Q_OS_WINCE)
- QString ret = QString::fromLatin1("/");
+ QString ret = QLatin1String("/");
#elif defined(Q_FS_FAT)
QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData());
- if(ret.isEmpty())
+ if (ret.isEmpty())
ret = QLatin1String("c:");
- ret += QLatin1String("/");
+ ret.append(QLatin1Char('/'));
#elif defined(Q_OS_OS2EMX)
char dir[4];
_abspath(dir, QLatin1String("/"), _MAX_PATH);
@@ -1252,26 +1103,22 @@ QString QFSFileEngine::rootPath()
QString QFSFileEngine::tempPath()
{
QString ret;
- int success;
- QT_WA({
+ {
wchar_t tempPath[MAX_PATH];
- success = GetTempPathW(MAX_PATH, tempPath);
- ret = QString::fromUtf16((ushort*)tempPath);
- } , {
- char tempPath[MAX_PATH];
- success = GetTempPathA(MAX_PATH, tempPath);
- ret = QString::fromLocal8Bit(tempPath);
- });
- if (ret.isEmpty() || !success) {
+ if (GetTempPath(MAX_PATH, tempPath))
+ ret = QString::fromWCharArray(tempPath);
+ if (!ret.isEmpty()) {
+ while (ret.endsWith(QLatin1Char('\\')))
+ ret.chop(1);
+ ret = QDir::fromNativeSeparators(ret);
+ }
+ }
+ if (ret.isEmpty()) {
#if !defined(Q_OS_WINCE)
- ret = QString::fromLatin1("c:/tmp");
+ ret = QLatin1String("c:/tmp");
#else
- ret = QString::fromLatin1("\\Temp");
+ ret = QLatin1String("/Temp");
#endif
- } else {
- ret = QDir::fromNativeSeparators(ret);
- while (ret.at(ret.length()-1) == QLatin1Char('/'))
- ret = ret.left(ret.length()-1);
}
return ret;
}
@@ -1284,23 +1131,21 @@ QFileInfoList QFSFileEngine::drives()
quint32 driveBits = (quint32) GetLogicalDrives() & 0x3ffffff;
#elif defined(Q_OS_OS2EMX)
quint32 driveBits, cur;
- if(DosQueryCurrentDisk(&cur,&driveBits) != NO_ERROR)
- exit(1);
+ if (DosQueryCurrentDisk(&cur, &driveBits) != NO_ERROR)
+ exit(1);
driveBits &= 0x3ffffff;
#endif
- char driveName[4];
+ char driveName[] = "A:/";
- qstrcpy(driveName, "A:/");
-
- while(driveBits) {
- if(driveBits & 1)
- ret.append(QString::fromLatin1(driveName).toUpper());
- driveName[0]++;
- driveBits = driveBits >> 1;
+ while (driveBits) {
+ if (driveBits & 1)
+ ret.append(QFileInfo(QLatin1String(driveName)));
+ driveName[0]++;
+ driveBits = driveBits >> 1;
}
return ret;
#else
- ret.append(QString::fromLatin1("/").toUpper());
+ ret.append(QFileInfo(QLatin1String("/")));
return ret;
#endif
}
@@ -1313,10 +1158,11 @@ bool QFSFileEnginePrivate::doStat() const
if (filePath.isEmpty())
return could_stat;
+
QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath;
fname = fixIfRelativeUncPath(fname);
- UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+ UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
if (fd != -1) {
#if !defined(Q_OS_WINCE)
@@ -1329,25 +1175,39 @@ bool QFSFileEnginePrivate::doStat() const
}
}
#else
- DWORD tmpAttributes = GetFileAttributesW((TCHAR*)QFSFileEnginePrivate::longFileName(fname).utf16());
+ DWORD tmpAttributes = GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(fname).utf16());
if (tmpAttributes != -1) {
fileAttrib = tmpAttributes;
could_stat = true;
- } else {
- return false;
}
#endif
} else {
- QT_WA({
- fileAttrib = GetFileAttributesW((TCHAR*)QFSFileEnginePrivate::longFileName(fname).utf16());
- } , {
- fileAttrib = GetFileAttributesA(QFSFileEnginePrivate::win95Name(QFileInfo(fname).absoluteFilePath()));
- });
+ fileAttrib = GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(fname).utf16());
+ if (fileAttrib == INVALID_FILE_ATTRIBUTES) {
+ int errorCode = GetLastError();
+ if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
+ QString path = QDir::toNativeSeparators(fname);
+ // path for the FindFirstFile should not end with a trailing slash
+ while (path.endsWith(QLatin1Char('\\')))
+ path.chop(1);
+
+ // FindFirstFile can not handle drives
+ if (!path.endsWith(QLatin1Char(':'))) {
+ WIN32_FIND_DATA findData;
+ HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(),
+ &findData);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ ::FindClose(hFind);
+ fileAttrib = findData.dwFileAttributes;
+ }
+ }
+ }
+ }
could_stat = fileAttrib != INVALID_FILE_ATTRIBUTES;
if (!could_stat) {
#if !defined(Q_OS_WINCE)
- if (!fname.isEmpty() && fname.at(0).isLetter() && fname.mid(1, fname.length()) == QLatin1String(":/")) {
- // an empty drive ??
+ if (isDriveRoot(fname)) {
+ // a valid drive ??
DWORD drivesBitmask = ::GetLogicalDrives();
int drivebit = 1 << (fname.at(0).toUpper().unicode() - QLatin1Char('A').unicode());
if (drivesBitmask & drivebit) {
@@ -1391,85 +1251,91 @@ bool QFSFileEnginePrivate::doStat() const
#endif
}
}
+
SetErrorMode(oldmode);
}
return could_stat;
}
+static QString readSymLink(const QString &link)
+{
+ QString result;
+#if !defined(Q_OS_WINCE)
+ HANDLE handle = CreateFile((wchar_t*)QFSFileEnginePrivate::longFileName(link).utf16(),
+ FILE_READ_EA,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ 0,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ 0);
+ if (handle != INVALID_HANDLE_VALUE) {
+ DWORD bufsize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
+ REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER*)qMalloc(bufsize);
+ DWORD retsize = 0;
+ if (::DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, 0, 0, rdb, bufsize, &retsize, 0)) {
+ if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+ int length = rdb->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
+ int offset = rdb->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t);
+ const wchar_t* PathBuffer = &rdb->MountPointReparseBuffer.PathBuffer[offset];
+ result = QString::fromWCharArray(PathBuffer, length);
+ } else {
+ int length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
+ int offset = rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t);
+ const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[offset];
+ result = QString::fromWCharArray(PathBuffer, length);
+ }
+ // cut-off "//?/" and "/??/"
+ if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\'))
+ result = result.mid(4);
+ }
+ qFree(rdb);
+ CloseHandle(handle);
+ }
+#else
+ Q_UNUSED(link);
+#endif // Q_OS_WINCE
+ return result;
+}
+
static QString readLink(const QString &link)
{
#if !defined(Q_OS_WINCE)
-#if !defined(QT_NO_LIBRARY)
+#if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS)
QString ret;
- QT_WA({
- bool neededCoInit = false;
- IShellLink *psl; // pointer to IShellLink i/f
- HRESULT hres;
- WIN32_FIND_DATA wfd;
- TCHAR szGotPath[MAX_PATH];
- // Get pointer to the IShellLink interface.
- hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
- IID_IShellLink, (LPVOID *)&psl);
- if(hres == CO_E_NOTINITIALIZED) { // COM was not initialized
- neededCoInit = true;
- CoInitialize(NULL);
- hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
- IID_IShellLink, (LPVOID *)&psl);
- }
- if(SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface.
- IPersistFile *ppf;
- hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
- if(SUCCEEDED(hres)) {
- hres = ppf->Load((LPOLESTR)link.utf16(), STGM_READ);
- //The original path of the link is retrieved. If the file/folder
- //was moved, the return value still have the old path.
- if(SUCCEEDED(hres)) {
- if (psl->GetPath(szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR)
- ret = QString::fromUtf16((ushort*)szGotPath);
- }
- ppf->Release();
- }
- psl->Release();
- }
- if(neededCoInit)
- CoUninitialize();
- } , {
- bool neededCoInit = false;
- IShellLinkA *psl; // pointer to IShellLink i/f
- HRESULT hres;
- WIN32_FIND_DATAA wfd;
- char szGotPath[MAX_PATH];
- // Get pointer to the IShellLink interface.
+ bool neededCoInit = false;
+ IShellLink *psl; // pointer to IShellLink i/f
+ WIN32_FIND_DATA wfd;
+ wchar_t szGotPath[MAX_PATH];
- hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
- IID_IShellLinkA, (LPVOID *)&psl);
+ // Get pointer to the IShellLink interface.
+ HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl);
- if(hres == CO_E_NOTINITIALIZED) { // COM was not initialized
- neededCoInit = true;
- CoInitialize(NULL);
- hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
- IID_IShellLinkA, (LPVOID *)&psl);
- }
- if(SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface.
- IPersistFile *ppf;
- hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
- if(SUCCEEDED(hres)) {
- hres = ppf->Load((LPOLESTR)QFileInfo(link).absoluteFilePath().utf16(), STGM_READ);
- //The original path of the link is retrieved. If the file/folder
- //was moved, the return value still have the old path.
- if(SUCCEEDED(hres)) {
- if (psl->GetPath((char*)szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR)
- ret = QString::fromLocal8Bit(szGotPath);
- }
- ppf->Release();
+ if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
+ neededCoInit = true;
+ CoInitialize(NULL);
+ hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ IID_IShellLink, (LPVOID *)&psl);
+ }
+ if (SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface.
+ IPersistFile *ppf;
+ hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
+ if (SUCCEEDED(hres)) {
+ hres = ppf->Load((LPOLESTR)link.utf16(), STGM_READ);
+ //The original path of the link is retrieved. If the file/folder
+ //was moved, the return value still have the old path.
+ if (SUCCEEDED(hres)) {
+ if (psl->GetPath(szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR)
+ ret = QString::fromWCharArray(szGotPath);
}
- psl->Release();
+ ppf->Release();
}
- if(neededCoInit)
- CoUninitialize();
- });
+ psl->Release();
+ }
+ if (neededCoInit)
+ CoUninitialize();
+
return ret;
#else
Q_UNUSED(link);
@@ -1479,7 +1345,7 @@ static QString readLink(const QString &link)
wchar_t target[MAX_PATH];
QString result;
if (SHGetShortcutTarget((wchar_t*)QFileInfo(link).absoluteFilePath().replace(QLatin1Char('/'),QLatin1Char('\\')).utf16(), target, MAX_PATH)) {
- result = QString::fromUtf16(reinterpret_cast<const ushort *> (target));
+ result = QString::fromWCharArray(target);
if (result.startsWith(QLatin1Char('"')))
result.remove(0,1);
if (result.endsWith(QLatin1Char('"')))
@@ -1489,93 +1355,49 @@ static QString readLink(const QString &link)
#endif // Q_OS_WINCE
}
-/*!
- \internal
-*/
-QString QFSFileEnginePrivate::getLink() const
-{
- return readLink(filePath);
-}
-
bool QFSFileEngine::link(const QString &newName)
{
#if !defined(Q_OS_WINCE)
-#if !defined(QT_NO_LIBRARY)
+#if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS)
bool ret = false;
QString linkName = newName;
//### assume that they add .lnk
- QT_WA({
- HRESULT hres;
- IShellLink *psl;
- bool neededCoInit = false;
+ IShellLink *psl;
+ bool neededCoInit = false;
- hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
- if(hres == CO_E_NOTINITIALIZED) { // COM was not initialized
- neededCoInit = true;
- CoInitialize(NULL);
- hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
- }
- if (SUCCEEDED(hres)) {
- hres = psl->SetPath((wchar_t *)fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16());
- if (SUCCEEDED(hres)) {
- hres = psl->SetWorkingDirectory((wchar_t *)fileName(AbsolutePathName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16());
- if (SUCCEEDED(hres)) {
- IPersistFile *ppf;
- hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
- if (SUCCEEDED(hres)) {
- hres = ppf->Save((TCHAR*)linkName.utf16(), TRUE);
- if (SUCCEEDED(hres))
- ret = true;
- ppf->Release();
- }
- }
- }
- psl->Release();
- }
- if(neededCoInit)
- CoUninitialize();
- } , {
- // the SetPath() call _sometimes_ changes the current path and when it does it sometimes
- // does not let us change it back unless we call currentPath() many times.
- QString cwd = currentPath();
- HRESULT hres;
- IShellLinkA *psl;
- bool neededCoInit = false;
+ HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
+ if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
+ neededCoInit = true;
+ CoInitialize(NULL);
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
- if(hres == CO_E_NOTINITIALIZED) { // COM was not initialized
- neededCoInit = true;
- CoInitialize(NULL);
- hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
- }
+ }
+
+ if (SUCCEEDED(hres)) {
+ hres = psl->SetPath((wchar_t *)fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16());
if (SUCCEEDED(hres)) {
- currentPath();
- hres = psl->SetPath((char *)QString::fromLocal8Bit(QFSFileEnginePrivate::win95Name(fileName(AbsoluteName))).utf16());
- currentPath();
+ hres = psl->SetWorkingDirectory((wchar_t *)fileName(AbsolutePathName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16());
if (SUCCEEDED(hres)) {
- hres = psl->SetWorkingDirectory((char *)QString::fromLocal8Bit(QFSFileEnginePrivate::win95Name(fileName(AbsolutePathName))).utf16());
- currentPath();
+ IPersistFile *ppf;
+ hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
if (SUCCEEDED(hres)) {
- IPersistFile *ppf;
- hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
- if (SUCCEEDED(hres)) {
- currentPath();
- hres = ppf->Save((LPCOLESTR)linkName.utf16(), TRUE);
- currentPath();
- if (SUCCEEDED(hres))
- ret = true;
- ppf->Release();
- }
+ hres = ppf->Save((wchar_t*)linkName.utf16(), TRUE);
+ if (SUCCEEDED(hres))
+ ret = true;
+ ppf->Release();
}
- psl->Release();
}
}
- if(neededCoInit)
- CoUninitialize();
- setCurrentPath(cwd);
- });
+ psl->Release();
+ }
+ if (!ret)
+ setError(QFile::RenameError, qt_error_string());
+
+ if (neededCoInit)
+ CoUninitialize();
+
return ret;
#else
Q_UNUSED(newName);
@@ -1589,7 +1411,10 @@ bool QFSFileEngine::link(const QString &newName)
// Need to append on our own
orgName.prepend(QLatin1Char('"'));
orgName.append(QLatin1Char('"'));
- return SUCCEEDED(SHCreateShortcut((wchar_t*)linkName.utf16(), (wchar_t*)orgName.utf16()));
+ bool ret = SUCCEEDED(SHCreateShortcut((wchar_t*)linkName.utf16(), (wchar_t*)orgName.utf16()));
+ if (!ret)
+ setError(QFile::RenameError, qt_error_string());
+ return ret;
#endif // Q_OS_WINCE
}
@@ -1602,71 +1427,64 @@ QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions() const
#if !defined(QT_NO_LIBRARY)
if((qt_ntfs_permission_lookup > 0) && ((QSysInfo::WindowsVersion&QSysInfo::WV_NT_based) > QSysInfo::WV_NT)) {
- PSID pOwner = 0;
- PSID pGroup = 0;
- PACL pDacl;
+ PSID pOwner = 0;
+ PSID pGroup = 0;
+ PACL pDacl;
PSECURITY_DESCRIPTOR pSD;
ACCESS_MASK access_mask;
enum { ReadMask = 0x00000001, WriteMask = 0x00000002, ExecMask = 0x00000020 };
resolveLibs();
- if(ptrGetNamedSecurityInfoW && ptrAllocateAndInitializeSid && ptrBuildTrusteeWithSidW && ptrGetEffectiveRightsFromAclW && ptrFreeSid) {
+ if(ptrGetNamedSecurityInfoW && ptrBuildTrusteeWithSidW && ptrGetEffectiveRightsFromAclW) {
QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath;
DWORD res = ptrGetNamedSecurityInfoW((wchar_t*)fname.utf16(), SE_FILE_OBJECT,
- OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
- &pOwner, &pGroup, &pDacl, 0, &pSD);
+ OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+ &pOwner, &pGroup, &pDacl, 0, &pSD);
if(res == ERROR_SUCCESS) {
TRUSTEE_W trustee;
{ //user
if(ptrGetEffectiveRightsFromAclW(pDacl, &currentUserTrusteeW, &access_mask) != ERROR_SUCCESS)
access_mask = (ACCESS_MASK)-1;
- if(access_mask & ReadMask)
- ret |= QAbstractFileEngine::ReadUserPerm;
- if(access_mask & WriteMask)
- ret |= QAbstractFileEngine::WriteUserPerm;
- if(access_mask & ExecMask)
- ret |= QAbstractFileEngine::ExeUserPerm;
+ if(access_mask & ReadMask)
+ ret |= QAbstractFileEngine::ReadUserPerm;
+ if(access_mask & WriteMask)
+ ret |= QAbstractFileEngine::WriteUserPerm;
+ if(access_mask & ExecMask)
+ ret |= QAbstractFileEngine::ExeUserPerm;
}
{ //owner
ptrBuildTrusteeWithSidW(&trustee, pOwner);
if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS)
access_mask = (ACCESS_MASK)-1;
- if(access_mask & ReadMask)
- ret |= QAbstractFileEngine::ReadOwnerPerm;
- if(access_mask & WriteMask)
- ret |= QAbstractFileEngine::WriteOwnerPerm;
- if(access_mask & ExecMask)
- ret |= QAbstractFileEngine::ExeOwnerPerm;
+ if(access_mask & ReadMask)
+ ret |= QAbstractFileEngine::ReadOwnerPerm;
+ if(access_mask & WriteMask)
+ ret |= QAbstractFileEngine::WriteOwnerPerm;
+ if(access_mask & ExecMask)
+ ret |= QAbstractFileEngine::ExeOwnerPerm;
}
{ //group
ptrBuildTrusteeWithSidW(&trustee, pGroup);
if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS)
access_mask = (ACCESS_MASK)-1;
- if(access_mask & ReadMask)
- ret |= QAbstractFileEngine::ReadGroupPerm;
- if(access_mask & WriteMask)
- ret |= QAbstractFileEngine::WriteGroupPerm;
- if(access_mask & ExecMask)
- ret |= QAbstractFileEngine::ExeGroupPerm;
+ if(access_mask & ReadMask)
+ ret |= QAbstractFileEngine::ReadGroupPerm;
+ if(access_mask & WriteMask)
+ ret |= QAbstractFileEngine::WriteGroupPerm;
+ if(access_mask & ExecMask)
+ ret |= QAbstractFileEngine::ExeGroupPerm;
}
{ //other (world)
- // Create SID for Everyone (World)
- SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY };
- PSID pWorld = 0;
- if(ptrAllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &pWorld)) {
- ptrBuildTrusteeWithSidW(&trustee, pWorld);
- if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS)
- access_mask = (ACCESS_MASK)-1; // ###
- if(access_mask & ReadMask)
- ret |= QAbstractFileEngine::ReadOtherPerm;
- if(access_mask & WriteMask)
- ret |= QAbstractFileEngine::WriteOtherPerm;
- if(access_mask & ExecMask)
- ret |= QAbstractFileEngine::ExeOtherPerm;
- }
- ptrFreeSid(pWorld);
+ if(ptrGetEffectiveRightsFromAclW(pDacl, &worldTrusteeW, &access_mask) != ERROR_SUCCESS)
+ access_mask = (ACCESS_MASK)-1; // ###
+ if(access_mask & ReadMask)
+ ret |= QAbstractFileEngine::ReadOtherPerm;
+ if(access_mask & WriteMask)
+ ret |= QAbstractFileEngine::WriteOtherPerm;
+ if(access_mask & ExecMask)
+ ret |= QAbstractFileEngine::ExeOtherPerm;
}
LocalFree(pSD);
}
@@ -1674,33 +1492,69 @@ QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions() const
} else
#endif
{
- //### what to do with permissions if we don't use ntfs or are not on a NT system
- // for now just add all permissions and what about exe missions ??
- // also qt_ntfs_permission_lookup is now not set by defualt ... should it ?
- ret |= QAbstractFileEngine::ReadOtherPerm | QAbstractFileEngine::ReadGroupPerm
- | QAbstractFileEngine::ReadOwnerPerm | QAbstractFileEngine::ReadUserPerm
- | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::WriteOwnerPerm
- | QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm;
- }
-
- if (doStat()) {
- if (ret & (QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm |
- QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm)) {
- if (fileAttrib & FILE_ATTRIBUTE_READONLY)
- ret &= ~(QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm |
- QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm);
- }
+ //### what to do with permissions if we don't use NTFS
+ // for now just add all permissions and what about exe missions ??
+ // also qt_ntfs_permission_lookup is now not set by defualt ... should it ?
+ ret |= QAbstractFileEngine::ReadOtherPerm | QAbstractFileEngine::ReadGroupPerm
+ | QAbstractFileEngine::ReadOwnerPerm | QAbstractFileEngine::ReadUserPerm
+ | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::WriteOwnerPerm
+ | QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm;
+
+ if (doStat()) {
+ if (ret & (QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm |
+ QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm)) {
+ if (fileAttrib & FILE_ATTRIBUTE_READONLY)
+ ret &= ~(QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm |
+ QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm);
+ }
- QString ext = filePath.right(4).toLower();
- if (ext == QLatin1String(".exe") || ext == QLatin1String(".com") || ext == QLatin1String(".bat") ||
- ext == QLatin1String(".pif") || ext == QLatin1String(".cmd") || (fileAttrib & FILE_ATTRIBUTE_DIRECTORY))
- ret |= QAbstractFileEngine::ExeOwnerPerm | QAbstractFileEngine::ExeGroupPerm |
- QAbstractFileEngine::ExeOtherPerm | QAbstractFileEngine::ExeUserPerm;
+ QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath;
+ QString ext = fname.right(4).toLower();
+ if (ext == QLatin1String(".exe") || ext == QLatin1String(".com") || ext == QLatin1String(".bat") ||
+ ext == QLatin1String(".pif") || ext == QLatin1String(".cmd") || (fileAttrib & FILE_ATTRIBUTE_DIRECTORY))
+ ret |= QAbstractFileEngine::ExeOwnerPerm | QAbstractFileEngine::ExeGroupPerm |
+ QAbstractFileEngine::ExeOtherPerm | QAbstractFileEngine::ExeUserPerm;
+ }
}
return ret;
}
/*!
+ \internal
+*/
+bool QFSFileEnginePrivate::isSymlink() const
+{
+#if !defined(Q_OS_WINCE)
+ if (need_lstat) {
+ need_lstat = false;
+ is_link = false;
+
+ if (fileAttrib & FILE_ATTRIBUTE_REPARSE_POINT) {
+ QString path = QDir::toNativeSeparators(filePath);
+ // path for the FindFirstFile should not end with a trailing slash
+ while (path.endsWith(QLatin1Char('\\')))
+ path.chop(1);
+
+ WIN32_FIND_DATA findData;
+ HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(),
+ &findData);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ ::FindClose(hFind);
+ if ((findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ && (findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT
+ || findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
+ is_link = true;
+ }
+ }
+ }
+ }
+ return is_link;
+#else
+ return false;
+#endif // Q_OS_WINCE
+}
+
+/*!
\reimp
*/
QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const
@@ -1708,8 +1562,11 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil
Q_D(const QFSFileEngine);
QAbstractFileEngine::FileFlags ret = 0;
// Force a stat, so that we're guaranteed to get up-to-date results
- if (type & QAbstractFileEngine::FileFlag(QAbstractFileEngine::Refresh)) {
+ if (type & Refresh) {
d->tried_stat = 0;
+#if !defined(Q_OS_WINCE)
+ d->need_lstat = 1;
+#endif
}
if (type & PermsMask) {
@@ -1726,12 +1583,15 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil
ret |= LinkType;
QString l = readLink(d->filePath);
if (!l.isEmpty()) {
- if (isDirPath(l, 0))
+ bool existed = false;
+ if (isDirPath(l, &existed) && existed)
ret |= DirectoryType;
- else
+ else if (existed)
ret |= FileType;
}
} else if (d->doStat()) {
+ if ((type & LinkType) && d->isSymlink())
+ ret |= LinkType;
if (d->fileAttrib & FILE_ATTRIBUTE_DIRECTORY) {
ret |= DirectoryType;
} else {
@@ -1740,14 +1600,15 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil
}
}
if (type & FlagsMask) {
- if(d->doStat()) {
- ret |= QAbstractFileEngine::FileFlags(ExistsFlag | LocalDiskFlag);
- if (d->fileAttrib & FILE_ATTRIBUTE_HIDDEN)
- ret |= HiddenFlag;
- if (d->filePath == QLatin1String("/") || (d->filePath.at(0).isLetter() && d->filePath.mid(1,d->filePath.length()) == QLatin1String(":/"))
- || isUncRoot(d->filePath)) {
+ ret |= LocalDiskFlag;
+ if (d->doStat()) {
+ ret |= ExistsFlag;
+ if (d->filePath == QLatin1String("/") || isDriveRoot(d->filePath) || isUncRoot(d->filePath)) {
ret |= RootFlag;
- ret &= ~HiddenFlag;
+ } else if (d->fileAttrib & FILE_ATTRIBUTE_HIDDEN) {
+ QString baseName = fileName(BaseName);
+ if (baseName != QLatin1String(".") && baseName != QLatin1String(".."))
+ ret |= HiddenFlag;
}
}
}
@@ -1757,38 +1618,38 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil
QString QFSFileEngine::fileName(FileName file) const
{
Q_D(const QFSFileEngine);
- if(file == BaseName) {
+ if (file == BaseName) {
int slash = d->filePath.lastIndexOf(QLatin1Char('/'));
- if(slash == -1) {
+ if (slash == -1) {
int colon = d->filePath.lastIndexOf(QLatin1Char(':'));
- if(colon != -1)
+ if (colon != -1)
return d->filePath.mid(colon + 1);
return d->filePath;
}
return d->filePath.mid(slash + 1);
- } else if(file == PathName) {
- if(!d->filePath.size())
+ } else if (file == PathName) {
+ if (!d->filePath.size())
return d->filePath;
int slash = d->filePath.lastIndexOf(QLatin1Char('/'));
- if(slash == -1) {
- if(d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':'))
+ if (slash == -1) {
+ if (d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':'))
return d->filePath.left(2);
- return QString::fromLatin1(".");
+ return QString(QLatin1Char('.'));
} else {
- if(!slash)
- return QString::fromLatin1("/");
- if(slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':'))
+ if (!slash)
+ return QString(QLatin1Char('/'));
+ if (slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':'))
slash++;
return d->filePath.left(slash);
}
- } else if(file == AbsoluteName || file == AbsolutePathName) {
+ } else if (file == AbsoluteName || file == AbsolutePathName) {
QString ret;
if (!isRelativePath()) {
#if !defined(Q_OS_WINCE)
- if (d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':')
- && d->filePath.at(2) != QLatin1Char('/') || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt
+ if ((d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':')
+ && d->filePath.at(2) != QLatin1Char('/')) || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt
d->filePath.startsWith(QLatin1Char('/')) // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt
) {
ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(d->filePath));
@@ -1796,7 +1657,7 @@ QString QFSFileEngine::fileName(FileName file) const
ret = d->filePath;
}
#else
- ret = d->filePath;
+ ret = d->filePath;
#endif
} else {
ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + d->filePath);
@@ -1825,7 +1686,7 @@ QString QFSFileEngine::fileName(FileName file) const
return ret.left(slash > 0 ? slash : 1);
}
return ret;
- } else if(file == CanonicalName || file == CanonicalPathName) {
+ } else if (file == CanonicalName || file == CanonicalPathName) {
if (!(fileFlags(ExistsFlag) & ExistsFlag))
return QString();
@@ -1835,13 +1696,18 @@ QString QFSFileEngine::fileName(FileName file) const
if (slash == -1)
ret = QDir::currentPath();
else if (slash == 0)
- ret = QLatin1String("/");
+ ret = QString(QLatin1Char('/'));
ret = ret.left(slash);
}
return ret;
- } else if(file == LinkName) {
- return QDir::fromNativeSeparators(d->getLink());
- } else if(file == BundleName) {
+ } else if (file == LinkName) {
+ QString ret;
+ if (d->filePath.endsWith(QLatin1String(".lnk")))
+ ret = readLink(d->filePath);
+ else if (d->doStat() && d->isSymlink())
+ ret = readSymLink(d->filePath);
+ return QDir::fromNativeSeparators(ret);
+ } else if (file == BundleName) {
return QString();
}
return d->filePath;
@@ -1850,10 +1716,11 @@ QString QFSFileEngine::fileName(FileName file) const
bool QFSFileEngine::isRelativePath() const
{
Q_D(const QFSFileEngine);
+ // drive, e.g. "a:", or UNC root, e.q. "//"
return !(d->filePath.startsWith(QLatin1Char('/'))
|| (d->filePath.length() >= 2
&& ((d->filePath.at(0).isLetter() && d->filePath.at(1) == QLatin1Char(':'))
- || (d->filePath.at(0) == QLatin1Char('/') && d->filePath.at(1) == QLatin1Char('/'))))); // drive, e.g. a:
+ || (d->filePath.at(0) == QLatin1Char('/') && d->filePath.at(1) == QLatin1Char('/')))));
}
uint QFSFileEngine::ownerId(FileOwner /*own*/) const
@@ -1897,7 +1764,7 @@ QString QFSFileEngine::owner(FileOwner own) const
#else
Q_UNUSED(own);
#endif
- return QString(QLatin1String(""));
+ return QString();
}
bool QFSFileEngine::setPermissions(uint perms)
@@ -1914,16 +1781,10 @@ bool QFSFileEngine::setPermissions(uint perms)
if (mode == 0) // not supported
return false;
-#if !defined(Q_OS_WINCE)
- QT_WA({
- ret = ::_wchmod((TCHAR*)d->filePath.utf16(), mode) == 0;
- } , {
- ret = ::_chmod(d->filePath.toLocal8Bit(), mode) == 0;
- });
-#else
- ret = ::_wchmod((TCHAR*)d->longFileName(d->filePath).utf16(), mode);
-#endif
- return ret;
+ ret = ::_wchmod((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), mode) == 0;
+ if (!ret)
+ setError(QFile::PermissionsError, qt_error_string(errno));
+ return ret;
}
bool QFSFileEngine::setSize(qint64 size)
@@ -1954,7 +1815,10 @@ bool QFSFileEngine::setSize(qint64 size)
// resize file on disk
QFile file(d->filePath);
if (file.open(QFile::ReadWrite)) {
- return file.resize(size);
+ bool ret = file.resize(size);
+ if (!ret)
+ setError(QFile::ResizeError, file.errorString());
+ return ret;
}
}
return false;
@@ -1964,34 +1828,33 @@ bool QFSFileEngine::setSize(qint64 size)
static inline QDateTime fileTimeToQDateTime(const FILETIME *time)
{
QDateTime ret;
- if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based || QSysInfo::WindowsVersion & QSysInfo::WV_CE_based) {
- // SystemTimeToTzSpecificLocalTime is not available on Win98/ME so we have to pull it off ourselves.
- SYSTEMTIME systime;
- FILETIME ftime;
- systime.wYear = 1970;
- systime.wMonth = 1;
- systime.wDay = 1;
- systime.wHour = 0;
- systime.wMinute = 0;
- systime.wSecond = 0;
- systime.wMilliseconds = 0;
- systime.wDayOfWeek = 4;
- SystemTimeToFileTime(&systime, &ftime);
- unsigned __int64 acttime = (unsigned __int64)time->dwHighDateTime << 32 | time->dwLowDateTime;
- FileTimeToSystemTime(time, &systime);
- unsigned __int64 time1970 = (unsigned __int64)ftime.dwHighDateTime << 32 | ftime.dwLowDateTime;
- unsigned __int64 difftime = acttime - time1970;
- difftime /= 10000000;
- ret.setTime_t((unsigned int)difftime);
- } else {
-#ifndef Q_OS_WINCE
- SYSTEMTIME sTime, lTime;
- FileTimeToSystemTime(time, &sTime);
- SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime);
- ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay));
- ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds));
+
+#if defined(Q_OS_WINCE)
+ SYSTEMTIME systime;
+ FILETIME ftime;
+ systime.wYear = 1970;
+ systime.wMonth = 1;
+ systime.wDay = 1;
+ systime.wHour = 0;
+ systime.wMinute = 0;
+ systime.wSecond = 0;
+ systime.wMilliseconds = 0;
+ systime.wDayOfWeek = 4;
+ SystemTimeToFileTime(&systime, &ftime);
+ unsigned __int64 acttime = (unsigned __int64)time->dwHighDateTime << 32 | time->dwLowDateTime;
+ FileTimeToSystemTime(time, &systime);
+ unsigned __int64 time1970 = (unsigned __int64)ftime.dwHighDateTime << 32 | ftime.dwLowDateTime;
+ unsigned __int64 difftime = acttime - time1970;
+ difftime /= 10000000;
+ ret.setTime_t((unsigned int)difftime);
+#else
+ SYSTEMTIME sTime, lTime;
+ FileTimeToSystemTime(time, &sTime);
+ SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime);
+ ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay));
+ ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds));
#endif
- }
+
return ret;
}
@@ -2015,13 +1878,31 @@ QDateTime QFSFileEngine::fileTime(FileTime time) const
}
#endif
} else {
- bool ok = false;
WIN32_FILE_ATTRIBUTE_DATA attribData;
- QT_WA({
- ok = ::GetFileAttributesExW((TCHAR*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), GetFileExInfoStandard, &attribData);
- } , {
- ok = ::GetFileAttributesExA(QFSFileEnginePrivate::win95Name(QFileInfo(d->filePath).absoluteFilePath()), GetFileExInfoStandard, &attribData);
- });
+ bool ok = ::GetFileAttributesEx((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), GetFileExInfoStandard, &attribData);
+ if (!ok) {
+ int errorCode = GetLastError();
+ if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
+ QString path = QDir::toNativeSeparators(d->filePath);
+ // path for the FindFirstFile should not end with a trailing slash
+ while (path.endsWith(QLatin1Char('\\')))
+ path.chop(1);
+
+ // FindFirstFile can not handle drives
+ if (!path.endsWith(QLatin1Char(':'))) {
+ WIN32_FIND_DATA findData;
+ HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(),
+ &findData);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ ::FindClose(hFind);
+ ok = true;
+ attribData.ftCreationTime = findData.ftCreationTime;
+ attribData.ftLastWriteTime = findData.ftLastWriteTime;
+ attribData.ftLastAccessTime = findData.ftLastAccessTime;
+ }
+ }
+ }
+ }
if (ok) {
if(time == CreationTime)
ret = fileTimeToQDateTime(&attribData.ftCreationTime);
@@ -2040,12 +1921,12 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
Q_Q(QFSFileEngine);
Q_UNUSED(flags);
if (openMode == QFile::NotOpen) {
- q->setError(QFile::PermissionsError, qt_error_string());
- return 0;
+ q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
+ return 0;
}
if (offset == 0 && size == 0) {
- q->setError(QFile::UnspecifiedError, qt_error_string());
- return 0;
+ q->setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
+ return 0;
}
@@ -2054,11 +1935,12 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
#ifndef Q_OS_WINCE
if (handle == INVALID_HANDLE_VALUE && fh)
handle = (HANDLE)_get_osfhandle(QT_FILENO(fh));
-#else
- #ifdef Q_USE_DEPRECATED_MAP_API
- nativeClose();
+#endif
+
+#ifdef Q_USE_DEPRECATED_MAP_API
if (fileMapHandle == INVALID_HANDLE_VALUE) {
- fileMapHandle = CreateFileForMappingW((TCHAR *)nativeFilePath.constData(),
+ nativeClose();
+ fileMapHandle = CreateFileForMapping((const wchar_t*)nativeFilePath.constData(),
GENERIC_READ | (openMode & QIODevice::WriteOnly ? GENERIC_WRITE : 0),
0,
NULL,
@@ -2067,27 +1949,22 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
NULL);
}
handle = fileMapHandle;
- #endif
- if (handle == INVALID_HANDLE_VALUE && fh)
- return 0;
#endif
+ if (handle == INVALID_HANDLE_VALUE) {
+ q->setError(QFile::UnspecifiedError, QLatin1String("No handle on file"));
+ return 0;
+ }
+
// first create the file mapping handle
- HANDLE mapHandle = 0;
DWORD protection = (openMode & QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY;
- QT_WA({
- mapHandle = ::CreateFileMappingW(handle, 0, protection,
- 0, 0, 0);
- },{
- mapHandle = ::CreateFileMappingA(handle, 0, protection,
- 0, 0, 0);
- });
+ HANDLE mapHandle = ::CreateFileMapping(handle, 0, protection, 0, 0, 0);
if (mapHandle == NULL) {
q->setError(QFile::PermissionsError, qt_error_string());
#ifdef Q_USE_DEPRECATED_MAP_API
mapHandleClose();
#endif
- return 0;
+ return 0;
}
// setup args to map
@@ -2116,7 +1993,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
switch(GetLastError()) {
case ERROR_ACCESS_DENIED:
q->setError(QFile::PermissionsError, qt_error_string());
- break;
+ break;
case ERROR_INVALID_PARAMETER:
// size are out of bounds
default:
@@ -2133,7 +2010,7 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
{
Q_Q(QFSFileEngine);
if (!maps.contains(ptr)) {
- q->setError(QFile::PermissionsError, qt_error_string());
+ q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
return false;
}
uchar *start = ptr - maps[ptr].first;
@@ -2163,4 +2040,5 @@ void QFSFileEnginePrivate::mapHandleClose()
}
}
#endif
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 70a1b8f..75f8e54 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -48,6 +48,10 @@
#include "qstringlist.h"
#include <limits.h>
+#ifdef QIODEVICE_DEBUG
+# include <ctype.h>
+#endif
+
QT_BEGIN_NAMESPACE
#ifdef QIODEVICE_DEBUG
@@ -362,7 +366,7 @@ QIODevice::QIODevice()
{
#if defined QIODEVICE_DEBUG
QFile *file = qobject_cast<QFile *>(this);
- printf("%p QIODevice::QIODevice(\"%s\") %s\n", this, className(),
+ printf("%p QIODevice::QIODevice(\"%s\") %s\n", this, metaObject()->className(),
qPrintable(file ? file->fileName() : QString()));
#endif
}
@@ -375,7 +379,7 @@ QIODevice::QIODevice(QObject *parent)
: QObject(*new QIODevicePrivate, parent)
{
#if defined QIODEVICE_DEBUG
- printf("%p QIODevice::QIODevice(%p \"%s\")\n", this, parent, className());
+ printf("%p QIODevice::QIODevice(%p \"%s\")\n", this, parent, metaObject()->className());
#endif
}
@@ -807,7 +811,7 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
#endif
if (readFromDevice < bytesToBuffer)
- d->buffer.truncate(readFromDevice < 0 ? 0 : int(readFromDevice));
+ d->buffer.truncate(int(readFromDevice));
if (!d->buffer.isEmpty()) {
lastReadChunkSize = d->buffer.read(data + readSoFar, maxSize - readSoFar);
readSoFar += lastReadChunkSize;
@@ -1032,6 +1036,15 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize)
if (readSoFar)
debugBinaryString(data, int(readSoFar));
#endif
+#if defined(Q_OS_SYMBIAN)
+ // Open C fgets strips '\r' but readSoFar gets returned as if it was still there
+ if ((d->openMode & Text) &&
+ readSoFar > 1 &&
+ data[readSoFar - 1] == '\0' &&
+ data[readSoFar - 2] == '\n') {
+ --readSoFar;
+ }
+#endif
if (readSoFar && data[readSoFar - 1] == '\n') {
if (d->openMode & Text) {
// QRingBuffer::readLine() isn't Text aware.
@@ -1070,6 +1083,12 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize)
data[readSoFar] = '\0';
if (d->openMode & Text) {
+#if defined(Q_OS_SYMBIAN)
+ // Open C fgets strips '\r' but readSoFar gets returned as if it was still there
+ if (readSoFar > 1 && data[readSoFar - 1] == '\0' && data[readSoFar - 2] == '\n') {
+ --readSoFar;
+ }
+#endif
if (readSoFar > 1 && data[readSoFar - 1] == '\n' && data[readSoFar - 2] == '\r') {
data[readSoFar - 2] = '\n';
data[readSoFar - 1] = '\0';
@@ -1450,11 +1469,11 @@ QByteArray QIODevice::peek(qint64 maxSize)
}
/*!
- Blocks until data is available for reading and the readyRead()
+ Blocks until new data is available for reading and the readyRead()
signal has been emitted, or until \a msecs milliseconds have
passed. If msecs is -1, this function will not time out.
- Returns true if data is available for reading; otherwise returns
+ Returns true if new data is available for reading; otherwise returns
false (if the operation timed out or if an error occurred).
This function can operate without an event loop. It is
@@ -1741,7 +1760,7 @@ QDebug operator<<(QDebug debug, QIODevice::OpenMode modes)
}
qSort(modeList);
debug << modeList.join(QLatin1String("|"));
- debug << ")";
+ debug << ')';
return debug;
}
#endif
diff --git a/src/corelib/io/qiodevice.h b/src/corelib/io/qiodevice.h
index 7942528..5a1c106 100644
--- a/src/corelib/io/qiodevice.h
+++ b/src/corelib/io/qiodevice.h
@@ -46,6 +46,7 @@
#include <QtCore/qobject.h>
#else
#include <QtCore/qobjectdefs.h>
+#include <QtCore/qscopedpointer.h>
#endif
#include <QtCore/qstring.h>
@@ -160,7 +161,7 @@ protected:
void setErrorString(const QString &errorString);
#ifdef QT_NO_QOBJECT
- QIODevicePrivate *d_ptr;
+ QScopedPointer<QIODevicePrivate> d_ptr;
#endif
private:
diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp
new file mode 100644
index 0000000..185d961
--- /dev/null
+++ b/src/corelib/io/qnoncontiguousbytedevice.cpp
@@ -0,0 +1,543 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnoncontiguousbytedevice_p.h"
+#include <qbuffer.h>
+#include <qdebug.h>
+#include <qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QNonContiguousByteDevice
+ \brief A QNonContiguousByteDevice is a representation of a
+ file, array or buffer that allows access with a read pointer.
+ \since 4.6
+
+ \inmodule QtCore
+
+ The goal of this class is to have a data representation that
+ allows us to avoid doing a memcpy as we have to do with QIODevice.
+
+ \sa QNonContiguousByteDeviceFactory
+
+ \internal
+*/
+/*!
+ \fn virtual const char* QNonContiguousByteDevice::readPointer(qint64 maximumLength, qint64 &len)
+
+ Return a byte pointer for at most \a maximumLength bytes of that device.
+ if \a maximumLength is -1, the caller does not care about the length and
+ the device may return what it desires to.
+ The actual number of bytes the pointer is valid for is returned in
+ the \a len variable.
+ \a len will be -1 if EOF or an error occurs.
+ If it was really EOF can then afterwards be checked with atEnd()
+ Returns 0 if it is not possible to read at that position.
+
+ \sa atEnd()
+
+ \internal
+*/
+/*!
+ \fn virtual bool QNonContiguousByteDevice::advanceReadPointer(qint64 amount)
+
+ will advance the internal read pointer by \a amount bytes.
+ The old readPointer is invalid after this call.
+
+ \sa readPointer()
+
+ \internal
+*/
+/*!
+ \fn virtual bool QNonContiguousByteDevice::atEnd()
+
+ Returns true if everything has been read and the read
+ pointer cannot be advanced anymore.
+
+ \sa readPointer(), advanceReadPointer(), reset()
+
+ \internal
+*/
+/*!
+ \fn virtual bool QNonContiguousByteDevice::reset()
+
+ Moves the internal read pointer back to the beginning.
+ Returns false if this was not possible.
+
+ \sa atEnd(), disableReset()
+
+ \internal
+*/
+/*!
+ \fn void QNonContiguousByteDevice::disableReset()
+
+ Disable the reset() call, e.g. it will always
+ do nothing and return false.
+
+ \sa reset()
+
+ \internal
+*/
+/*!
+ \fn virtual qint64 QNonContiguousByteDevice::size()
+
+ Returns the size of the complete device or -1 if unknown.
+ May also return less/more than what can be actually read with readPointer()
+
+ \internal
+*/
+/*!
+ \fn void QNonContiguousByteDevice::readyRead()
+
+ Emitted when there is data available
+
+ \internal
+*/
+/*!
+ \fn void QNonContiguousByteDevice::readProgress(qint64 current, qint64 total)
+
+ Emitted when data has been "read" by advancing the read pointer
+
+ \internal
+*/
+
+QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)0), resetDisabled(false)
+{
+}
+
+QNonContiguousByteDevice::~QNonContiguousByteDevice()
+{
+}
+
+void QNonContiguousByteDevice::disableReset()
+{
+ resetDisabled = true;
+}
+
+QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b) : QNonContiguousByteDevice()
+{
+ buffer = b;
+ byteArray = QByteArray::fromRawData(buffer->buffer().constData() + buffer->pos(), buffer->size() - buffer->pos());
+ arrayImpl = new QNonContiguousByteDeviceByteArrayImpl(&byteArray);
+ arrayImpl->setParent(this);
+ connect(arrayImpl, SIGNAL(readyRead()), SIGNAL(readyRead()));
+ connect(arrayImpl, SIGNAL(readProgress(qint64,qint64)), SIGNAL(readProgress(qint64,qint64)));
+}
+
+QNonContiguousByteDeviceBufferImpl::~QNonContiguousByteDeviceBufferImpl()
+{
+}
+
+const char* QNonContiguousByteDeviceBufferImpl::readPointer(qint64 maximumLength, qint64 &len)
+{
+ return arrayImpl->readPointer(maximumLength, len);
+}
+
+bool QNonContiguousByteDeviceBufferImpl::advanceReadPointer(qint64 amount)
+{
+ return arrayImpl->advanceReadPointer(amount);
+}
+
+bool QNonContiguousByteDeviceBufferImpl::atEnd()
+{
+ return arrayImpl->atEnd();
+}
+
+bool QNonContiguousByteDeviceBufferImpl::reset()
+{
+ if (resetDisabled)
+ return false;
+ return arrayImpl->reset();
+}
+
+qint64 QNonContiguousByteDeviceBufferImpl::size()
+{
+ return arrayImpl->size();
+}
+
+QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba) : QNonContiguousByteDevice(), currentPosition(0)
+{
+ byteArray = ba;
+}
+
+QNonContiguousByteDeviceByteArrayImpl::~QNonContiguousByteDeviceByteArrayImpl()
+{
+}
+
+const char* QNonContiguousByteDeviceByteArrayImpl::readPointer(qint64 maximumLength, qint64 &len)
+{
+ if (atEnd()) {
+ len = -1;
+ return 0;
+ }
+
+ if (maximumLength != -1)
+ len = qMin(maximumLength, size() - currentPosition);
+ else
+ len = size() - currentPosition;
+
+ return byteArray->constData() + currentPosition;
+}
+
+bool QNonContiguousByteDeviceByteArrayImpl::advanceReadPointer(qint64 amount)
+{
+ currentPosition += amount;
+ emit readProgress(currentPosition, size());
+ return true;
+}
+
+bool QNonContiguousByteDeviceByteArrayImpl::atEnd()
+{
+ return currentPosition >= size();
+}
+
+bool QNonContiguousByteDeviceByteArrayImpl::reset()
+{
+ if (resetDisabled)
+ return false;
+
+ currentPosition = 0;
+ return true;
+}
+
+qint64 QNonContiguousByteDeviceByteArrayImpl::size()
+{
+ return byteArray->size();
+}
+
+QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb)
+ : QNonContiguousByteDevice(), currentPosition(0)
+{
+ ringBuffer = rb;
+}
+
+QNonContiguousByteDeviceRingBufferImpl::~QNonContiguousByteDeviceRingBufferImpl()
+{
+}
+
+const char* QNonContiguousByteDeviceRingBufferImpl::readPointer(qint64 maximumLength, qint64 &len)
+{
+ if (atEnd()) {
+ len = -1;
+ return 0;
+ }
+
+ const char *returnValue = ringBuffer->readPointerAtPosition(currentPosition, len);
+
+ if (maximumLength != -1)
+ len = qMin(len, maximumLength);
+
+ return returnValue;
+}
+
+bool QNonContiguousByteDeviceRingBufferImpl::advanceReadPointer(qint64 amount)
+{
+ currentPosition += amount;
+ emit readProgress(currentPosition, size());
+ return true;
+}
+
+bool QNonContiguousByteDeviceRingBufferImpl::atEnd()
+{
+ return currentPosition >= size();
+}
+
+bool QNonContiguousByteDeviceRingBufferImpl::reset()
+{
+ if (resetDisabled)
+ return false;
+
+ currentPosition = 0;
+ return true;
+}
+
+qint64 QNonContiguousByteDeviceRingBufferImpl::size()
+{
+ return ringBuffer->size();
+}
+
+QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d)
+ : QNonContiguousByteDevice(),
+ currentReadBuffer(0), currentReadBufferSize(16*1024),
+ currentReadBufferAmount(0), currentReadBufferPosition(0), totalAdvancements(0),
+ eof(false)
+{
+ device = d;
+ initialPosition = d->pos();
+ connect(device, SIGNAL(readyRead()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
+ connect(device, SIGNAL(readChannelFinished()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
+}
+
+QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl()
+{
+ delete currentReadBuffer;
+}
+
+const char* QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLength, qint64 &len)
+{
+ if (eof == true) {
+ len = -1;
+ return 0;
+ }
+
+ if (currentReadBuffer == 0)
+ currentReadBuffer = new QByteArray(currentReadBufferSize, '\0'); // lazy alloc
+
+ if (maximumLength == -1)
+ maximumLength = currentReadBufferSize;
+
+ if (currentReadBufferAmount - currentReadBufferPosition > 0) {
+ len = currentReadBufferAmount - currentReadBufferPosition;
+ return currentReadBuffer->data() + currentReadBufferPosition;
+ }
+
+ qint64 haveRead = device->read(currentReadBuffer->data(), qMin(maximumLength, currentReadBufferSize));
+
+ if ((haveRead == -1) || (haveRead == 0 && device->atEnd() && !device->isSequential())) {
+ eof = true;
+ len = -1;
+ // size was unknown before, emit a readProgress with the final size
+ if (size() == -1)
+ emit readProgress(totalAdvancements, totalAdvancements);
+ return 0;
+ }
+
+ currentReadBufferAmount = haveRead;
+ currentReadBufferPosition = 0;
+
+ len = haveRead;
+ return currentReadBuffer->data();
+}
+
+bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount)
+{
+ totalAdvancements += amount;
+
+ // normal advancement
+ currentReadBufferPosition += amount;
+
+ // advancing over that what has actually been read before
+ if (currentReadBufferPosition > currentReadBufferAmount) {
+ qint64 i = currentReadBufferPosition - currentReadBufferAmount;
+ while (i > 0) {
+ if (device->getChar(0) == false) {
+ emit readProgress(totalAdvancements - i, size());
+ return false; // ### FIXME handle eof
+ }
+ i--;
+ }
+
+ currentReadBufferPosition = 0;
+ currentReadBufferAmount = 0;
+ }
+
+ if (size() == -1)
+ emit readProgress(totalAdvancements, totalAdvancements);
+ else
+ emit readProgress(totalAdvancements, size());
+
+ return true;
+}
+
+bool QNonContiguousByteDeviceIoDeviceImpl::atEnd()
+{
+ return eof == true;
+}
+
+bool QNonContiguousByteDeviceIoDeviceImpl::reset()
+{
+ if (resetDisabled)
+ return false;
+
+ if (device->seek(initialPosition)) {
+ eof = false; // assume eof is false, it will be true after a read has been attempted
+ return true;
+ }
+
+ return false;
+}
+
+qint64 QNonContiguousByteDeviceIoDeviceImpl::size()
+{
+ // note that this is different from the size() implementation of QIODevice!
+
+ if (device->isSequential())
+ return -1;
+
+ return device->size() - initialPosition;
+}
+
+QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0)
+{
+ byteDevice = bd;
+ connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead()));
+
+ open(ReadOnly);
+}
+
+QByteDeviceWrappingIoDevice::~QByteDeviceWrappingIoDevice()
+{
+
+}
+
+bool QByteDeviceWrappingIoDevice::isSequential() const
+{
+ return (byteDevice->size() == -1);
+}
+
+bool QByteDeviceWrappingIoDevice::atEnd() const
+{
+ return byteDevice->atEnd();
+}
+
+bool QByteDeviceWrappingIoDevice::reset()
+{
+ return byteDevice->reset();
+}
+
+qint64 QByteDeviceWrappingIoDevice::size() const
+{
+ if (isSequential())
+ return 0;
+
+ return byteDevice->size();
+}
+
+
+qint64 QByteDeviceWrappingIoDevice::readData( char * data, qint64 maxSize)
+{
+ qint64 len;
+ const char *readPointer = byteDevice->readPointer(maxSize, len);
+ if (len == -1)
+ return -1;
+
+ memcpy(data, readPointer, len);
+ byteDevice->advanceReadPointer(len);
+ return len;
+}
+
+qint64 QByteDeviceWrappingIoDevice::writeData( const char* data, qint64 maxSize)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(maxSize);
+ return -1;
+}
+
+/*!
+ \class QNonContiguousByteDeviceFactory
+ \since 4.6
+
+ \inmodule QtCore
+
+ Creates a QNonContiguousByteDevice out of a QIODevice,
+ QByteArray etc.
+
+ \sa QNonContiguousByteDevice
+
+ \internal
+*/
+
+/*!
+ \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device);
+
+ Create a QNonContiguousByteDevice out of a QIODevice.
+ For QFile, QBuffer and all other QIoDevice, sequential or not.
+
+ \internal
+*/
+QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device)
+{
+ // shortcut if it is a QBuffer
+ if (QBuffer* buffer = qobject_cast<QBuffer*>(device)) {
+ return new QNonContiguousByteDeviceBufferImpl(buffer);
+ }
+
+ // ### FIXME special case if device is a QFile that supports map()
+ // then we can actually deal with the file without using read/peek
+
+ // generic QIODevice
+ return new QNonContiguousByteDeviceIoDeviceImpl(device); // FIXME
+}
+
+/*!
+ \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer);
+
+ Create a QNonContiguousByteDevice out of a QRingBuffer.
+
+ \internal
+*/
+QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer)
+{
+ return new QNonContiguousByteDeviceRingBufferImpl(ringBuffer);
+}
+
+/*!
+ \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray);
+
+ Create a QNonContiguousByteDevice out of a QByteArray.
+
+ \internal
+*/
+QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray)
+{
+ return new QNonContiguousByteDeviceByteArrayImpl(byteArray);
+}
+
+/*!
+ \fn static QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice);
+
+ Wrap the \a byteDevice (possibly again) into a QIODevice.
+
+ \internal
+*/
+QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice)
+{
+ // ### FIXME if it already has been based on QIoDevice, we could that one out again
+ // and save some calling
+
+ // needed for FTP backend
+
+ return new QByteDeviceWrappingIoDevice(byteDevice);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h
new file mode 100644
index 0000000..ecf9b9c
--- /dev/null
+++ b/src/corelib/io/qnoncontiguousbytedevice_p.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNONCONTIGUOUSBYTEDEVICE_H
+#define QNONCONTIGUOUSBYTEDEVICE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qbuffer.h>
+#include <QtCore/qiodevice.h>
+#include "private/qringbuffer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_CORE_EXPORT QNonContiguousByteDevice : public QObject
+{
+ Q_OBJECT
+public:
+ virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0;
+ virtual bool advanceReadPointer(qint64 amount) = 0;
+ virtual bool atEnd() = 0;
+ virtual bool reset() = 0;
+ void disableReset();
+ virtual qint64 size() = 0;
+
+protected:
+ QNonContiguousByteDevice();
+ virtual ~QNonContiguousByteDevice();
+
+ bool resetDisabled;
+Q_SIGNALS:
+ void readyRead();
+ void readProgress(qint64 current, qint64 total);
+};
+
+class Q_CORE_EXPORT QNonContiguousByteDeviceFactory
+{
+public:
+ static QNonContiguousByteDevice* create(QIODevice *device);
+ static QNonContiguousByteDevice* create(QByteArray *byteArray);
+ static QNonContiguousByteDevice* create(QRingBuffer *ringBuffer);
+ static QIODevice* wrap(QNonContiguousByteDevice* byteDevice);
+};
+
+// the actual implementations
+//
+
+class QNonContiguousByteDeviceByteArrayImpl : public QNonContiguousByteDevice
+{
+public:
+ QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba);
+ ~QNonContiguousByteDeviceByteArrayImpl();
+ const char* readPointer(qint64 maximumLength, qint64 &len);
+ bool advanceReadPointer(qint64 amount);
+ bool atEnd();
+ bool reset();
+ qint64 size();
+protected:
+ QByteArray* byteArray;
+ qint64 currentPosition;
+};
+
+class QNonContiguousByteDeviceRingBufferImpl : public QNonContiguousByteDevice
+{
+public:
+ QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb);
+ ~QNonContiguousByteDeviceRingBufferImpl();
+ const char* readPointer(qint64 maximumLength, qint64 &len);
+ bool advanceReadPointer(qint64 amount);
+ bool atEnd();
+ bool reset();
+ qint64 size();
+protected:
+ QRingBuffer* ringBuffer;
+ qint64 currentPosition;
+};
+
+
+class QNonContiguousByteDeviceIoDeviceImpl : public QNonContiguousByteDevice
+{
+public:
+ QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d);
+ ~QNonContiguousByteDeviceIoDeviceImpl();
+ const char* readPointer(qint64 maximumLength, qint64 &len);
+ bool advanceReadPointer(qint64 amount);
+ bool atEnd();
+ bool reset();
+ qint64 size();
+protected:
+ QIODevice* device;
+ QByteArray* currentReadBuffer;
+ qint64 currentReadBufferSize;
+ qint64 currentReadBufferAmount;
+ qint64 currentReadBufferPosition;
+ qint64 totalAdvancements;
+ bool eof;
+ qint64 initialPosition;
+};
+
+class QNonContiguousByteDeviceBufferImpl : public QNonContiguousByteDevice
+{
+public:
+ QNonContiguousByteDeviceBufferImpl(QBuffer *b);
+ ~QNonContiguousByteDeviceBufferImpl();
+ const char* readPointer(qint64 maximumLength, qint64 &len);
+ bool advanceReadPointer(qint64 amount);
+ bool atEnd();
+ bool reset();
+ qint64 size();
+protected:
+ QBuffer* buffer;
+ QByteArray byteArray;
+ QNonContiguousByteDeviceByteArrayImpl* arrayImpl;
+};
+
+// ... and the reverse thing
+class QByteDeviceWrappingIoDevice : public QIODevice
+{
+public:
+ QByteDeviceWrappingIoDevice (QNonContiguousByteDevice *bd);
+ ~QByteDeviceWrappingIoDevice ();
+ virtual bool isSequential () const;
+ virtual bool atEnd () const;
+ virtual bool reset ();
+ virtual qint64 size () const;
+protected:
+ virtual qint64 readData ( char * data, qint64 maxSize );
+ virtual qint64 writeData ( const char * data, qint64 maxSize );
+
+ QNonContiguousByteDevice *byteDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index 9425132..f7049d3 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -101,6 +101,296 @@ QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
+/*!
+ \class QProcessEnvironment
+
+ \brief The QProcessEnvironment class holds the environment variables that
+ can be passed to a program.
+
+ \ingroup io
+ \ingroup misc
+ \mainclass
+ \reentrant
+ \since 4.6
+
+ A process's environment is composed of a set of key=value pairs known as
+ environment variables. The QProcessEnvironment class wraps that concept
+ and allows easy manipulation of those variables. It's meant to be used
+ along with QProcess, to set the environment for child processes. It
+ cannot be used to change the current process's environment.
+
+ The environment of the calling process can be obtained using
+ QProcessEnvironment::systemEnvironment().
+
+ On Unix systems, the variable names are case-sensitive. For that reason,
+ this class will not touch the names of the variables. Note as well that
+ Unix environment allows both variable names and contents to contain arbitrary
+ binary data (except for the NUL character), but this is not supported by
+ QProcessEnvironment. This class only supports names and values that are
+ encodable by the current locale settings (see QTextCodec::codecForLocale).
+
+ On Windows, the variable names are case-insensitive. Therefore,
+ QProcessEnvironment will always uppercase the names and do case-insensitive
+ comparisons.
+
+ On Windows CE, the concept of environment does not exist. This class will
+ keep the values set for compatibility with other platforms, but the values
+ set will have no effect on the processes being created.
+
+ \sa QProcess, QProcess::systemEnvironment(), QProcess::setProcessEnvironment()
+*/
+#ifdef Q_OS_WIN
+static inline QProcessEnvironmentPrivate::Unit prepareName(const QString &name)
+{ return name.toUpper(); }
+static inline QProcessEnvironmentPrivate::Unit prepareName(const QByteArray &name)
+{ return QString::fromLocal8Bit(name).toUpper(); }
+static inline QString nameToString(const QProcessEnvironmentPrivate::Unit &name)
+{ return name; }
+static inline QProcessEnvironmentPrivate::Unit prepareValue(const QString &value)
+{ return value; }
+static inline QProcessEnvironmentPrivate::Unit prepareValue(const QByteArray &value)
+{ return QString::fromLocal8Bit(value); }
+static inline QString valueToString(const QProcessEnvironmentPrivate::Unit &value)
+{ return value; }
+static inline QByteArray valueToByteArray(const QProcessEnvironmentPrivate::Unit &value)
+{ return value.toLocal8Bit(); }
+#else
+static inline QProcessEnvironmentPrivate::Unit prepareName(const QByteArray &name)
+{ return name; }
+static inline QProcessEnvironmentPrivate::Unit prepareName(const QString &name)
+{ return name.toLocal8Bit(); }
+static inline QString nameToString(const QProcessEnvironmentPrivate::Unit &name)
+{ return QString::fromLocal8Bit(name); }
+static inline QProcessEnvironmentPrivate::Unit prepareValue(const QByteArray &value)
+{ return value; }
+static inline QProcessEnvironmentPrivate::Unit prepareValue(const QString &value)
+{ return value.toLocal8Bit(); }
+static inline QString valueToString(const QProcessEnvironmentPrivate::Unit &value)
+{ return QString::fromLocal8Bit(value); }
+static inline QByteArray valueToByteArray(const QProcessEnvironmentPrivate::Unit &value)
+{ return value; }
+#endif
+
+template<> void QSharedDataPointer<QProcessEnvironmentPrivate>::detach()
+{
+ if (d && d->ref == 1)
+ return;
+ QProcessEnvironmentPrivate *x = (d ? new QProcessEnvironmentPrivate(*d)
+ : new QProcessEnvironmentPrivate);
+ x->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = x;
+}
+
+QStringList QProcessEnvironmentPrivate::toList() const
+{
+ QStringList result;
+ QHash<Unit, Unit>::ConstIterator it = hash.constBegin(),
+ end = hash.constEnd();
+ for ( ; it != end; ++it) {
+ QString data = nameToString(it.key());
+ QString value = valueToString(it.value());
+ data.reserve(data.length() + value.length() + 1);
+ data.append(QLatin1Char('='));
+ data.append(value);
+ result << data;
+ }
+ return result;
+}
+
+QProcessEnvironment QProcessEnvironmentPrivate::fromList(const QStringList &list)
+{
+ QProcessEnvironment env;
+ QStringList::ConstIterator it = list.constBegin(),
+ end = list.constEnd();
+ for ( ; it != end; ++it) {
+ int pos = it->indexOf(QLatin1Char('='));
+ if (pos < 1)
+ continue;
+
+ QString value = it->mid(pos + 1);
+ QString name = *it;
+ name.truncate(pos);
+ env.insert(name, value);
+ }
+ return env;
+}
+
+/*!
+ Creates a new QProcessEnvironment object. This constructor creates an
+ empty environment. If set on a QProcess, this will cause the current
+ environment variables to be removed.
+*/
+QProcessEnvironment::QProcessEnvironment()
+ : d(0)
+{
+}
+
+/*!
+ Frees the resources associated with this QProcessEnvironment object.
+*/
+QProcessEnvironment::~QProcessEnvironment()
+{
+}
+
+/*!
+ Creates a QProcessEnvironment object that is a copy of \a other.
+*/
+QProcessEnvironment::QProcessEnvironment(const QProcessEnvironment &other)
+ : d(other.d)
+{
+}
+
+/*!
+ Copies the contents of the \a other QProcessEnvironment object into this
+ one.
+*/
+QProcessEnvironment &QProcessEnvironment::operator=(const QProcessEnvironment &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ \fn bool QProcessEnvironment::operator !=(const QProcessEnvironment &other) const
+
+ Returns true if this and the \a other QProcessEnvironment objects are different.
+
+ \sa operator==()
+*/
+
+/*!
+ Returns true if this and the \a other QProcessEnvironment objects are equal.
+
+ Two QProcessEnvironment objects are considered equal if they have the same
+ set of key=value pairs. The comparison of keys is done case-sensitive on
+ platforms where the environment is case-sensitive.
+
+ \sa operator!=(), contains()
+*/
+bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const
+{
+ return d->hash == other.d->hash;
+}
+
+/*!
+ Returns true if this QProcessEnvironment object is empty: that is
+ there are no key=value pairs set.
+
+ \sa clear(), systemEnvironment(), insert()
+*/
+bool QProcessEnvironment::isEmpty() const
+{
+ return d ? d->hash.isEmpty() : true;
+}
+
+/*!
+ Removes all key=value pairs from this QProcessEnvironment object, making
+ it empty.
+
+ \sa isEmpty(), systemEnvironment()
+*/
+void QProcessEnvironment::clear()
+{
+ if (d)
+ d->hash.clear();
+}
+
+/*!
+ Returns true if the environment variable of name \a name is found in
+ this QProcessEnvironment object.
+
+ On Windows, variable names are case-insensitive, so the key is converted
+ to uppercase before searching. On other systems, names are case-sensitive
+ so no trasformation is applied.
+
+ \sa insert(), value()
+*/
+bool QProcessEnvironment::contains(const QString &name) const
+{
+ return d ? d->hash.contains(prepareName(name)) : false;
+}
+
+/*!
+ Inserts the environment variable of name \a name and contents \a value
+ into this QProcessEnvironment object. If that variable already existed,
+ it is replaced by the new value.
+
+ On Windows, variable names are case-insensitive, so this function always
+ uppercases the variable name before inserting. On other systems, names
+ are case-sensitive, so no transformation is applied.
+
+ On most systems, inserting a variable with no contents will have the
+ same effect for applications as if the variable had not been set at all.
+ However, to guarantee that there are no incompatibilities, to remove a
+ variable, please use the remove() function.
+
+ \sa contains(), remove(), value()
+*/
+void QProcessEnvironment::insert(const QString &name, const QString &value)
+{
+ d->hash.insert(prepareName(name), prepareValue(value));
+}
+
+/*!
+ Removes the environment variable identified by \a name from this
+ QProcessEnvironment object. If that variable did not exist before,
+ nothing happens.
+
+ On Windows, variable names are case-insensitive, so the key is converted
+ to uppercase before searching. On other systems, names are case-sensitive
+ so no trasformation is applied.
+
+ \sa contains(), insert(), value()
+*/
+void QProcessEnvironment::remove(const QString &name)
+{
+ if (d)
+ d->hash.remove(prepareName(name));
+}
+
+/*!
+ Searches this QProcessEnvironment object for a variable identified by
+ \a name and returns its value. If the variable is not found in this object,
+ then \a defaultValue is returned instead.
+
+ On Windows, variable names are case-insensitive, so the key is converted
+ to uppercase before searching. On other systems, names are case-sensitive
+ so no trasformation is applied.
+
+ \sa contains(), insert(), remove()
+*/
+QString QProcessEnvironment::value(const QString &name, const QString &defaultValue) const
+{
+ if (!d)
+ return defaultValue;
+
+ QProcessEnvironmentPrivate::Hash::ConstIterator it = d->hash.constFind(prepareName(name));
+ if (it == d->hash.constEnd())
+ return defaultValue;
+
+ return valueToString(it.value());
+}
+
+/*!
+ Converts this QProcessEnvironment object into a list of strings, one for
+ each environment variable that is set. The environment variable's name
+ and its value are separated by an equal character ('=').
+
+ The QStringList contents returned by this function are suitable for use
+ with the QProcess::setEnvironment function. However, it is recommended
+ to use QProcess::setProcessEnvironment instead since that will avoid
+ unnecessary copying of the data.
+
+ \sa systemEnvironment(), QProcess::systemEnvironment(), QProcess::environment(),
+ QProcess::setEnvironment()
+*/
+QStringList QProcessEnvironment::toStringList() const
+{
+ return d ? d->toList() : QStringList();
+}
+
void QProcessPrivate::Channel::clear()
{
switch (type) {
@@ -128,12 +418,19 @@ void QProcessPrivate::Channel::clear()
to communicate with them.
\ingroup io
- \ingroup misc
- \mainclass
+
\reentrant
+ \section1 Running a Process
+
To start a process, pass the name and command line arguments of
- the program you want to run as arguments to start(). For example:
+ the program you want to run as arguments to start(). Arguments
+ are supplied as individual strings in a QStringList.
+
+ For example, the following code snippet runs the analog clock
+ example in the Motif style on X11 platforms by passing strings
+ containing "-style" and "motif" as two items in the list of
+ arguments:
\snippet doc/src/snippets/qprocess/qprocess-simpleexecution.cpp 0
\dots
@@ -153,7 +450,8 @@ void QProcessPrivate::Channel::clear()
used as an input source for QXmlReader, or for generating data to
be uploaded using QFtp.
- \note On Windows CE, reading and writing to a process is not supported.
+ \note On Windows CE and Symbian, reading and writing to a process
+ is not supported.
When the process exits, QProcess reenters the \l NotRunning state
(the initial state), and emits finished().
@@ -203,6 +501,10 @@ void QProcessPrivate::Channel::clear()
setWorkingDirectory(). By default, processes are run in the
current working directory of the calling process.
+ \note On Symbian, setting environment or working directory
+ is not supported. The working directory will always be the private
+ directory of the running process.
+
\section1 Synchronous Process API
QProcess provides a set of functions which allow it to be used
@@ -230,7 +532,7 @@ void QProcessPrivate::Channel::clear()
\snippet doc/src/snippets/process/process.cpp 0
- \section1 Notes for Windows Users
+ \section1 Notes for Windows Users
Some Windows commands (for example, \c dir) are not provided by
separate applications, but by the command interpreter itself.
@@ -282,7 +584,7 @@ void QProcessPrivate::Channel::clear()
writes to its standard output and standard error will be written
to the standard output and standard error of the main process.
- \sa setReadChannelMode()
+ \sa setProcessChannelMode()
*/
/*!
@@ -436,6 +738,10 @@ QProcessPrivate::QProcessPrivate()
#ifdef Q_OS_UNIX
serial = 0;
#endif
+#ifdef Q_OS_SYMBIAN
+ symbianProcess = NULL;
+ processLaunched = false;
+#endif
}
/*! \internal
@@ -508,6 +814,13 @@ void QProcessPrivate::cleanup()
#ifdef Q_OS_UNIX
serial = 0;
#endif
+#ifdef Q_OS_SYMBIAN
+ if (symbianProcess) {
+ symbianProcess->Close();
+ delete symbianProcess;
+ symbianProcess = NULL;
+ }
+#endif
}
/*! \internal
@@ -765,7 +1078,7 @@ void QProcessPrivate::closeWriteChannel()
if (stdinChannel.notifier) {
qDeleteInEventHandler(stdinChannel.notifier);
stdinChannel.notifier = 0;
- }
+ }
}
#ifdef Q_OS_WIN
// ### Find a better fix, feeding the process little by little
@@ -837,7 +1150,7 @@ void QProcess::setReadChannelMode(ProcessChannelMode mode)
Returns the channel mode of the QProcess standard output and
standard error channels.
- \sa setReadChannelMode(), ProcessChannelMode, setReadChannel()
+ \sa setProcessChannelMode(), ProcessChannelMode, setReadChannel()
*/
QProcess::ProcessChannelMode QProcess::processChannelMode() const
{
@@ -854,7 +1167,7 @@ QProcess::ProcessChannelMode QProcess::processChannelMode() const
\snippet doc/src/snippets/code/src_corelib_io_qprocess.cpp 0
- \sa readChannelMode(), ProcessChannelMode, setReadChannel()
+ \sa processChannelMode(), ProcessChannelMode, setReadChannel()
*/
void QProcess::setProcessChannelMode(ProcessChannelMode mode)
{
@@ -1064,6 +1377,10 @@ QString QProcess::workingDirectory() const
process in this directory. The default behavior is to start the
process in the working directory of the calling process.
+ \note The working directory setting is ignored on Symbian;
+ the private directory of the process is considered its working
+ directory.
+
\sa workingDirectory(), start()
*/
void QProcess::setWorkingDirectory(const QString &dir)
@@ -1183,6 +1500,7 @@ QProcess::ProcessState QProcess::state() const
}
/*!
+ \deprecated
Sets the environment that QProcess will use when starting a process to the
\a environment specified which consists of a list of key=value pairs.
@@ -1191,26 +1509,67 @@ QProcess::ProcessState QProcess::state() const
\snippet doc/src/snippets/qprocess-environment/main.cpp 0
- \sa environment(), systemEnvironment()
+ \note This function is less efficient than the setProcessEnvironment()
+ function.
+
+ \sa environment(), setProcessEnvironment(), systemEnvironment()
*/
void QProcess::setEnvironment(const QStringList &environment)
{
+ setProcessEnvironment(QProcessEnvironmentPrivate::fromList(environment));
+}
+
+/*!
+ \deprecated
+ Returns the environment that QProcess will use when starting a
+ process, or an empty QStringList if no environment has been set
+ using setEnvironment() or setEnvironmentHash(). If no environment
+ has been set, the environment of the calling process will be used.
+
+ \note The environment settings are ignored on Windows CE and Symbian,
+ as there is no concept of an environment.
+
+ \sa processEnvironment(), setEnvironment(), systemEnvironment()
+*/
+QStringList QProcess::environment() const
+{
+ Q_D(const QProcess);
+ return d->environment.toStringList();
+}
+
+/*!
+ \since 4.6
+ Sets the environment that QProcess will use when starting a process to the
+ \a environment object.
+
+ For example, the following code adds the \c{C:\\BIN} directory to the list of
+ executable paths (\c{PATHS}) on Windows and sets \c{TMPDIR}:
+
+ \snippet doc/src/snippets/qprocess-environment/main.cpp 1
+
+ Note how, on Windows, environment variable names are case-insensitive.
+
+ \sa processEnvironment(), QProcessEnvironment::systemEnvironment(), setEnvironment()
+*/
+void QProcess::setProcessEnvironment(const QProcessEnvironment &environment)
+{
Q_D(QProcess);
d->environment = environment;
}
/*!
+ \since 4.6
Returns the environment that QProcess will use when starting a
- process, or an empty QStringList if no environment has been set
- using setEnvironment(). If no environment has been set, the
- environment of the calling process will be used.
+ process, or an empty object if no environment has been set using
+ setEnvironment() or setProcessEnvironment(). If no environment has
+ been set, the environment of the calling process will be used.
\note The environment settings are ignored on Windows CE,
as there is no concept of an environment.
- \sa setEnvironment(), systemEnvironment()
+ \sa setProcessEnvironment(), setEnvironment(), QProcessEnvironment::isValid()
*/
-QStringList QProcess::environment() const
+QProcessEnvironment QProcess::processEnvironment() const
{
Q_D(const QProcess);
return d->environment;
@@ -1287,7 +1646,8 @@ bool QProcess::waitForBytesWritten(int msecs)
has been emitted, or until \a msecs milliseconds have passed.
Returns true if the process finished; otherwise returns false (if
- the operation timed out or if an error occurred).
+ the operation timed out, if an error occurred, or if this QProcess
+ is already finished).
This function can operate without an event loop. It is
useful when writing non-GUI applications and when performing
@@ -1486,16 +1846,16 @@ QByteArray QProcess::readAllStandardError()
process, a warning may be printed at the console, and the existing
process will continue running.
- Note that arguments that contain spaces are not passed to the
+ \note Arguments that contain spaces are not passed to the
process as separate arguments.
- \bold{Windows:} Arguments that contain spaces are wrapped in quotes.
-
\note Processes are started asynchronously, which means the started()
and error() signals may be delayed. Call waitForStarted() to make
sure the process has started (or has failed to start) and those signals
have been emitted.
+ \bold{Windows:} Arguments that contain spaces are wrapped in quotes.
+
\sa pid(), started(), waitForStarted()
*/
void QProcess::start(const QString &program, const QStringList &arguments, OpenMode mode)
@@ -1507,7 +1867,7 @@ void QProcess::start(const QString &program, const QStringList &arguments, OpenM
}
#if defined QPROCESS_DEBUG
- qDebug() << "QProcess::start(" << program << "," << arguments << "," << mode << ")";
+ qDebug() << "QProcess::start(" << program << ',' << arguments << ',' << mode << ')';
#endif
d->outputReadBuffer.clear();
@@ -1636,6 +1996,9 @@ void QProcess::start(const QString &program, OpenMode mode)
event loop does not handle the WM_CLOSE message, can only be terminated by
calling kill().
+ \note Terminating running processes from other processes will typically
+ cause a panic in Symbian due to platform security.
+
\sa kill()
*/
void QProcess::terminate()
@@ -1755,7 +2118,7 @@ bool QProcess::startDetached(const QString &program,
otherwise returns false. If the calling process exits, the
detached process will continue to live.
- Note that arguments that contain spaces are not passed to the
+ \note Arguments that contain spaces are not passed to the
process as separate arguments.
\bold{Unix:} The started process will run in its own session and act
@@ -1796,9 +2159,9 @@ QT_BEGIN_INCLUDE_NAMESPACE
#ifdef Q_OS_MAC
# include <crt_externs.h>
# define environ (*_NSGetEnviron())
-#elif defined(Q_OS_WINCE)
- static char *qt_wince_environ[] = { 0 };
-#define environ qt_wince_environ
+#elif defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ static char *qt_empty_environ[] = { 0 };
+#define environ qt_empty_environ
#elif !defined(Q_OS_WIN)
extern char **environ;
#endif
@@ -1812,7 +2175,16 @@ QT_END_INCLUDE_NAMESPACE
\snippet doc/src/snippets/code/src_corelib_io_qprocess.cpp 8
- \sa environment(), setEnvironment()
+ This function does not cache the system environment. Therefore, it's
+ possible to obtain an updated version of the environment if low-level C
+ library functions like \tt setenv ot \tt putenv have been called.
+
+ However, note that repeated calls to this function will recreate the
+ list of environment variables, which is a non-trivial operation.
+
+ \note For new code, it is recommended to use QProcessEvironment::systemEnvironment()
+
+ \sa QProcessEnvironment::systemEnvironment(), environment(), setEnvironment()
*/
QStringList QProcess::systemEnvironment()
{
@@ -1825,6 +2197,36 @@ QStringList QProcess::systemEnvironment()
}
/*!
+ \since 4.6
+
+ Returns the environment of the calling process as a QProcessEnvironment.
+
+ This function does not cache the system environment. Therefore, it's
+ possible to obtain an updated version of the environment if low-level C
+ library functions like \tt setenv ot \tt putenv have been called.
+
+ However, note that repeated calls to this function will recreate the
+ QProcessEnvironment object, which is a non-trivial operation.
+
+ \sa QProcess::systemEnvironment()
+*/
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
+{
+ QProcessEnvironment env;
+ const char *entry;
+ for (int count = 0; (entry = environ[count]); ++count) {
+ const char *equal = strchr(entry, '=');
+ if (!equal)
+ continue;
+
+ QByteArray name(entry, equal - entry);
+ QByteArray value(equal + 1);
+ env.insert(QString::fromLocal8Bit(name), QString::fromLocal8Bit(value));
+ }
+ return env;
+}
+
+/*!
\typedef Q_PID
\relates QProcess
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 00da7c3..bfa5c30 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -44,6 +44,7 @@
#include <QtCore/qiodevice.h>
#include <QtCore/qstringlist.h>
+#include <QtCore/qshareddata.h>
QT_BEGIN_HEADER
@@ -53,8 +54,13 @@ QT_MODULE(Core)
#ifndef QT_NO_PROCESS
-#if (!defined(Q_OS_WIN32) && !defined(Q_OS_WINCE)) || defined(qdoc)
+#if (!defined(Q_OS_WIN32) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)) || defined(qdoc)
typedef qint64 Q_PID;
+#elif defined(Q_OS_SYMBIAN)
+QT_END_NAMESPACE
+# include <e32std.h>
+QT_BEGIN_NAMESPACE
+typedef TProcessId Q_PID;
#else
QT_END_NAMESPACE
typedef struct _PROCESS_INFORMATION *Q_PID;
@@ -62,6 +68,37 @@ QT_BEGIN_NAMESPACE
#endif
class QProcessPrivate;
+class QProcessEnvironmentPrivate;
+
+class Q_CORE_EXPORT QProcessEnvironment
+{
+public:
+ QProcessEnvironment();
+ QProcessEnvironment(const QProcessEnvironment &other);
+ ~QProcessEnvironment();
+ QProcessEnvironment &operator=(const QProcessEnvironment &other);
+
+ bool operator==(const QProcessEnvironment &other) const;
+ inline bool operator!=(const QProcessEnvironment &other) const
+ { return !(*this == other); }
+
+ bool isEmpty() const;
+ void clear();
+
+ bool contains(const QString &name) const;
+ void insert(const QString &name, const QString &value);
+ void remove(const QString &name);
+ QString value(const QString &name, const QString &defaultValue = QString()) const;
+
+ QStringList toStringList() const;
+
+ static QProcessEnvironment systemEnvironment();
+
+private:
+ friend class QProcessPrivate;
+ friend class QProcessEnvironmentPrivate;
+ QSharedDataPointer<QProcessEnvironmentPrivate> d;
+};
class Q_CORE_EXPORT QProcess : public QIODevice
{
@@ -121,6 +158,8 @@ public:
void setEnvironment(const QStringList &environment);
QStringList environment() const;
+ void setProcessEnvironment(const QProcessEnvironment &environment);
+ QProcessEnvironment processEnvironment() const;
QProcess::ProcessError error() const;
QProcess::ProcessState state() const;
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index d9c6369..40278a1 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -55,6 +55,8 @@
#include "QtCore/qprocess.h"
#include "QtCore/qstringlist.h"
+#include "QtCore/qhash.h"
+#include "QtCore/qshareddata.h"
#include "private/qringbuffer_p.h"
#include "private/qiodevice_p.h"
@@ -76,6 +78,21 @@ class QWindowsPipeWriter;
class QWinEventNotifier;
class QTimer;
+class QProcessEnvironmentPrivate: public QSharedData
+{
+public:
+#ifdef Q_OS_WIN
+ typedef QString Unit;
+#else
+ typedef QByteArray Unit;
+#endif
+ typedef QHash<Unit, Unit> Hash;
+ Hash hash;
+
+ static QProcessEnvironment fromList(const QStringList &list);
+ QStringList toList() const;
+};
+
class QProcessPrivate : public QIODevicePrivate
{
public:
@@ -161,7 +178,7 @@ public:
QString program;
QStringList arguments;
- QStringList environment;
+ QProcessEnvironment environment;
QRingBuffer outputReadBuffer;
QRingBuffer errorReadBuffer;
@@ -180,7 +197,7 @@ public:
QWinEventNotifier *processFinishedNotifier;
void startProcess();
-#ifdef Q_OS_UNIX
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
void execChild(const char *workingDirectory, char **path, char **argv, char **envp);
#endif
bool processStarted();
@@ -221,6 +238,11 @@ public:
#ifdef Q_OS_UNIX
static void initializeProcessManager();
#endif
+
+#ifdef Q_OS_SYMBIAN
+ bool processLaunched;
+ RProcess* symbianProcess;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess_symbian.cpp b/src/corelib/io/qprocess_symbian.cpp
new file mode 100644
index 0000000..5b00ed0
--- /dev/null
+++ b/src/corelib/io/qprocess_symbian.cpp
@@ -0,0 +1,1043 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QPROCESS_DEBUG
+
+#ifdef QPROCESS_DEBUG
+#include "qdebug.h"
+#define QPROCESS_DEBUG_PRINT(args...) qDebug(args);
+#else
+#define QPROCESS_DEBUG_PRINT(args...)
+#endif
+
+#ifndef QT_NO_PROCESS
+
+#define QPROCESS_ASSERT(check, panicReason, args...) \
+ if (!(check)) { \
+ qWarning(args); \
+ User::Panic(KQProcessPanic, panicReason); \
+ }
+
+#include <exception>
+#include <e32base.h>
+#include <e32std.h>
+#include <stdio.h>
+#include "qplatformdefs.h"
+
+#include "qstring.h"
+#include "qprocess.h"
+#include "qprocess_p.h"
+#include "qeventdispatcher_symbian_p.h"
+
+#include <private/qthread_p.h>
+#include <qmutex.h>
+#include <qmap.h>
+#include <qsocketnotifier.h>
+
+#include <errno.h>
+
+
+QT_BEGIN_NAMESPACE
+
+_LIT(KQProcessManagerThreadName, "QProcManThread");
+_LIT(KQProcessPanic, "QPROCESS");
+enum TQProcessPanic {
+ EProcessManagerMediatorRunError = 1,
+ EProcessManagerMediatorInactive = 2,
+ EProcessManagerMediatorNotPending = 3,
+ EProcessManagerMediatorInvalidCmd = 4,
+ EProcessManagerMediatorCreationFailed = 5,
+ EProcessManagerMediatorThreadOpenFailed = 6,
+ EProcessManagerMediatorNullObserver = 7,
+ EProcessActiveRunError = 10,
+ EProcessActiveNullParameter = 11,
+ EProcessManagerMutexCreationFail = 20,
+ EProcessManagerThreadCreationFail = 21,
+ EProcessManagerSchedulerCreationFail = 22,
+ EProcessManagerNullParam = 23
+};
+
+// Forward declarations
+class QProcessManager;
+
+
+// Active object to listen for child process death
+class QProcessActive : public CActive
+{
+public:
+ static QProcessActive *construct(QProcess *process,
+ RProcess **proc,
+ int serial,
+ int deathPipe);
+
+ virtual ~QProcessActive();
+
+ void start();
+ void stop();
+
+ bool error();
+
+protected:
+
+ // Inherited from CActive
+ void RunL();
+ TInt RunError(TInt aError);
+ void DoCancel();
+
+ QProcessActive();
+
+private:
+
+ QProcess *process;
+ RProcess **pproc;
+ int serial;
+ int deathPipe;
+ bool errorValue;
+};
+
+// Active object to communicate synchronously with process manager thread
+class QProcessManagerMediator : public CActive
+{
+public:
+ static QProcessManagerMediator *construct();
+
+ virtual ~QProcessManagerMediator();
+
+ bool add(QProcessActive *processObserver);
+ void remove(QProcessActive *processObserver);
+ void terminate();
+
+protected:
+
+ enum Commands {
+ ENoCommand,
+ EAdd,
+ ERemove,
+ ETerminate
+ };
+
+ // Inherited from CActive
+ void RunL();
+ TInt RunError(TInt aError);
+ void DoCancel();
+
+ QProcessManagerMediator();
+
+ bool notify(QProcessActive *processObserver, Commands command);
+
+private:
+ QProcessActive *currentObserver;
+ Commands currentCommand;
+
+ RThread processManagerThread;
+};
+
+// Process manager manages child process death listeners.
+//
+// Note: Because QProcess can be used outside event loop, we cannot be guaranteed
+// an active scheduler exists for us to add our process death listener objects.
+// We can't just install active scheduler on the calling thread, as that would block it
+// if we want to actually use it, so a separate manager thread is required.
+class QProcessManager
+{
+public:
+ QProcessManager();
+ ~QProcessManager();
+
+ void startThread();
+
+ TInt run(void *param);
+ bool add(QProcess *process);
+ void remove(QProcess *process);
+
+ inline void setMediator(QProcessManagerMediator *newMediator) {
+ mediator = newMediator;
+ };
+
+private:
+ inline void lock() {
+ managerMutex.Wait();
+ };
+ inline void unlock() {
+ managerMutex.Signal();
+ };
+
+ QMap<int, QProcessActive *> children;
+ QProcessManagerMediator *mediator;
+ RMutex managerMutex;
+ bool threadStarted;
+ RThread managerThread;
+};
+
+static bool qt_rprocess_running(RProcess *proc)
+{
+ if (proc && proc->Handle()) {
+ TExitType et = proc->ExitType();
+ if (et == EExitPending)
+ return true;
+ }
+
+ return false;
+}
+
+static void qt_create_symbian_commandline(const QStringList &arguments, QString &commandLine)
+{
+ for (int i = 0; i < arguments.size(); ++i) {
+ QString tmp = arguments.at(i);
+ // in the case of \" already being in the string the \ must also be escaped
+ tmp.replace(QLatin1String("\\\""), QLatin1String("\\\\\""));
+ // escape a single " because the arguments will be parsed
+ tmp.replace(QLatin1String("\""), QLatin1String("\\\""));
+ if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
+ // The argument must not end with a \ since this would be interpreted
+ // as escaping the quote -- rather put the \ behind the quote: e.g.
+ // rather use "foo"\ than "foo\"
+ QString endQuote(QLatin1String("\""));
+ int i = tmp.length();
+ while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\')) {
+ --i;
+ endQuote += QLatin1String("\\");
+ }
+ commandLine += QLatin1String(" \"") + tmp.left(i) + endQuote;
+ } else {
+ commandLine += QLatin1Char(' ') + tmp;
+ }
+ }
+}
+
+static TInt qt_create_symbian_process(RProcess **proc, const QString &programName, const QStringList &arguments)
+{
+ RProcess *newProc = NULL;
+ newProc = new RProcess();
+
+ if (!newProc)
+ return KErrNoMemory;
+
+ QString commandLine;
+ qt_create_symbian_commandline(arguments, commandLine);
+
+ TPtrC program_ptr(reinterpret_cast<const TText*>(programName.constData()));
+ TPtrC cmdline_ptr(reinterpret_cast<const TText*>(commandLine.constData()));
+
+ TInt err = newProc->Create(program_ptr, cmdline_ptr);
+
+ if (err == KErrNotFound) {
+ // Strip path from program name and try again (i.e. try from default location "\sys\bin")
+ int index = programName.lastIndexOf(QChar('\\'));
+ int index2 = programName.lastIndexOf(QChar('/'));
+ index = qMax(index, index2);
+
+ if (index != -1 && programName.length() >= index) {
+ QString strippedName;
+ strippedName = programName.mid(index + 1);
+ QPROCESS_DEBUG_PRINT("qt_create_symbian_process() Executable '%s' not found, trying stripped version '%s'",
+ qPrintable(programName), qPrintable(strippedName));
+
+ TPtrC stripped_ptr(reinterpret_cast<const TText*>(strippedName.constData()));
+ err = newProc->Create(stripped_ptr, cmdline_ptr);
+
+ if (err != KErrNone) {
+ QPROCESS_DEBUG_PRINT("qt_create_symbian_process() Unable to create process '%s': %d",
+ qPrintable(strippedName), err);
+ }
+ }
+ }
+
+ if (err == KErrNone)
+ *proc = newProc;
+ else
+ delete newProc;
+
+ return err;
+}
+
+static qint64 qt_native_read(int fd, char *data, qint64 maxlen)
+{
+ qint64 ret = 0;
+ do {
+ ret = ::read(fd, data, maxlen);
+ } while (ret == -1 && errno == EINTR);
+
+ QPROCESS_DEBUG_PRINT("qt_native_read(): fd: %d, result: %d, errno = %d", fd, (int)ret, errno);
+
+ return ret;
+}
+
+static qint64 qt_native_write(int fd, const char *data, qint64 len)
+{
+ qint64 ret = 0;
+ do {
+ ret = ::write(fd, data, len);
+ } while (ret == -1 && errno == EINTR);
+
+ QPROCESS_DEBUG_PRINT("qt_native_write(): fd: %d, result: %d, errno = %d", fd, (int)ret, errno);
+
+ return ret;
+}
+
+static void qt_native_close(int fd)
+{
+ int ret;
+ do {
+ ret = ::close(fd);
+ } while (ret == -1 && errno == EINTR);
+}
+
+static void qt_create_pipe(int *pipe)
+{
+ if (pipe[0] != -1)
+ qt_native_close(pipe[0]);
+ if (pipe[1] != -1)
+ qt_native_close(pipe[1]);
+ if (::pipe(pipe) != 0) {
+ qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s",
+ pipe, qPrintable(qt_error_string(errno)));
+ } else {
+ QPROCESS_DEBUG_PRINT("qt_create_pipe(): Created pipe %d - %d", pipe[0], pipe[1]);
+ }
+}
+
+// Called from ProcessManagerThread
+QProcessActive *QProcessActive::construct(QProcess *process,
+ RProcess **proc,
+ int serial,
+ int deathPipe)
+{
+ QPROCESS_ASSERT((process || proc || *proc),
+ EProcessActiveNullParameter,
+ "QProcessActive::construct(): process (0x%x), proc (0x%x) or *proc == NULL, not creating an instance", process, proc)
+
+ QProcessActive *newInstance = new QProcessActive();
+
+ if (!newInstance) {
+ QPROCESS_DEBUG_PRINT("QProcessActive::construct(): Failed to create new instance");
+ } else {
+ newInstance->process = process;
+ newInstance->pproc = proc;
+ newInstance->serial = serial;
+ newInstance->deathPipe = deathPipe;
+ newInstance->errorValue = false;
+ }
+
+ return newInstance;
+}
+
+// Called from ProcessManagerThread
+QProcessActive::QProcessActive()
+ : CActive(CActive::EPriorityStandard)
+{
+ // Nothing to do
+}
+
+// Called from ProcessManagerThread
+QProcessActive::~QProcessActive()
+{
+ process = NULL;
+ pproc = NULL;
+}
+
+// Called from ProcessManagerThread
+void QProcessActive::start()
+{
+ if (qt_rprocess_running(*pproc)) {
+ CActiveScheduler::Add(this);
+ (*pproc)->Logon(iStatus);
+ SetActive();
+ QPROCESS_DEBUG_PRINT("QProcessActive::start(): Started monitoring for process exit.");
+ } else {
+ QPROCESS_DEBUG_PRINT("QProcessActive::start(): Process doesn't exist or is already dead");
+ // Assume process has already died
+ qt_native_write(deathPipe, "", 1);
+ errorValue = true;
+ }
+}
+
+// Called from ProcessManagerThread
+void QProcessActive::stop()
+{
+ QPROCESS_DEBUG_PRINT("QProcessActive::stop()");
+
+ // Remove this from scheduler (also cancels the request)
+ Deque();
+}
+
+bool QProcessActive::error()
+{
+ return errorValue;
+}
+
+// Called from ProcessManagerThread
+void QProcessActive::RunL()
+{
+ // If this method gets executed, the monitored process has died
+
+ // Notify main thread
+ qt_native_write(deathPipe, "", 1);
+ QPROCESS_DEBUG_PRINT("QProcessActive::RunL() sending death notice to %d", deathPipe);
+}
+
+// Called from ProcessManagerThread
+TInt QProcessActive::RunError(TInt aError)
+{
+ Q_UNUSED(aError);
+ // Handle RunL leave (should never happen)
+ QPROCESS_ASSERT(0, EProcessActiveRunError, "QProcessActive::RunError(): Should never get here!")
+ return 0;
+}
+
+// Called from ProcessManagerThread
+void QProcessActive::DoCancel()
+{
+ QPROCESS_DEBUG_PRINT("QProcessActive::DoCancel()");
+
+ if (qt_rprocess_running(*pproc)) {
+ (*pproc)->LogonCancel(iStatus);
+ QPROCESS_DEBUG_PRINT("QProcessActive::DoCancel(): Stopped monitoring for process exit.");
+ } else {
+ QPROCESS_DEBUG_PRINT("QProcessActive::DoCancel(): Process doesn't exist");
+ }
+}
+
+
+// Called from ProcessManagerThread
+QProcessManagerMediator *QProcessManagerMediator::construct()
+{
+ QProcessManagerMediator *newInstance = new QProcessManagerMediator;
+ TInt err(KErrNone);
+
+ newInstance->currentCommand = ENoCommand;
+ newInstance->currentObserver = NULL;
+
+ if (newInstance) {
+ err = newInstance->processManagerThread.Open(newInstance->processManagerThread.Id());
+ QPROCESS_ASSERT((err == KErrNone),
+ EProcessManagerMediatorThreadOpenFailed,
+ "QProcessManagerMediator::construct(): Failed to open processManagerThread (err:%d)", err)
+ } else {
+ QPROCESS_ASSERT(0,
+ EProcessManagerMediatorCreationFailed,
+ "QProcessManagerMediator::construct(): Failed to open construct mediator")
+ }
+
+ // Activate mediator
+ CActiveScheduler::Add(newInstance);
+ newInstance->iStatus = KRequestPending;
+ newInstance->SetActive();
+ QPROCESS_DEBUG_PRINT("QProcessManagerMediator::construct(): new instance successfully created and activated");
+
+ return newInstance;
+}
+
+// Called from ProcessManagerThread
+QProcessManagerMediator::QProcessManagerMediator()
+ : CActive(CActive::EPriorityStandard)
+{
+ // Nothing to do
+}
+
+// Called from ProcessManagerThread
+QProcessManagerMediator::~QProcessManagerMediator()
+{
+ processManagerThread.Close();
+ currentCommand = ENoCommand;
+ currentObserver = NULL;
+}
+
+// Called from main thread
+bool QProcessManagerMediator::add(QProcessActive *processObserver)
+{
+ QPROCESS_DEBUG_PRINT("QProcessManagerMediator::add()");
+ return notify(processObserver, EAdd);
+}
+
+// Called from main thread
+void QProcessManagerMediator::remove(QProcessActive *processObserver)
+{
+ QPROCESS_DEBUG_PRINT("QProcessManagerMediator::remove()");
+ notify(processObserver, ERemove);
+}
+
+// Called from main thread
+void QProcessManagerMediator::terminate()
+{
+ QPROCESS_DEBUG_PRINT("QProcessManagerMediator::terminate()");
+ notify(NULL, ETerminate);
+}
+
+// Called from main thread
+bool QProcessManagerMediator::notify(QProcessActive *processObserver, Commands command)
+{
+ bool success(true);
+
+ QPROCESS_DEBUG_PRINT("QProcessManagerMediator::Notify(): Command: %d, processObserver: 0x%x", command, processObserver);
+
+ QPROCESS_ASSERT((command == ETerminate || processObserver),
+ EProcessManagerMediatorNullObserver,
+ "QProcessManagerMediator::Notify(): NULL processObserver not allowed for command: %d", command)
+
+ QPROCESS_ASSERT(IsActive(),
+ EProcessManagerMediatorInactive,
+ "QProcessManagerMediator::Notify(): Mediator is not active!")
+
+ QPROCESS_ASSERT(iStatus == KRequestPending,
+ EProcessManagerMediatorNotPending,
+ "QProcessManagerMediator::Notify(): Mediator request not pending!")
+
+ currentObserver = processObserver;
+ currentCommand = command;
+
+ // Sync with process manager thread
+ TRequestStatus pmStatus;
+ processManagerThread.Rendezvous(pmStatus);
+
+ // Complete request -> RunL will run in the process manager thread
+ TRequestStatus *status = &iStatus;
+ processManagerThread.RequestComplete(status, command);
+
+ QPROCESS_DEBUG_PRINT("QProcessManagerMediator::Notify(): Waiting process manager to complete...");
+ User::WaitForRequest(pmStatus);
+ QPROCESS_DEBUG_PRINT("QProcessManagerMediator::Notify(): Wait over");
+
+ if (currentObserver) {
+ success = !(currentObserver->error());
+ QPROCESS_DEBUG_PRINT("QProcessManagerMediator::Notify(): success = %d", success);
+ }
+
+ currentObserver = NULL;
+ currentCommand = ENoCommand;
+
+ return success;
+}
+
+// Called from ProcessManagerThread
+void QProcessManagerMediator::RunL()
+{
+ QPROCESS_DEBUG_PRINT("QProcessManagerMediator::RunL(): currentCommand: %d, iStatus: %d", currentCommand, iStatus.Int());
+ switch (currentCommand) {
+ case EAdd:
+ currentObserver->start();
+ break;
+ case ERemove:
+ currentObserver->stop();
+ break;
+ case ETerminate:
+ Deque();
+ CActiveScheduler::Stop();
+ return;
+ default:
+ QPROCESS_ASSERT(0,
+ EProcessManagerMediatorInvalidCmd,
+ "QProcessManagerMediator::RunL(): Invalid command!")
+ break;
+ }
+
+ iStatus = KRequestPending;
+ SetActive();
+
+ // Notify main thread that we are done
+ RThread::Rendezvous(KErrNone);
+}
+
+// Called from ProcessManagerThread
+TInt QProcessManagerMediator::RunError(TInt aError)
+{
+ Q_UNUSED(aError);
+ // Handle RunL leave (should never happen)
+ QPROCESS_ASSERT(0,
+ EProcessManagerMediatorRunError,
+ "QProcessManagerMediator::RunError(): Should never get here!")
+ return 0;
+}
+
+// Called from ProcessManagerThread
+void QProcessManagerMediator::DoCancel()
+{
+ QPROCESS_DEBUG_PRINT("QProcessManagerMediator::DoCancel()");
+ TRequestStatus *status = &iStatus;
+ processManagerThread.RequestComplete(status, KErrCancel);
+}
+
+Q_GLOBAL_STATIC(QProcessManager, processManager)
+
+TInt processManagerThreadFunction(TAny *param)
+{
+ QPROCESS_ASSERT(param,
+ EProcessManagerNullParam,
+ "processManagerThreadFunction(): NULL param")
+
+ QProcessManager *manager = reinterpret_cast<QProcessManager*>(param);
+
+ CActiveScheduler *scheduler = new CQtActiveScheduler();
+
+ QPROCESS_ASSERT(scheduler,
+ EProcessManagerSchedulerCreationFail,
+ "processManagerThreadFunction(): Scheduler creation failed")
+
+ CActiveScheduler::Install(scheduler);
+
+ //Creating mediator also adds it to scheduler and activates it. Failure will panic.
+ manager->setMediator(QProcessManagerMediator::construct());
+ RThread::Rendezvous(KErrNone);
+
+ CActiveScheduler::Start();
+
+ CActiveScheduler::Install(NULL);
+ delete scheduler;
+
+ return KErrNone;
+}
+
+QProcessManager::QProcessManager()
+ : mediator(NULL), threadStarted(false)
+{
+ TInt err = managerMutex.CreateLocal();
+
+ QPROCESS_ASSERT(err == KErrNone,
+ EProcessManagerMutexCreationFail,
+ "QProcessManager::QProcessManager(): Failed to create new managerMutex (err: %d)", err)
+}
+
+QProcessManager::~QProcessManager()
+{
+ QPROCESS_DEBUG_PRINT("QProcessManager::~QProcessManager()");
+ // Cancel death listening for all child processes
+ if (mediator) {
+ QMap<int, QProcessActive *>::Iterator it = children.begin();
+ while (it != children.end()) {
+ // Remove all monitors
+ QProcessActive *active = it.value();
+ mediator->remove(active);
+
+ QPROCESS_DEBUG_PRINT("QProcessManager::~QProcessManager() removed listening for a process");
+ ++it;
+ }
+
+ // Terminate process manager thread.
+ mediator->terminate();
+ delete mediator;
+ }
+
+ qDeleteAll(children.values());
+ children.clear();
+ managerThread.Close();
+ managerMutex.Close();
+}
+
+void QProcessManager::startThread()
+{
+ lock();
+
+ if (!threadStarted) {
+ TInt err = managerThread.Create(KQProcessManagerThreadName,
+ processManagerThreadFunction,
+ 0x5000,
+ (RAllocator*)NULL,
+ (TAny*)this,
+ EOwnerProcess);
+
+ QPROCESS_ASSERT(err == KErrNone,
+ EProcessManagerThreadCreationFail,
+ "QProcessManager::startThread(): Failed to create new managerThread (err:%d)", err)
+
+ threadStarted = true;
+
+ // Manager thread must start running before we continue, so sync with rendezvous
+ TRequestStatus status;
+ managerThread.Rendezvous(status);
+ managerThread.Resume();
+ User::WaitForRequest(status);
+ }
+
+ unlock();
+}
+
+static QBasicAtomicInt idCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
+
+bool QProcessManager::add(QProcess *process)
+{
+ QPROCESS_ASSERT(process,
+ EProcessManagerNullParam,
+ "QProcessManager::add(): Failed to add QProcessActive to ProcessManager - NULL process")
+
+ lock();
+
+ int serial = idCounter.fetchAndAddRelaxed(1);
+ process->d_func()->serial = serial;
+
+ QPROCESS_DEBUG_PRINT("QProcessManager::add(): serial: %d, deathPipe: %d - %d, symbianProcess: 0x%x", serial, process->d_func()->deathPipe[0], process->d_func()->deathPipe[1], process->d_func()->symbianProcess);
+
+ QProcessActive *newActive =
+ QProcessActive::construct(process,
+ &(process->d_func()->symbianProcess),
+ serial,
+ process->d_func()->deathPipe[1]);
+
+ if (newActive) {
+ if (mediator->add(newActive)) {
+ children.insert(serial, newActive);
+ unlock();
+ return true;
+ } else {
+ QPROCESS_DEBUG_PRINT("QProcessManager::add(): Failed to add QProcessActive to ProcessManager");
+ delete newActive;
+ }
+ }
+
+ unlock();
+
+ return false;
+}
+
+void QProcessManager::remove(QProcess *process)
+{
+ QPROCESS_ASSERT(process,
+ EProcessManagerNullParam,
+ "QProcessManager::remove(): Failed to remove QProcessActive from ProcessManager - NULL process")
+
+ lock();
+
+ int serial = process->d_func()->serial;
+ QProcessActive *active = children.value(serial);
+ if (!active) {
+ unlock();
+ return;
+ }
+
+ mediator->remove(active);
+
+ children.remove(serial);
+ delete active;
+
+ unlock();
+}
+
+void QProcessPrivate::destroyPipe(int *pipe)
+{
+ if (pipe[1] != -1) {
+ qt_native_close(pipe[1]);
+ pipe[1] = -1;
+ }
+ if (pipe[0] != -1) {
+ qt_native_close(pipe[0]);
+ pipe[0] = -1;
+ }
+}
+
+bool QProcessPrivate::createChannel(Channel &channel)
+{
+ Q_UNUSED(channel);
+ // No channels used
+ return false;
+}
+
+void QProcessPrivate::startProcess()
+{
+ Q_Q(QProcess);
+
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::startProcess()");
+
+ // Start the process (platform dependent)
+ q->setProcessState(QProcess::Starting);
+
+ processManager()->startThread();
+
+ qt_create_pipe(deathPipe);
+ if (threadData->eventDispatcher) {
+ deathNotifier = new QSocketNotifier(deathPipe[0],
+ QSocketNotifier::Read, q);
+ QObject::connect(deathNotifier, SIGNAL(activated(int)),
+ q, SLOT(_q_processDied()));
+ }
+
+ TInt err = qt_create_symbian_process(&symbianProcess, program, arguments);
+
+ if (err == KErrNone) {
+ pid = symbianProcess->Id();
+
+ ::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK);
+
+ if (!processManager()->add(q)) {
+ qWarning("QProcessPrivate::startProcess(): Failed to start monitoring for process death.");
+ err = KErrNoMemory;
+ }
+ }
+
+ if (err != KErrNone) {
+ // Cleanup, report error and return
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::startProcess() Process open failed, err: %d, '%s'", err, qPrintable(program));
+ q->setProcessState(QProcess::NotRunning);
+ processError = QProcess::FailedToStart;
+ q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Resource error (qt_create_symbian_process failure)")));
+ emit q->error(processError);
+ cleanup();
+ return;
+ }
+
+ processLaunched = true;
+
+ symbianProcess->Resume();
+
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::startProcess(): this: 0x%x, pid: %d", this, (TUint)pid);
+
+ // Notify child start
+ _q_startupNotification();
+
+}
+
+bool QProcessPrivate::processStarted()
+{
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::processStarted() == %s", processLaunched ? "true" : "false");
+
+ // Since we cannot get information whether process has actually been launched
+ // or not in Symbian, we need to fake it. Assume process is started if launch was
+ // successful.
+
+ return processLaunched;
+}
+
+qint64 QProcessPrivate::bytesAvailableFromStdout() const
+{
+ // In Symbian, stdout is not supported
+ return 0;
+}
+
+qint64 QProcessPrivate::bytesAvailableFromStderr() const
+{
+ // In Symbian, stderr is not supported
+ return 0;
+}
+
+qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(maxlen);
+ // In Symbian, stdout is not supported
+ return 0;
+}
+
+qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(maxlen);
+ // In Symbian, stderr is not supported
+ return 0;
+}
+
+qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(maxlen);
+ // In Symbian, stdin is not supported
+ return 0;
+}
+
+void QProcessPrivate::terminateProcess()
+{
+ // Needs PowerMgmt capability if process has been started; will panic kern-exec 46 otherwise.
+ // Always works if process is not yet started.
+ if (qt_rprocess_running(symbianProcess)) {
+ symbianProcess->Terminate(0);
+ } else {
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::terminateProcess(), Process not running");
+ }
+}
+
+void QProcessPrivate::killProcess()
+{
+ // Needs PowerMgmt capability if process has been started; will panic kern-exec 46 otherwise.
+ // Always works if process is not yet started.
+ if (qt_rprocess_running(symbianProcess)) {
+ symbianProcess->Kill(0);
+ } else {
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::killProcess(), Process not running");
+ }
+}
+
+bool QProcessPrivate::waitForStarted(int msecs)
+{
+ Q_UNUSED(msecs);
+ // Since we can get no actual feedback from process beyond its death,
+ // assume that started has already been emitted if process has been launched
+ return processLaunched;
+}
+
+bool QProcessPrivate::waitForReadyRead(int msecs)
+{
+ // Functionality not supported in Symbian
+ Q_UNUSED(msecs);
+ return false;
+}
+
+bool QProcessPrivate::waitForBytesWritten(int msecs)
+{
+ // Functionality not supported in Symbian
+ Q_UNUSED(msecs);
+ return false;
+}
+
+bool QProcessPrivate::waitForFinished(int msecs)
+{
+ Q_Q(QProcess);
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished(%d)", msecs);
+
+ TRequestStatus timerStatus = 0;
+ TRequestStatus logonStatus = 0;
+ bool timeoutOccurred = false;
+
+ // Logon to process to observe its death
+ if (qt_rprocess_running(symbianProcess)) {
+ symbianProcess->Logon(logonStatus);
+
+ // Create timer
+ RTimer timer;
+ timer.CreateLocal();
+ TTimeIntervalMicroSeconds32 interval(msecs*1000);
+ timer.After(timerStatus, interval);
+
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished() - Waiting...");
+ User::WaitForRequest(logonStatus, timerStatus);
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished() - Wait completed");
+
+ if (timerStatus == KErrNone)
+ timeoutOccurred = true;
+
+ timer.Cancel();
+ timer.Close();
+
+ symbianProcess->LogonCancel(logonStatus);
+
+ // Eat cancel request completion so that it won't mess up main thread scheduling later
+ User::WaitForRequest(logonStatus, timerStatus);
+ } else {
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished(), qt_rprocess_running returned false");
+ }
+
+ if (timeoutOccurred) {
+ processError = QProcess::Timedout;
+ q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Process operation timed out")));
+ return false;
+ }
+
+ _q_processDied();
+
+ return true;
+}
+
+bool QProcessPrivate::waitForWrite(int msecs)
+{
+ // Functionality not supported in Symbian
+ Q_UNUSED(msecs);
+ return false;
+}
+
+// Deceptively named function. Exit code is actually got in waitForDeadChild().
+void QProcessPrivate::findExitCode()
+{
+ Q_Q(QProcess);
+ processManager()->remove(q);
+}
+
+bool QProcessPrivate::waitForDeadChild()
+{
+ Q_Q(QProcess);
+
+ // read a byte from the death pipe
+ char c;
+ qt_native_read(deathPipe[0], &c, 1);
+
+ if (symbianProcess && symbianProcess->Handle()) {
+ TExitType et = symbianProcess->ExitType();
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForDeadChild() symbianProcess->ExitType: %d", et);
+ if (et != EExitPending) {
+ processManager()->remove(q);
+ exitCode = symbianProcess->ExitReason();
+ crashed = (et == EExitPanic);
+#if defined QPROCESS_DEBUG
+ TExitCategoryName catName = symbianProcess->ExitCategory();
+ qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode"
+ << exitCode << ", crashed:" << crashed
+ << ", category:" << QString::fromUtf16(catName.Ptr());
+#endif
+ } else {
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForDeadChild() not dead!");
+ }
+ }
+
+ return true;
+}
+
+void QProcessPrivate::_q_notified()
+{
+ // Nothing to do in Symbian
+}
+
+/*! \internal
+ */
+bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
+{
+ QPROCESS_DEBUG_PRINT("QProcessPrivate::startDetached()");
+ Q_UNUSED(workingDirectory);
+
+ RProcess *newProc = NULL;
+
+ TInt err = qt_create_symbian_process(&newProc, program, arguments);
+
+ if (err == KErrNone) {
+ if (pid)
+ *pid = (qint64)newProc->Id();
+
+ newProc->Resume();
+ newProc->Close();
+ return true;
+ }
+
+ return false;
+}
+
+
+void QProcessPrivate::initializeProcessManager()
+{
+ (void) processManager();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PROCESS
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 0084c4a..baf90c4 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -84,6 +84,7 @@ QT_END_NAMESPACE
#include "qprocess.h"
#include "qprocess_p.h"
+#include "private/qcore_unix_p.h"
#ifdef Q_OS_MAC
#include <private/qcore_mac_p.h>
@@ -114,78 +115,11 @@ static inline char *strdup(const char *data)
}
#endif
-static qint64 qt_native_read(int fd, char *data, qint64 maxlen)
-{
- qint64 ret = 0;
- do {
- ret = ::read(fd, data, maxlen);
- } while (ret == -1 && errno == EINTR);
- return ret;
-}
-
-static qint64 qt_native_write(int fd, const char *data, qint64 len)
-{
- qint64 ret = 0;
- do {
- ret = ::write(fd, data, len);
- } while (ret == -1 && errno == EINTR);
- return ret;
-}
-
-static void qt_native_close(int fd)
-{
- int ret;
- do {
- ret = ::close(fd);
- } while (ret == -1 && errno == EINTR);
-}
-
-static void qt_native_dup2(int oldfd, int newfd)
-{
- int ret;
- do {
- ret = ::dup2(oldfd, newfd);
- } while (ret == -1 && errno == EINTR);
-}
-
-static void qt_native_chdir(const char *path)
-{
- int ret;
- do {
- ret = ::chdir(path);
- } while (ret == -1 && errno == EINTR);
-}
-
-static void qt_native_execve(const char *filename, char *const argv[],
- char *const envp[])
-{
- int ret;
- do {
- ret = ::execve(filename, argv, envp);
- } while (ret == -1 && errno == EINTR);
-}
-
-static void qt_native_execv(const char *path, char *const argv[])
-{
- int ret;
- do {
- ret = ::execv(path, argv);
- } while (ret == -1 && errno == EINTR);
-}
-
-static void qt_native_execvp(const char *file, char *const argv[])
-{
- int ret;
- do {
- ret = ::execvp(file, argv);
- } while (ret == -1 && errno == EINTR);
-}
-
static int qt_qprocess_deadChild_pipe[2];
static void (*qt_sa_old_sigchld_handler)(int) = 0;
static void qt_sa_sigchld_handler(int signum)
{
- qt_native_write(qt_qprocess_deadChild_pipe[1], "", 1);
+ qt_safe_write(qt_qprocess_deadChild_pipe[1], "", 1);
#if defined (QPROCESS_DEBUG)
fprintf(stderr, "*** SIGCHLD\n");
#endif
@@ -194,6 +128,13 @@ static void qt_sa_sigchld_handler(int signum)
qt_sa_old_sigchld_handler(signum);
}
+static inline void add_fd(int &nfds, int fd, fd_set *fdset)
+{
+ FD_SET(fd, fdset);
+ if ((fd) > nfds)
+ nfds = fd;
+}
+
struct QProcessInfo {
QProcess *process;
int deathPipe;
@@ -221,7 +162,17 @@ private:
QMap<int, QProcessInfo *> children;
};
-Q_GLOBAL_STATIC(QProcessManager, processManager)
+
+Q_GLOBAL_STATIC(QMutex, processManagerGlobalMutex)
+
+static QProcessManager *processManager() {
+ // The constructor of QProcessManager should be called only once
+ // so we cannot use Q_GLOBAL_STATIC directly for QProcessManager
+ QMutex *mutex = processManagerGlobalMutex();
+ QMutexLocker locker(mutex);
+ static QProcessManager processManager;
+ return &processManager;
+}
QProcessManager::QProcessManager()
{
@@ -231,13 +182,7 @@ QProcessManager::QProcessManager()
// initialize the dead child pipe and make it non-blocking. in the
// extremely unlikely event that the pipe fills up, we do not under any
// circumstances want to block.
- ::pipe(qt_qprocess_deadChild_pipe);
- ::fcntl(qt_qprocess_deadChild_pipe[0], F_SETFD, FD_CLOEXEC);
- ::fcntl(qt_qprocess_deadChild_pipe[1], F_SETFD, FD_CLOEXEC);
- ::fcntl(qt_qprocess_deadChild_pipe[0], F_SETFL,
- ::fcntl(qt_qprocess_deadChild_pipe[0], F_GETFL) | O_NONBLOCK);
- ::fcntl(qt_qprocess_deadChild_pipe[1], F_SETFL,
- ::fcntl(qt_qprocess_deadChild_pipe[1], F_GETFL) | O_NONBLOCK);
+ qt_safe_pipe(qt_qprocess_deadChild_pipe, O_NONBLOCK);
// set up the SIGCHLD handler, which writes a single byte to the dead
// child pipe every time a child dies.
@@ -254,13 +199,13 @@ QProcessManager::QProcessManager()
QProcessManager::~QProcessManager()
{
// notify the thread that we're shutting down.
- qt_native_write(qt_qprocess_deadChild_pipe[1], "@", 1);
- qt_native_close(qt_qprocess_deadChild_pipe[1]);
+ qt_safe_write(qt_qprocess_deadChild_pipe[1], "@", 1);
+ qt_safe_close(qt_qprocess_deadChild_pipe[1]);
wait();
// on certain unixes, closing the reading end of the pipe will cause
// select in run() to block forever, rather than return with EBADF.
- qt_native_close(qt_qprocess_deadChild_pipe[0]);
+ qt_safe_close(qt_qprocess_deadChild_pipe[0]);
qt_qprocess_deadChild_pipe[0] = -1;
qt_qprocess_deadChild_pipe[1] = -1;
@@ -304,7 +249,7 @@ void QProcessManager::run()
// signals may have been delivered in the meantime, to avoid race
// conditions.
char c;
- if (qt_native_read(qt_qprocess_deadChild_pipe[0], &c, 1) < 0 || c == '@')
+ if (qt_safe_read(qt_qprocess_deadChild_pipe[0], &c, 1) < 0 || c == '@')
break;
// catch any and all children that we can.
@@ -323,7 +268,7 @@ void QProcessManager::catchDeadChildren()
// notify all children that they may have died. they need to run
// waitpid() in their own thread.
QProcessInfo *info = it.value();
- qt_native_write(info->deathPipe, "", 1);
+ qt_safe_write(info->deathPipe, "", 1);
#if defined (QPROCESS_DEBUG)
qDebug() << "QProcessManager::run() sending death notice to" << info->process;
@@ -382,32 +327,23 @@ void QProcessManager::unlock()
static void qt_create_pipe(int *pipe)
{
if (pipe[0] != -1)
- qt_native_close(pipe[0]);
+ qt_safe_close(pipe[0]);
if (pipe[1] != -1)
- qt_native_close(pipe[1]);
-#ifdef Q_OS_IRIX
- if (::socketpair(AF_UNIX, SOCK_STREAM, 0, pipe) == -1) {
- qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s",
- pipe, qPrintable(qt_error_string(errno)));
- }
-#else
- if (::pipe(pipe) != 0) {
+ qt_safe_close(pipe[1]);
+ if (qt_safe_pipe(pipe) != 0) {
qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s",
pipe, qPrintable(qt_error_string(errno)));
}
-#endif
- ::fcntl(pipe[0], F_SETFD, FD_CLOEXEC);
- ::fcntl(pipe[1], F_SETFD, FD_CLOEXEC);
}
void QProcessPrivate::destroyPipe(int *pipe)
{
if (pipe[1] != -1) {
- qt_native_close(pipe[1]);
+ qt_safe_close(pipe[1]);
pipe[1] = -1;
}
if (pipe[0] != -1) {
- qt_native_close(pipe[0]);
+ qt_safe_close(pipe[0]);
pipe[0] = -1;
}
}
@@ -460,7 +396,7 @@ bool QProcessPrivate::createChannel(Channel &channel)
if (&channel == &stdinChannel) {
// try to open in read-only mode
channel.pipe[1] = -1;
- if ( (channel.pipe[0] = QT_OPEN(fname, O_RDONLY)) != -1)
+ if ( (channel.pipe[0] = qt_safe_open(fname, O_RDONLY)) != -1)
return true; // success
q->setErrorString(QProcess::tr("Could not open input redirection for reading"));
@@ -472,7 +408,7 @@ bool QProcessPrivate::createChannel(Channel &channel)
mode |= O_TRUNC;
channel.pipe[0] = -1;
- if ( (channel.pipe[1] = QT_OPEN(fname, mode, 0666)) != -1)
+ if ( (channel.pipe[1] = qt_safe_open(fname, mode, 0666)) != -1)
return true; // success
q->setErrorString(QProcess::tr("Could not open output redirection for writing"));
@@ -522,8 +458,12 @@ bool QProcessPrivate::createChannel(Channel &channel)
}
}
-static char **_q_dupEnvironment(const QStringList &environment, int *envc)
+static char **_q_dupEnvironment(const QHash<QByteArray, QByteArray> &environment, int *envc)
{
+ *envc = 0;
+ if (environment.isEmpty())
+ return 0;
+
// if LD_LIBRARY_PATH exists in the current environment, but
// not in the environment list passed by the programmer, then
// copy it over.
@@ -532,27 +472,29 @@ static char **_q_dupEnvironment(const QStringList &environment, int *envc)
#else
static const char libraryPath[] = "LD_LIBRARY_PATH";
#endif
- const QString libraryPathString = QLatin1String(libraryPath);
- QStringList env = environment;
- QStringList matches = env.filter(
- QRegExp(QLatin1Char('^') + libraryPathString + QLatin1Char('=')));
- const QString envLibraryPath = QString::fromLocal8Bit(::getenv(libraryPath));
- if (matches.isEmpty() && !envLibraryPath.isEmpty()) {
- QString entry = libraryPathString;
- entry += QLatin1Char('=');
- entry += envLibraryPath;
- env << libraryPathString + QLatin1Char('=') + envLibraryPath;
+ const QByteArray envLibraryPath = qgetenv(libraryPath);
+ bool needToAddLibraryPath = !envLibraryPath.isEmpty() &&
+ !environment.contains(libraryPath);
+
+ char **envp = new char *[environment.count() + 2];
+ envp[environment.count()] = 0;
+ envp[environment.count() + 1] = 0;
+
+ QHash<QByteArray, QByteArray>::ConstIterator it = environment.constBegin();
+ const QHash<QByteArray, QByteArray>::ConstIterator end = environment.constEnd();
+ for ( ; it != end; ++it) {
+ QByteArray key = it.key();
+ QByteArray value = it.value();
+ key.reserve(key.length() + 1 + value.length());
+ key.append('=');
+ key.append(value);
+
+ envp[(*envc)++] = ::strdup(key.constData());
}
- char **envp = new char *[env.count() + 1];
- envp[env.count()] = 0;
-
- for (int j = 0; j < env.count(); ++j) {
- QString item = env.at(j);
- envp[j] = ::strdup(item.toLocal8Bit().constData());
- }
-
- *envc = env.count();
+ if (needToAddLibraryPath)
+ envp[(*envc)++] = ::strdup(QByteArray(libraryPath) + '=' +
+ envLibraryPath);
return envp;
}
@@ -581,29 +523,25 @@ void QProcessPrivate::startProcess()
processManager()->start();
// Initialize pipes
+ if (!createChannel(stdinChannel) ||
+ !createChannel(stdoutChannel) ||
+ !createChannel(stderrChannel))
+ return;
qt_create_pipe(childStartedPipe);
+ qt_create_pipe(deathPipe);
+
if (threadData->eventDispatcher) {
startupSocketNotifier = new QSocketNotifier(childStartedPipe[0],
QSocketNotifier::Read, q);
QObject::connect(startupSocketNotifier, SIGNAL(activated(int)),
q, SLOT(_q_startupNotification()));
- }
- qt_create_pipe(deathPipe);
- ::fcntl(deathPipe[0], F_SETFD, FD_CLOEXEC);
- ::fcntl(deathPipe[1], F_SETFD, FD_CLOEXEC);
- if (threadData->eventDispatcher) {
deathNotifier = new QSocketNotifier(deathPipe[0],
QSocketNotifier::Read, q);
QObject::connect(deathNotifier, SIGNAL(activated(int)),
q, SLOT(_q_processDied()));
}
- if (!createChannel(stdinChannel) ||
- !createChannel(stdoutChannel) ||
- !createChannel(stderrChannel))
- return;
-
// Start the process (platform dependent)
q->setProcessState(QProcess::Starting);
@@ -652,7 +590,9 @@ void QProcessPrivate::startProcess()
// Duplicate the environment.
int envc = 0;
- char **envp = _q_dupEnvironment(environment, &envc);
+ char **envp = 0;
+ if (environment.d.constData())
+ envp = _q_dupEnvironment(environment.d.constData()->hash, &envc);
// Encode the working directory if it's non-empty, otherwise just pass 0.
const char *workingDirPtr = 0;
@@ -731,11 +671,11 @@ void QProcessPrivate::startProcess()
// parent
// close the ends we don't use and make all pipes non-blocking
::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK);
- qt_native_close(childStartedPipe[1]);
+ qt_safe_close(childStartedPipe[1]);
childStartedPipe[1] = -1;
if (stdinChannel.pipe[0] != -1) {
- qt_native_close(stdinChannel.pipe[0]);
+ qt_safe_close(stdinChannel.pipe[0]);
stdinChannel.pipe[0] = -1;
}
@@ -743,7 +683,7 @@ void QProcessPrivate::startProcess()
::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK);
if (stdoutChannel.pipe[1] != -1) {
- qt_native_close(stdoutChannel.pipe[1]);
+ qt_safe_close(stdoutChannel.pipe[1]);
stdoutChannel.pipe[1] = -1;
}
@@ -751,7 +691,7 @@ void QProcessPrivate::startProcess()
::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK);
if (stderrChannel.pipe[1] != -1) {
- qt_native_close(stderrChannel.pipe[1]);
+ qt_safe_close(stderrChannel.pipe[1]);
stderrChannel.pipe[1] = -1;
}
if (stderrChannel.pipe[0] != -1)
@@ -764,35 +704,34 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
Q_Q(QProcess);
- // copy the stdin socket
- qt_native_dup2(stdinChannel.pipe[0], fileno(stdin));
+ // copy the stdin socket (without closing on exec)
+ qt_safe_dup2(stdinChannel.pipe[0], fileno(stdin), 0);
// copy the stdout and stderr if asked to
if (processChannelMode != QProcess::ForwardedChannels) {
- qt_native_dup2(stdoutChannel.pipe[1], fileno(stdout));
+ qt_safe_dup2(stdoutChannel.pipe[1], fileno(stdout), 0);
// merge stdout and stderr if asked to
if (processChannelMode == QProcess::MergedChannels) {
- qt_native_dup2(fileno(stdout), fileno(stderr));
+ qt_safe_dup2(fileno(stdout), fileno(stderr), 0);
} else {
- qt_native_dup2(stderrChannel.pipe[1], fileno(stderr));
+ qt_safe_dup2(stderrChannel.pipe[1], fileno(stderr), 0);
}
}
// make sure this fd is closed if execvp() succeeds
- qt_native_close(childStartedPipe[0]);
- ::fcntl(childStartedPipe[1], F_SETFD, FD_CLOEXEC);
+ qt_safe_close(childStartedPipe[0]);
// enter the working directory
if (workingDir)
- qt_native_chdir(workingDir);
+ QT_CHDIR(workingDir);
// this is a virtual call, and it base behavior is to do nothing.
q->setupChildProcess();
// execute the process
- if (environment.isEmpty()) {
- qt_native_execvp(argv[0], argv);
+ if (!envp) {
+ qt_safe_execvp(argv[0], argv);
} else {
if (path) {
char **arg = path;
@@ -801,14 +740,14 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
#if defined (QPROCESS_DEBUG)
fprintf(stderr, "QProcessPrivate::execChild() searching / starting %s\n", argv[0]);
#endif
- qt_native_execve(argv[0], argv, envp);
+ qt_safe_execve(argv[0], argv, envp);
++arg;
}
} else {
#if defined (QPROCESS_DEBUG)
fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
#endif
- qt_native_execve(argv[0], argv, envp);
+ qt_safe_execve(argv[0], argv, envp);
}
}
@@ -816,21 +755,21 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
#if defined (QPROCESS_DEBUG)
fprintf(stderr, "QProcessPrivate::execChild() failed, notifying parent process\n");
#endif
- qt_native_write(childStartedPipe[1], "", 1);
- qt_native_close(childStartedPipe[1]);
+ qt_safe_write(childStartedPipe[1], "", 1);
+ qt_safe_close(childStartedPipe[1]);
childStartedPipe[1] = -1;
}
bool QProcessPrivate::processStarted()
{
char c;
- int i = qt_native_read(childStartedPipe[0], &c, 1);
+ int i = qt_safe_read(childStartedPipe[0], &c, 1);
if (startupSocketNotifier) {
startupSocketNotifier->setEnabled(false);
startupSocketNotifier->deleteLater();
startupSocketNotifier = 0;
}
- qt_native_close(childStartedPipe[0]);
+ qt_safe_close(childStartedPipe[0]);
childStartedPipe[0] = -1;
#if defined (QPROCESS_DEBUG)
@@ -865,7 +804,7 @@ qint64 QProcessPrivate::bytesAvailableFromStderr() const
qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen)
{
- qint64 bytesRead = qt_native_read(stdoutChannel.pipe[0], data, maxlen);
+ qint64 bytesRead = qt_safe_read(stdoutChannel.pipe[0], data, maxlen);
#if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::readFromStdout(%p \"%s\", %lld) == %lld",
data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead);
@@ -875,7 +814,7 @@ qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen)
qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen)
{
- qint64 bytesRead = qt_native_read(stderrChannel.pipe[0], data, maxlen);
+ qint64 bytesRead = qt_safe_read(stderrChannel.pipe[0], data, maxlen);
#if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::readFromStderr(%p \"%s\", %lld) == %lld",
data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead);
@@ -899,7 +838,7 @@ qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen)
{
qt_ignore_sigpipe();
- qint64 written = qt_native_write(stdinChannel.pipe[1], data, maxlen);
+ qint64 written = qt_safe_write(stdinChannel.pipe[1], data, maxlen);
#if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::writeToStdin(%p \"%s\", %lld) == %lld",
data, qt_prettyDebug(data, maxlen, 16).constData(), maxlen, written);
@@ -925,17 +864,15 @@ void QProcessPrivate::killProcess()
::kill(pid_t(pid), SIGKILL);
}
-static int qt_native_select(fd_set *fdread, fd_set *fdwrite, int timeout)
+static int select_msecs(int nfds, fd_set *fdread, fd_set *fdwrite, int timeout)
{
+ if (timeout < 0)
+ return qt_safe_select(nfds, fdread, fdwrite, 0, 0);
+
struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
-
- int ret;
- do {
- ret = select(FD_SETSIZE, fdread, fdwrite, 0, timeout < 0 ? 0 : &tv);
- } while (ret < 0 && (errno == EINTR));
- return ret;
+ return qt_safe_select(nfds, fdread, fdwrite, 0, &tv);
}
/*
@@ -963,11 +900,7 @@ bool QProcessPrivate::waitForStarted(int msecs)
fd_set fds;
FD_ZERO(&fds);
FD_SET(childStartedPipe[0], &fds);
- int ret;
- do {
- ret = qt_native_select(&fds, 0, msecs);
- } while (ret < 0 && errno == EINTR);
- if (ret == 0) {
+ if (select_msecs(childStartedPipe[0] + 1, &fds, 0, msecs) == 0) {
processError = QProcess::Timedout;
q->setErrorString(QProcess::tr("Process operation timed out"));
#if defined (QPROCESS_DEBUG)
@@ -1000,24 +933,23 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
+ int nfds = deathPipe[0];
+ FD_SET(deathPipe[0], &fdread);
+
if (processState == QProcess::Starting)
- FD_SET(childStartedPipe[0], &fdread);
+ add_fd(nfds, childStartedPipe[0], &fdread);
if (stdoutChannel.pipe[0] != -1)
- FD_SET(stdoutChannel.pipe[0], &fdread);
+ add_fd(nfds, stdoutChannel.pipe[0], &fdread);
if (stderrChannel.pipe[0] != -1)
- FD_SET(stderrChannel.pipe[0], &fdread);
-
- FD_SET(deathPipe[0], &fdread);
+ add_fd(nfds, stderrChannel.pipe[0], &fdread);
if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
- FD_SET(stdinChannel.pipe[1], &fdwrite);
+ add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
- int ret = qt_native_select(&fdread, &fdwrite, timeout);
+ int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
if (ret < 0) {
- if (errno == EINTR)
- continue;
break;
}
if (ret == 0) {
@@ -1073,24 +1005,24 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
+ int nfds = deathPipe[0];
+ FD_SET(deathPipe[0], &fdread);
+
if (processState == QProcess::Starting)
- FD_SET(childStartedPipe[0], &fdread);
+ add_fd(nfds, childStartedPipe[0], &fdread);
if (stdoutChannel.pipe[0] != -1)
- FD_SET(stdoutChannel.pipe[0], &fdread);
+ add_fd(nfds, stdoutChannel.pipe[0], &fdread);
if (stderrChannel.pipe[0] != -1)
- FD_SET(stderrChannel.pipe[0], &fdread);
+ add_fd(nfds, stderrChannel.pipe[0], &fdread);
- FD_SET(deathPipe[0], &fdread);
if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
- FD_SET(stdinChannel.pipe[1], &fdwrite);
+ add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
- int ret = qt_native_select(&fdread, &fdwrite, timeout);
+ int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
if (ret < 0) {
- if (errno == EINTR)
- continue;
break;
}
@@ -1136,29 +1068,28 @@ bool QProcessPrivate::waitForFinished(int msecs)
forever {
fd_set fdread;
fd_set fdwrite;
+ int nfds = -1;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
if (processState == QProcess::Starting)
- FD_SET(childStartedPipe[0], &fdread);
+ add_fd(nfds, childStartedPipe[0], &fdread);
if (stdoutChannel.pipe[0] != -1)
- FD_SET(stdoutChannel.pipe[0], &fdread);
+ add_fd(nfds, stdoutChannel.pipe[0], &fdread);
if (stderrChannel.pipe[0] != -1)
- FD_SET(stderrChannel.pipe[0], &fdread);
+ add_fd(nfds, stderrChannel.pipe[0], &fdread);
if (processState == QProcess::Running)
- FD_SET(deathPipe[0], &fdread);
+ add_fd(nfds, deathPipe[0], &fdread);
if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
- FD_SET(stdinChannel.pipe[1], &fdwrite);
+ add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
- int ret = qt_native_select(&fdread, &fdwrite, timeout);
+ int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
if (ret < 0) {
- if (errno == EINTR)
- continue;
break;
}
if (ret == 0) {
@@ -1193,12 +1124,7 @@ bool QProcessPrivate::waitForWrite(int msecs)
fd_set fdwrite;
FD_ZERO(&fdwrite);
FD_SET(stdinChannel.pipe[1], &fdwrite);
-
- int ret;
- do {
- ret = qt_native_select(0, &fdwrite, msecs < 0 ? 0 : msecs) == 1;
- } while (ret < 0 && errno == EINTR);
- return ret == 1;
+ return select_msecs(stdinChannel.pipe[1] + 1, 0, &fdwrite, msecs < 0 ? 0 : msecs) == 1;
}
void QProcessPrivate::findExitCode()
@@ -1213,15 +1139,11 @@ bool QProcessPrivate::waitForDeadChild()
// read a byte from the death pipe
char c;
- qt_native_read(deathPipe[0], &c, 1);
+ qt_safe_read(deathPipe[0], &c, 1);
// check if our process is dead
int exitStatus;
- pid_t waitResult = 0;
- do {
- waitResult = waitpid(pid_t(pid), &exitStatus, WNOHANG);
- } while ((waitResult == -1 && errno == EINTR));
- if (waitResult > 0) {
+ if (qt_safe_waitpid(pid_t(pid), &exitStatus, WNOHANG) > 0) {
processManager()->remove(q);
crashed = !WIFEXITED(exitStatus);
exitCode = WEXITSTATUS(exitStatus);
@@ -1251,10 +1173,10 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
// To catch the startup of the child
int startedPipe[2];
- ::pipe(startedPipe);
+ qt_safe_pipe(startedPipe);
// To communicate the pid of the child
int pidPipe[2];
- ::pipe(pidPipe);
+ qt_safe_pipe(pidPipe);
pid_t childPid = qt_fork();
if (childPid == 0) {
@@ -1265,16 +1187,15 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
::setsid();
- qt_native_close(startedPipe[0]);
- qt_native_close(pidPipe[0]);
+ qt_safe_close(startedPipe[0]);
+ qt_safe_close(pidPipe[0]);
pid_t doubleForkPid = qt_fork();
if (doubleForkPid == 0) {
- ::fcntl(startedPipe[1], F_SETFD, FD_CLOEXEC);
- qt_native_close(pidPipe[1]);
+ qt_safe_close(pidPipe[1]);
if (!encodedWorkingDirectory.isEmpty())
- qt_native_chdir(encodedWorkingDirectory.constData());
+ QT_CHDIR(encodedWorkingDirectory.constData());
char **argv = new char *[arguments.size() + 2];
for (int i = 0; i < arguments.size(); ++i) {
@@ -1295,13 +1216,13 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
if (!tmp.endsWith('/')) tmp += '/';
tmp += QFile::encodeName(program);
argv[0] = tmp.data();
- qt_native_execv(argv[0], argv);
+ qt_safe_execv(argv[0], argv);
}
}
} else {
QByteArray tmp = QFile::encodeName(program);
argv[0] = tmp.data();
- qt_native_execv(argv[0], argv);
+ qt_safe_execv(argv[0], argv);
}
struct sigaction noaction;
@@ -1311,8 +1232,8 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
// '\1' means execv failed
char c = '\1';
- qt_native_write(startedPipe[1], &c, 1);
- qt_native_close(startedPipe[1]);
+ qt_safe_write(startedPipe[1], &c, 1);
+ qt_safe_close(startedPipe[1]);
::_exit(1);
} else if (doubleForkPid == -1) {
struct sigaction noaction;
@@ -1322,40 +1243,39 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
// '\2' means internal error
char c = '\2';
- qt_native_write(startedPipe[1], &c, 1);
+ qt_safe_write(startedPipe[1], &c, 1);
}
- qt_native_close(startedPipe[1]);
- qt_native_write(pidPipe[1], (const char *)&doubleForkPid, sizeof(pid_t));
- qt_native_chdir("/");
+ qt_safe_close(startedPipe[1]);
+ qt_safe_write(pidPipe[1], (const char *)&doubleForkPid, sizeof(pid_t));
+ QT_CHDIR("/");
::_exit(1);
}
- qt_native_close(startedPipe[1]);
- qt_native_close(pidPipe[1]);
+ qt_safe_close(startedPipe[1]);
+ qt_safe_close(pidPipe[1]);
if (childPid == -1) {
- qt_native_close(startedPipe[0]);
- qt_native_close(pidPipe[0]);
+ qt_safe_close(startedPipe[0]);
+ qt_safe_close(pidPipe[0]);
return false;
}
char reply = '\0';
- int startResult = qt_native_read(startedPipe[0], &reply, 1);
+ int startResult = qt_safe_read(startedPipe[0], &reply, 1);
int result;
- qt_native_close(startedPipe[0]);
- while (::waitpid(childPid, &result, 0) == -1 && errno == EINTR)
- { }
+ qt_safe_close(startedPipe[0]);
+ qt_safe_waitpid(childPid, &result, 0);
bool success = (startResult != -1 && reply == '\0');
if (success && pid) {
pid_t actualPid = 0;
- if (qt_native_read(pidPipe[0], (char *)&actualPid, sizeof(pid_t)) == sizeof(pid_t)) {
+ if (qt_safe_read(pidPipe[0], (char *)&actualPid, sizeof(pid_t)) == sizeof(pid_t)) {
*pid = actualPid;
} else {
*pid = 0;
}
}
- qt_native_close(pidPipe[0]);
+ qt_safe_close(pidPipe[0]);
return success;
}
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 7b05fd3..a1c54f1 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -54,7 +54,7 @@
#include <private/qthread_p.h>
#include <qdebug.h>
-#include "private/qfsfileengine_p.h" // for longFileName and win95FileName
+#include "private/qfsfileengine_p.h" // for longFileName
#ifndef QT_NO_PROCESS
@@ -122,25 +122,15 @@ bool QProcessPrivate::createChannel(Channel &channel)
if (&channel == &stdinChannel) {
// try to open in read-only mode
channel.pipe[1] = INVALID_Q_PIPE;
- QT_WA({
- channel.pipe[0] =
- CreateFileW((TCHAR*)QFSFileEnginePrivate::longFileName(channel.file).utf16(),
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &secAtt,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- }, {
- channel.pipe[0] =
- CreateFileA(QFSFileEnginePrivate::win95Name(channel.file),
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &secAtt,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- });
+ channel.pipe[0] =
+ CreateFile((const wchar_t*)QFSFileEnginePrivate::longFileName(channel.file).utf16(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &secAtt,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
if (channel.pipe[0] != INVALID_Q_PIPE)
return true;
@@ -148,31 +138,15 @@ bool QProcessPrivate::createChannel(Channel &channel)
} else {
// open in write mode
channel.pipe[0] = INVALID_Q_PIPE;
- DWORD creation;
- if (channel.append)
- creation = OPEN_ALWAYS;
- else
- creation = CREATE_ALWAYS;
-
- QT_WA({
- channel.pipe[1] =
- CreateFileW((TCHAR*)QFSFileEnginePrivate::longFileName(channel.file).utf16(),
- GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &secAtt,
- creation,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- }, {
- channel.pipe[1] =
- CreateFileA(QFSFileEnginePrivate::win95Name(channel.file),
- GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &secAtt,
- creation,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- });
+ channel.pipe[1] =
+ CreateFile((const wchar_t *)QFSFileEnginePrivate::longFileName(channel.file).utf16(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &secAtt,
+ channel.append ? OPEN_ALWAYS : CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
if (channel.pipe[1] != INVALID_Q_PIPE) {
if (channel.append) {
SetFilePointer(channel.pipe[1], 0, NULL, FILE_END);
@@ -272,12 +246,12 @@ static QString qt_create_commandline(const QString &program, const QStringList &
QString args;
if (!program.isEmpty()) {
QString programName = program;
- if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1String(" ")))
- programName = QLatin1String("\"") + programName + QLatin1String("\"");
- programName.replace(QLatin1String("/"), QLatin1String("\\"));
+ if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1Char(' ')))
+ programName = QLatin1Char('\"') + programName + QLatin1Char('\"');
+ programName.replace(QLatin1Char('/'), QLatin1Char('\\'));
// add the prgram as the first arg ... it works better
- args = programName + QLatin1String(" ");
+ args = programName + QLatin1Char(' ');
}
for (int i=0; i<arguments.size(); ++i) {
@@ -285,16 +259,16 @@ static QString qt_create_commandline(const QString &program, const QStringList &
// in the case of \" already being in the string the \ must also be escaped
tmp.replace( QLatin1String("\\\""), QLatin1String("\\\\\"") );
// escape a single " because the arguments will be parsed
- tmp.replace( QLatin1String("\""), QLatin1String("\\\"") );
+ tmp.replace( QLatin1Char('\"'), QLatin1String("\\\"") );
if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
// The argument must not end with a \ since this would be interpreted
// as escaping the quote -- rather put the \ behind the quote: e.g.
// rather use "foo"\ than "foo\"
- QString endQuote(QLatin1String("\""));
+ QString endQuote(QLatin1Char('\"'));
int i = tmp.length();
while (i>0 && tmp.at(i-1) == QLatin1Char('\\')) {
--i;
- endQuote += QLatin1String("\\");
+ endQuote += QLatin1Char('\\');
}
args += QLatin1String(" \"") + tmp.left(i) + endQuote;
} else {
@@ -304,54 +278,60 @@ static QString qt_create_commandline(const QString &program, const QStringList &
return args;
}
-static QByteArray qt_create_environment(const QStringList &environment)
+static QByteArray qt_create_environment(const QHash<QString, QString> &environment)
{
QByteArray envlist;
if (!environment.isEmpty()) {
- QStringList envStrings = environment;
- int pos = 0;
- // add PATH if necessary (for DLL loading)
- if (envStrings.filter(QRegExp(QLatin1String("^PATH="),Qt::CaseInsensitive)).isEmpty()) {
+ QHash<QString, QString> copy = environment;
+
+ // add PATH if necessary (for DLL loading)
+ if (!copy.contains(QLatin1String("PATH"))) {
QByteArray path = qgetenv("PATH");
if (!path.isEmpty())
- envStrings.prepend(QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path)));
+ copy.insert(QLatin1String("PATH"), QString::fromLocal8Bit(path));
}
+
// add systemroot if needed
- if (envStrings.filter(QRegExp(QLatin1String("^SystemRoot="),Qt::CaseInsensitive)).isEmpty()) {
- QByteArray systemRoot = qgetenv("SystemRoot");
+ if (!copy.contains(QLatin1String("SYSTEMROOT"))) {
+ QByteArray systemRoot = qgetenv("SYSTEMROOT");
if (!systemRoot.isEmpty())
- envStrings.prepend(QString(QLatin1String("SystemRoot=%1")).arg(QString::fromLocal8Bit(systemRoot)));
+ copy.insert(QLatin1String("SYSTEMROOT"), QString::fromLocal8Bit(systemRoot));
}
-#ifdef UNICODE
- if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) {
- for (QStringList::ConstIterator it = envStrings.constBegin(); it != envStrings.constEnd(); ++it) {
- QString tmp = *it;
- uint tmpSize = sizeof(TCHAR) * (tmp.length()+1);
- envlist.resize(envlist.size() + tmpSize);
- memcpy(envlist.data()+pos, tmp.utf16(), tmpSize);
- pos += tmpSize;
- }
- // add the 2 terminating 0 (actually 4, just to be on the safe side)
- envlist.resize( envlist.size()+4 );
- envlist[pos++] = 0;
- envlist[pos++] = 0;
- envlist[pos++] = 0;
- envlist[pos++] = 0;
- } else
-#endif // UNICODE
- {
- for (QStringList::ConstIterator it = envStrings.constBegin(); it != envStrings.constEnd(); it++) {
- QByteArray tmp = (*it).toLocal8Bit();
- uint tmpSize = tmp.length() + 1;
- envlist.resize(envlist.size() + tmpSize);
- memcpy(envlist.data()+pos, tmp.data(), tmpSize);
- pos += tmpSize;
- }
- // add the terminating 0 (actually 2, just to be on the safe side)
- envlist.resize(envlist.size()+2);
- envlist[pos++] = 0;
- envlist[pos++] = 0;
+
+ int pos = 0;
+ QHash<QString, QString>::ConstIterator it = copy.constBegin(),
+ end = copy.constEnd();
+
+ static const wchar_t equal = L'=';
+ static const wchar_t nul = L'\0';
+
+ for ( ; it != end; ++it) {
+ uint tmpSize = sizeof(wchar_t) * (it.key().length() + it.value().length() + 2);
+ // ignore empty strings
+ if (tmpSize == sizeof(wchar_t) * 2)
+ continue;
+ envlist.resize(envlist.size() + tmpSize);
+
+ tmpSize = it.key().length() * sizeof(wchar_t);
+ memcpy(envlist.data()+pos, it.key().utf16(), tmpSize);
+ pos += tmpSize;
+
+ memcpy(envlist.data()+pos, &equal, sizeof(wchar_t));
+ pos += sizeof(wchar_t);
+
+ tmpSize = it.value().length() * sizeof(wchar_t);
+ memcpy(envlist.data()+pos, it.value().utf16(), tmpSize);
+ pos += tmpSize;
+
+ memcpy(envlist.data()+pos, &nul, sizeof(wchar_t));
+ pos += sizeof(wchar_t);
}
+ // add the 2 terminating 0 (actually 4, just to be on the safe side)
+ envlist.resize( envlist.size()+4 );
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
}
return envlist;
}
@@ -382,7 +362,9 @@ void QProcessPrivate::startProcess()
QString args = qt_create_commandline(QString(), arguments);
#else
QString args = qt_create_commandline(program, arguments);
- QByteArray envlist = qt_create_environment(environment);
+ QByteArray envlist;
+ if (environment.d.constData())
+ envlist = qt_create_environment(environment.d.constData()->hash);
#endif
#if defined QPROCESS_DEBUG
@@ -392,58 +374,35 @@ void QProcessPrivate::startProcess()
qDebug(" pass environment : %s", environment.isEmpty() ? "no" : "yes");
#endif
- DWORD dwCreationFlags = 0;
- if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based))
- dwCreationFlags |= CREATE_NO_WINDOW;
-
-#ifdef UNICODE
- if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) {
#if defined(Q_OS_WINCE)
- QString fullPathProgram = program;
- if (!QDir::isAbsolutePath(fullPathProgram))
- fullPathProgram = QFileInfo(fullPathProgram).absoluteFilePath();
- fullPathProgram.replace(QLatin1String("/"), QLatin1String("\\"));
- success = CreateProcessW((WCHAR*)fullPathProgram.utf16(),
- (WCHAR*)args.utf16(),
- 0, 0, false, 0, 0, 0, 0, pid);
+ QString fullPathProgram = program;
+ if (!QDir::isAbsolutePath(fullPathProgram))
+ fullPathProgram = QFileInfo(fullPathProgram).absoluteFilePath();
+ fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\'));
+ success = CreateProcess((wchar_t*)fullPathProgram.utf16(),
+ (wchar_t*)args.utf16(),
+ 0, 0, false, 0, 0, 0, 0, pid);
#else
- dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
- STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
- (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
- (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
- 0, 0, 0,
- STARTF_USESTDHANDLES,
- 0, 0, 0,
- stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1]
- };
- success = CreateProcessW(0, (WCHAR*)args.utf16(),
- 0, 0, TRUE, dwCreationFlags,
- environment.isEmpty() ? 0 : envlist.data(),
- workingDirectory.isEmpty() ? 0
- : (WCHAR*)QDir::toNativeSeparators(workingDirectory).utf16(),
- &startupInfo, pid);
-#endif
- } else
-#endif // UNICODE
- {
-#ifndef Q_OS_WINCE
- STARTUPINFOA startupInfo = { sizeof( STARTUPINFOA ), 0, 0, 0,
- (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
- (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
- 0, 0, 0,
- STARTF_USESTDHANDLES,
- 0, 0, 0,
- stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1]
- };
-
- success = CreateProcessA(0, args.toLocal8Bit().data(),
- 0, 0, TRUE, dwCreationFlags, environment.isEmpty() ? 0 : envlist.data(),
- workingDirectory.isEmpty() ? 0
- : QDir::toNativeSeparators(workingDirectory).toLocal8Bit().data(),
- &startupInfo, pid);
-#endif // Q_OS_WINCE
+ DWORD dwCreationFlags = CREATE_NO_WINDOW;
+ dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
+ STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
+ (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
+ (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
+ 0, 0, 0,
+ STARTF_USESTDHANDLES,
+ 0, 0, 0,
+ stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1]
+ };
+ success = CreateProcess(0, (wchar_t*)args.utf16(),
+ 0, 0, TRUE, dwCreationFlags,
+ environment.isEmpty() ? 0 : envlist.data(),
+ workingDirectory.isEmpty() ? 0 : (wchar_t*)QDir::toNativeSeparators(workingDirectory).utf16(),
+ &startupInfo, pid);
+ if (!success) {
+ // Capture the error string before we do CloseHandle below
+ q->setErrorString(QProcess::tr("Process failed to start: %1").arg(qt_error_string()));
}
-#ifndef Q_OS_WINCE
+
if (stdinChannel.pipe[0] != INVALID_Q_PIPE) {
CloseHandle(stdinChannel.pipe[0]);
stdinChannel.pipe[0] = INVALID_Q_PIPE;
@@ -461,7 +420,6 @@ void QProcessPrivate::startProcess()
if (!success) {
cleanup();
processError = QProcess::FailedToStart;
- q->setErrorString(QProcess::tr("Process failed to start"));
emit q->error(processError);
q->setProcessState(QProcess::NotRunning);
return;
@@ -483,7 +441,7 @@ void QProcessPrivate::startProcess()
}
// give the process a chance to start ...
- Sleep(SLEEPMIN*2);
+ Sleep(SLEEPMIN * 2);
_q_startupNotification();
}
@@ -857,42 +815,25 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
PROCESS_INFORMATION pinfo;
-#ifdef UNICODE
- if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) {
#if defined(Q_OS_WINCE)
QString fullPathProgram = program;
if (!QDir::isAbsolutePath(fullPathProgram))
- fullPathProgram.prepend(QDir::currentPath().append(QLatin1String("/")));
- fullPathProgram.replace(QLatin1String("/"), QLatin1String("\\"));
- success = CreateProcessW((WCHAR*)fullPathProgram.utf16(),
- (WCHAR*)args.utf16(),
- 0, 0, false, CREATE_NEW_CONSOLE, 0, 0, 0, &pinfo);
+ fullPathProgram.prepend(QDir::currentPath().append(QLatin1Char('/')));
+ fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\'));
+ success = CreateProcess((wchar_t*)fullPathProgram.utf16(),
+ (wchar_t*)args.utf16(),
+ 0, 0, false, CREATE_NEW_CONSOLE, 0, 0, 0, &pinfo);
#else
STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
- success = CreateProcessW(0, (WCHAR*)args.utf16(),
- 0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, 0,
- workingDir.isEmpty() ? (const WCHAR *)0 : (const WCHAR *)workingDir.utf16(),
- &startupInfo, &pinfo);
-#endif
- } else
-#endif // UNICODE
- {
-#ifndef Q_OS_WINCE
- STARTUPINFOA startupInfo = { sizeof( STARTUPINFOA ), 0, 0, 0,
- (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
- (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- success = CreateProcessA(0, args.toLocal8Bit().data(),
- 0, 0, FALSE, CREATE_NEW_CONSOLE, 0,
- workingDir.isEmpty() ? (LPCSTR)0 : workingDir.toLocal8Bit().constData(),
+ success = CreateProcess(0, (wchar_t*)args.utf16(),
+ 0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, 0,
+ workingDir.isEmpty() ? 0 : (wchar_t*)workingDir.utf16(),
&startupInfo, &pinfo);
#endif // Q_OS_WINCE
- }
if (success) {
CloseHandle(pinfo.hThread);
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index a66bdba..7b1244f 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -56,10 +56,54 @@
#include <qplatformdefs.h>
#include "private/qabstractfileengine_p.h"
+#ifdef Q_OS_UNIX
+# include "private/qcore_unix_p.h"
+#endif
+
//#define DEBUG_RESOURCE_MATCH
+#if defined(Q_OS_VXWORKS)
+# if defined(m_data)
+# undef m_data
+# endif
+# if defined(m_len)
+# undef m_len
+# endif
+#endif
+
QT_BEGIN_NAMESPACE
+
+class QStringSplitter
+{
+public:
+ QStringSplitter(const QString &s)
+ : m_string(s), m_data(m_string.constData()), m_len(s.length()), m_pos(0)
+ {
+ m_splitChar = QLatin1Char('/');
+ }
+
+ inline bool hasNext() {
+ while (m_pos < m_len && m_data[m_pos] == m_splitChar)
+ ++m_pos;
+ return m_pos < m_len;
+ }
+
+ inline QStringRef next() {
+ int start = m_pos;
+ while (m_pos < m_len && m_data[m_pos] != m_splitChar)
+ ++m_pos;
+ return QStringRef(&m_string, start, m_pos - start);
+ }
+
+ QString m_string;
+ const QChar *m_data;
+ QChar m_splitChar;
+ int m_len;
+ int m_pos;
+};
+
+
//resource glue
class QResourceRoot
{
@@ -101,6 +145,16 @@ protected:
}
};
+static QString cleanPath(const QString &_path)
+{
+ QString path = QDir::cleanPath(_path);
+ // QDir::cleanPath does not remove two trailing slashes under _Windows_
+ // due to support for UNC paths. Remove those manually.
+ if (path.startsWith(QLatin1String("//")))
+ path.remove(0, 1);
+ return path;
+}
+
Q_DECLARE_TYPEINFO(QResourceRoot, Q_MOVABLE_TYPE);
Q_GLOBAL_STATIC_WITH_ARGS(QMutex, resourceMutex, (QMutex::Recursive))
@@ -115,7 +169,7 @@ Q_GLOBAL_STATIC(QStringList, resourceSearchPaths)
\brief The QResource class provides an interface for reading directly from resources.
\ingroup io
- \mainclass
+
\reentrant
\since 4.2
@@ -216,9 +270,10 @@ QResourcePrivate::load(const QString &file)
related.clear();
QMutexLocker lock(resourceMutex());
const ResourceList *list = resourceList();
+ QString cleaned = cleanPath(file);
for(int i = 0; i < list->size(); ++i) {
QResourceRoot *res = list->at(i);
- const int node = res->findNode(file);
+ const int node = res->findNode(cleaned);
if(node != -1) {
if(related.isEmpty()) {
container = res->isContainer(node);
@@ -263,9 +318,8 @@ QResourcePrivate::ensureInitialized() const
if(path.startsWith(QLatin1Char(':')))
path = path.mid(1);
- bool found = false;
if(path.startsWith(QLatin1Char('/'))) {
- found = that->load(path);
+ that->load(path);
} else {
QMutexLocker lock(resourceMutex());
QStringList searchPaths = *resourceSearchPaths();
@@ -273,7 +327,6 @@ QResourcePrivate::ensureInitialized() const
for(int i = 0; i < searchPaths.size(); ++i) {
const QString searchPath(searchPaths.at(i) + QLatin1Char('/') + path);
if(that->load(searchPath)) {
- found = true;
that->absoluteFilePath = QLatin1Char(':') + searchPath;
break;
}
@@ -292,6 +345,7 @@ QResourcePrivate::ensureChildren() const
if(path.startsWith(QLatin1Char(':')))
path = path.mid(1);
QSet<QString> kids;
+ QString cleaned = cleanPath(path);
for(int i = 0; i < related.size(); ++i) {
QResourceRoot *res = related.at(i);
if(res->mappingRootSubdir(path, &k) && !k.isEmpty()) {
@@ -300,7 +354,7 @@ QResourcePrivate::ensureChildren() const
kids.insert(k);
}
} else {
- const int node = res->findNode(path);
+ const int node = res->findNode(cleaned);
if(node != -1) {
QStringList related_children = res->children(node);
for(int kid = 0; kid < related_children.size(); ++kid) {
@@ -334,7 +388,6 @@ QResource::QResource(const QString &file, const QLocale &locale) : d_ptr(new QRe
*/
QResource::~QResource()
{
- delete d_ptr;
}
/*!
@@ -528,7 +581,7 @@ QResource::addSearchPath(const QString &path)
Returns the current search path list. This list is consulted when
creating a relative resource.
- \sa addSearchPath()
+ \sa QDir::addSearchPath() QDir::setSearchPaths()
*/
QStringList
@@ -562,30 +615,32 @@ inline QString QResourceRoot::name(int node) const
(names[name_offset+1] << 0);
name_offset += 2;
name_offset += 4; //jump past hash
- for(int i = 0; i < name_length*2; i+=2)
- ret += QChar(names[name_offset+i+1], names[name_offset+i]);
+
+ ret.resize(name_length);
+ QChar *strData = ret.data();
+ for(int i = 0; i < name_length*2; i+=2) {
+ QChar c(names[name_offset+i+1], names[name_offset+i]);
+ *strData = c;
+ ++strData;
+ }
return ret;
}
+
int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const
{
- QString path = QDir::cleanPath(_path);
- // QDir::cleanPath does not remove two trailing slashes under _Windows_
- // due to support for UNC paths. Remove those manually.
- if (path.startsWith(QLatin1String("//")))
- path.remove(0, 1);
-
+ QString path = _path;
{
QString root = mappingRoot();
if(!root.isEmpty()) {
if(root == path) {
- path = QLatin1String("/");
+ path = QLatin1Char('/');
} else {
- if(!root.endsWith(QLatin1String("/")))
- root += QLatin1String("/");
+ if(!root.endsWith(QLatin1Char('/')))
+ root += QLatin1Char('/');
if(path.size() >= root.size() && path.startsWith(root))
path = path.mid(root.length()-1);
if(path.isEmpty())
- path = QLatin1String("/");
+ path = QLatin1Char('/');
}
}
}
@@ -604,12 +659,11 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const
//now iterate up the tree
int node = -1;
- QStringList segments = path.split(QLatin1Char('/'), QString::SkipEmptyParts);
-#ifdef DEBUG_RESOURCE_MATCH
- qDebug() << "****" << segments;
-#endif
- for(int i = 0; child_count && i < segments.size(); ++i) {
- const QString &segment = segments[i];
+
+ QStringSplitter splitter(path);
+ while (child_count && splitter.hasNext()) {
+ QStringRef segment = splitter.next();
+
#ifdef DEBUG_RESOURCE_MATCH
qDebug() << " CHILDREN" << segment;
for(int j = 0; j < child_count; ++j) {
@@ -651,7 +705,7 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const
(tree[offset+1] << 0);
offset += 2;
- if(i == segments.size()-1) {
+ if(!splitter.hasNext()) {
if(!(flags & Directory)) {
const short country = (tree[offset+0] << 8) +
(tree[offset+1] << 0);
@@ -1431,11 +1485,7 @@ uchar *QResourceFileEnginePrivate::map(qint64 offset, qint64 size, QFile::Memory
{
Q_Q(QResourceFileEngine);
Q_UNUSED(flags);
- if (!resource.isValid()
- || offset < 0
- || size < 0
- || offset + size > resource.size()
- || (size == 0)) {
+ if (offset < 0 || size <= 0 || !resource.isValid() || offset + size > resource.size()) {
q->setError(QFile::UnspecifiedError, QString());
return 0;
}
diff --git a/src/corelib/io/qresource.h b/src/corelib/io/qresource.h
index 020036b..676464f 100644
--- a/src/corelib/io/qresource.h
+++ b/src/corelib/io/qresource.h
@@ -91,7 +91,7 @@ protected:
QStringList children() const;
protected:
- QResourcePrivate *d_ptr;
+ QScopedPointer<QResourcePrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(QResource)
diff --git a/src/corelib/io/qresource_iterator.cpp b/src/corelib/io/qresource_iterator.cpp
index 02e018d..f1a77af 100644
--- a/src/corelib/io/qresource_iterator.cpp
+++ b/src/corelib/io/qresource_iterator.cpp
@@ -73,13 +73,11 @@ bool QResourceFileEngineIterator::hasNext() const
return false;
// Initialize and move to the next entry.
- QResourceFileEngineIterator *that = const_cast<QResourceFileEngineIterator *>(this);
- that->entries = resource.children();
- if (!that->entries.isEmpty())
- that->index = 0;
+ entries = resource.children();
+ index = 0;
}
- return index <= entries.size();
+ return index < entries.size();
}
QString QResourceFileEngineIterator::currentFileName() const
diff --git a/src/corelib/io/qresource_iterator_p.h b/src/corelib/io/qresource_iterator_p.h
index 6b1276e..ef1fb21 100644
--- a/src/corelib/io/qresource_iterator_p.h
+++ b/src/corelib/io/qresource_iterator_p.h
@@ -71,8 +71,8 @@ public:
QString currentFileName() const;
private:
- QStringList entries;
- int index;
+ mutable QStringList entries;
+ mutable int index;
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index 77a0a3d..48671ba 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -74,6 +74,10 @@
#endif // Q_OS_WIN
#endif // QT_NO_QOBJECT
+#ifdef Q_OS_VXWORKS
+# include <ioLib.h>
+#endif
+
#include <stdlib.h>
#ifndef CSIDL_COMMON_APPDATA
@@ -167,7 +171,7 @@ static bool isLikelyToBeNfs(int handle)
}
#elif defined(Q_OS_SOLARIS) || defined(Q_OS_IRIX) || defined(Q_OS_AIX) || defined(Q_OS_HPUX) \
- || defined(Q_OS_OSF) || defined(Q_OS_QNX) || defined(Q_OS_QNX6) || defined(Q_OS_SCO) \
+ || defined(Q_OS_OSF) || defined(Q_OS_QNX) || defined(Q_OS_SCO) \
|| defined(Q_OS_UNIXWARE) || defined(Q_OS_RELIANT) || defined(Q_OS_NETBSD)
QT_BEGIN_INCLUDE_NAMESPACE
# include <sys/statvfs.h>
@@ -217,6 +221,12 @@ QConfFile::QConfFile(const QString &fileName, bool _userPerms)
usedHashFunc()->insert(name, this);
}
+QConfFile::~QConfFile()
+{
+ if (usedHashFunc())
+ usedHashFunc()->remove(name);
+}
+
ParsedSettingsMap QConfFile::mergedKeyMap() const
{
ParsedSettingsMap result = originalKeys;
@@ -263,7 +273,7 @@ QConfFile *QConfFile::fromName(const QString &fileName, bool _userPerms)
ConfFileHash *usedHash = usedHashFunc();
ConfFileCache *unusedCache = unusedCacheFunc();
- QConfFile *confFile;
+ QConfFile *confFile = 0;
QMutexLocker locker(globalMutex());
if (!(confFile = usedHash->value(absPath))) {
@@ -1037,33 +1047,16 @@ static QString windowsConfigPath(int type)
// This only happens when bootstrapping qmake.
#ifndef Q_OS_WINCE
QLibrary library(QLatin1String("shell32"));
- QT_WA( {
- typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPTSTR, int, BOOL);
- GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve("SHGetSpecialFolderPathW");
- if (SHGetSpecialFolderPath) {
- TCHAR path[MAX_PATH];
- SHGetSpecialFolderPath(0, path, type, FALSE);
- result = QString::fromUtf16((ushort*)path);
- }
- } , {
- typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, char*, int, BOOL);
- GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve("SHGetSpecialFolderPathA");
- if (SHGetSpecialFolderPath) {
- char path[MAX_PATH];
- SHGetSpecialFolderPath(0, path, type, FALSE);
- result = QString::fromLocal8Bit(path);
- }
- } );
#else
QLibrary library(QLatin1String("coredll"));
- typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPTSTR, int, BOOL);
- GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve("SHGetSpecialFolderPath");
+#endif // Q_OS_WINCE
+ typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPWSTR, int, BOOL);
+ GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve("SHGetSpecialFolderPathW");
if (SHGetSpecialFolderPath) {
wchar_t path[MAX_PATH];
SHGetSpecialFolderPath(0, path, type, FALSE);
- result = QString::fromUtf16((ushort*)path);
+ result = QString::fromWCharArray(path);
}
-#endif // Q_OS_WINCE
#endif // QT_NO_QOBJECT
@@ -1106,10 +1099,10 @@ static QString getPath(QSettings::Format format, QSettings::Scope scope)
QString homePath = QDir::homePath();
QString systemPath;
- globalMutex()->lock();
+ QMutexLocker locker(globalMutex());
PathHash *pathHash = pathHashFunc();
bool loadSystemPath = pathHash->isEmpty();
- globalMutex()->unlock();
+ locker.unlock();
if (loadSystemPath) {
/*
@@ -1121,7 +1114,7 @@ static QString getPath(QSettings::Format format, QSettings::Scope scope)
systemPath += QLatin1Char('/');
}
- QMutexLocker locker(globalMutex());
+ locker.relock();
if (pathHash->isEmpty()) {
/*
Lazy initialization of pathHash. We initialize the
@@ -1181,9 +1174,6 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
int i;
initFormat();
- for (i = 0; i < NumConfFiles; ++i)
- confFiles[i] = 0;
-
QString org = organization;
if (org.isEmpty()) {
setStatus(QSettings::AccessError);
@@ -1196,14 +1186,14 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
if (scope == QSettings::UserScope) {
QString userPath = getPath(format, QSettings::UserScope);
if (!application.isEmpty())
- confFiles[F_User | F_Application] = QConfFile::fromName(userPath + appFile, true);
- confFiles[F_User | F_Organization] = QConfFile::fromName(userPath + orgFile, true);
+ confFiles[F_User | F_Application].reset(QConfFile::fromName(userPath + appFile, true));
+ confFiles[F_User | F_Organization].reset(QConfFile::fromName(userPath + orgFile, true));
}
QString systemPath = getPath(format, QSettings::SystemScope);
if (!application.isEmpty())
- confFiles[F_System | F_Application] = QConfFile::fromName(systemPath + appFile, false);
- confFiles[F_System | F_Organization] = QConfFile::fromName(systemPath + orgFile, false);
+ confFiles[F_System | F_Application].reset(QConfFile::fromName(systemPath + appFile, false));
+ confFiles[F_System | F_Organization].reset(QConfFile::fromName(systemPath + orgFile, false));
for (i = 0; i < NumConfFiles; ++i) {
if (confFiles[i]) {
@@ -1222,9 +1212,7 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
{
initFormat();
- confFiles[0] = QConfFile::fromName(fileName, true);
- for (int i = 1; i < NumConfFiles; ++i)
- confFiles[i] = 0;
+ confFiles[0].reset(QConfFile::fromName(fileName, true));
initAccess();
}
@@ -1237,23 +1225,30 @@ QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
for (int i = 0; i < NumConfFiles; ++i) {
if (confFiles[i] && !confFiles[i]->ref.deref()) {
- if (usedHash)
- usedHash->remove(confFiles[i]->name);
-
if (confFiles[i]->size == 0) {
- delete confFiles[i];
+ delete confFiles[i].take();
} else if (unusedCache) {
- // compute a better size?
- unusedCache->insert(confFiles[i]->name, confFiles[i],
+ if (usedHash)
+ usedHash->remove(confFiles[i]->name);
+ QT_TRY {
+ // compute a better size?
+ unusedCache->insert(confFiles[i]->name, confFiles[i].data(),
10 + (confFiles[i]->originalKeys.size() / 4));
+ confFiles[i].take();
+ } QT_CATCH(...) {
+ // out of memory. Do not cache the file.
+ delete confFiles[i].take();
+ }
}
}
+ // prevent the ScopedPointer to deref it again.
+ confFiles[i].take();
}
}
void QConfFileSettingsPrivate::remove(const QString &key)
{
- QConfFile *confFile = confFiles[spec];
+ QConfFile *confFile = confFiles[spec].data();
if (!confFile)
return;
@@ -1280,7 +1275,7 @@ void QConfFileSettingsPrivate::remove(const QString &key)
void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
{
- QConfFile *confFile = confFiles[spec];
+ QConfFile *confFile = confFiles[spec].data();
if (!confFile)
return;
@@ -1297,7 +1292,7 @@ bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const
bool found = false;
for (int i = 0; i < NumConfFiles; ++i) {
- if (QConfFile *confFile = confFiles[i]) {
+ if (QConfFile *confFile = confFiles[i].data()) {
QMutexLocker locker(&confFile->mutex);
if (!confFile->addedKeys.isEmpty()) {
@@ -1332,7 +1327,7 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
int startPos = prefix.size();
for (int i = 0; i < NumConfFiles; ++i) {
- if (QConfFile *confFile = confFiles[i]) {
+ if (QConfFile *confFile = confFiles[i].data()) {
QMutexLocker locker(&confFile->mutex);
if (thePrefix.isEmpty()) {
@@ -1365,7 +1360,7 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
void QConfFileSettingsPrivate::clear()
{
- QConfFile *confFile = confFiles[spec];
+ QConfFile *confFile = confFiles[spec].data();
if (!confFile)
return;
@@ -1381,7 +1376,7 @@ void QConfFileSettingsPrivate::sync()
// error we just try to go on and make the best of it
for (int i = 0; i < NumConfFiles; ++i) {
- QConfFile *confFile = confFiles[i];
+ QConfFile *confFile = confFiles[i].data();
if (confFile) {
QMutexLocker locker(&confFile->mutex);
syncConfFile(i);
@@ -1396,7 +1391,7 @@ void QConfFileSettingsPrivate::flush()
QString QConfFileSettingsPrivate::fileName() const
{
- QConfFile *confFile = confFiles[spec];
+ QConfFile *confFile = confFiles[spec].data();
if (!confFile)
return QString();
return confFile->name;
@@ -1407,7 +1402,7 @@ bool QConfFileSettingsPrivate::isWritable() const
if (format > QSettings::IniFormat && !writeFunc)
return false;
- QConfFile *confFile = confFiles[spec];
+ QConfFile *confFile = confFiles[spec].data();
if (!confFile)
return false;
@@ -1416,7 +1411,7 @@ bool QConfFileSettingsPrivate::isWritable() const
void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
{
- QConfFile *confFile = confFiles[confFileNo];
+ QConfFile *confFile = confFiles[confFileNo].data();
bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
bool ok;
@@ -1459,11 +1454,7 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
QString writeSemName = QLatin1String("QSettingsWriteSem ");
writeSemName.append(file.fileName());
- QT_WA( {
- writeSemaphore = CreateSemaphoreW(0, 1, 1, reinterpret_cast<const wchar_t *>(writeSemName.utf16()));
- } , {
- writeSemaphore = CreateSemaphoreA(0, 1, 1, writeSemName.toLocal8Bit());
- } );
+ writeSemaphore = CreateSemaphore(0, 1, 1, reinterpret_cast<const wchar_t *>(writeSemName.utf16()));
if (writeSemaphore) {
WaitForSingleObject(writeSemaphore, INFINITE);
@@ -1479,11 +1470,7 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
QString readSemName(QLatin1String("QSettingsReadSem "));
readSemName.append(file.fileName());
- QT_WA( {
- readSemaphore = CreateSemaphoreW(0, FileLockSemMax, FileLockSemMax, reinterpret_cast<const wchar_t *>(readSemName.utf16()));
- } , {
- readSemaphore = CreateSemaphoreA(0, FileLockSemMax, FileLockSemMax, readSemName.toLocal8Bit());
- } );
+ readSemaphore = CreateSemaphore(0, FileLockSemMax, FileLockSemMax, reinterpret_cast<const wchar_t *>(readSemName.utf16()));
if (readSemaphore) {
for (int i = 0; i < numReadLocks; ++i)
@@ -2025,8 +2012,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\brief The QSettings class provides persistent platform-independent application settings.
\ingroup io
- \ingroup misc
- \mainclass
+
\reentrant
Users normally expect an application to remember its settings
@@ -2132,12 +2118,12 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
Custom types registered using qRegisterMetaType() and
qRegisterMetaTypeStreamOperators() can be stored using QSettings.
- \section1 Key Syntax
+ \section1 Section and Key Syntax
Setting keys can contain any Unicode characters. The Windows
registry and INI files use case-insensitive keys, whereas the
Carbon Preferences API on Mac OS X uses case-sensitive keys. To
- avoid portability problems, follow these two simple rules:
+ avoid portability problems, follow these simple rules:
\list 1
\o Always refer to the same key using the same case. For example,
@@ -2148,7 +2134,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
example, if you have a key called "MainWindow", don't try to
save another key as "mainwindow".
- \o Do not use slashes ('/' and '\\') in key names; the
+ \o Do not use slashes ('/' and '\\') in section or key names; the
backslash character is used to separate sub keys (see below). On
windows '\\' are converted by QSettings to '/', which makes
them identical.
@@ -2759,11 +2745,13 @@ QSettings::QSettings(const QString &fileName, Format format)
QSettings::~QSettings()
{
Q_D(QSettings);
- if (d->pendingChanges)
- d->flush();
-#ifdef QT_NO_QOBJECT
- delete d;
-#endif
+ if (d->pendingChanges) {
+ QT_TRY {
+ d->flush();
+ } QT_CATCH(...) {
+ ; // ok. then don't flush but at least don't throw in the destructor
+ }
+ }
}
/*!
@@ -3211,8 +3199,8 @@ bool QSettings::isWritable() const
Note that the Windows registry and INI files use case-insensitive
keys, whereas the Carbon Preferences API on Mac OS X uses
- case-sensitive keys. To avoid portability problems, see the \l{Key
- Syntax} rules.
+ case-sensitive keys. To avoid portability problems, see the
+ \l{Section and Key Syntax} rules.
Example:
@@ -3246,8 +3234,8 @@ void QSettings::setValue(const QString &key, const QVariant &value)
Note that the Windows registry and INI files use case-insensitive
keys, whereas the Carbon Preferences API on Mac OS X uses
- case-sensitive keys. To avoid portability problems, see the \l{Key
- Syntax} rules.
+ case-sensitive keys. To avoid portability problems, see the
+ \l{Section and Key Syntax} rules.
\sa setValue(), value(), contains()
*/
@@ -3281,8 +3269,8 @@ void QSettings::remove(const QString &key)
Note that the Windows registry and INI files use case-insensitive
keys, whereas the Carbon Preferences API on Mac OS X uses
- case-sensitive keys. To avoid portability problems, see the \l{Key
- Syntax} rules.
+ case-sensitive keys. To avoid portability problems, see the
+ \l{Section and Key Syntax} rules.
\sa value(), setValue()
*/
@@ -3343,8 +3331,8 @@ bool QSettings::event(QEvent *event)
Note that the Windows registry and INI files use case-insensitive
keys, whereas the Carbon Preferences API on Mac OS X uses
- case-sensitive keys. To avoid portability problems, see the \l{Key
- Syntax} rules.
+ case-sensitive keys. To avoid portability problems, see the
+ \l{Section and Key Syntax} rules.
Example:
@@ -3566,8 +3554,7 @@ void QSettings::setPath_helper(Scope scope, const QString &organization, const Q
QSettingsPrivate *oldPriv = d;
QSettingsPrivate *newPriv = QSettingsPrivate::create(oldPriv->format, scope, organization, application);
static_cast<QObjectPrivate &>(*newPriv) = static_cast<QObjectPrivate &>(*oldPriv); // copy the QObject stuff over (hack)
- delete oldPriv;
- d_ptr = newPriv;
+ d_ptr.reset(newPriv);
}
/*! \fn bool QSettings::writeEntry(const QString &key, bool value)
diff --git a/src/corelib/io/qsettings.h b/src/corelib/io/qsettings.h
index ff92d1a..4c9953a 100644
--- a/src/corelib/io/qsettings.h
+++ b/src/corelib/io/qsettings.h
@@ -78,7 +78,7 @@ class Q_CORE_EXPORT QSettings
#ifndef QT_NO_QOBJECT
Q_OBJECT
#else
- QSettingsPrivate *d_ptr;
+ QScopedPointer<QSettingsPrivate> d_ptr;
#endif
Q_DECLARE_PRIVATE(QSettings)
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index 24536b0..dc1beb3 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -146,9 +146,11 @@ inline QString QSettingsGroup::toString() const
return result;
}
-class Q_CORE_EXPORT QConfFile
+class Q_AUTOTEST_EXPORT QConfFile
{
public:
+ ~QConfFile();
+
ParsedSettingsMap mergedKeyMap() const;
bool isWritable() const;
@@ -300,7 +302,7 @@ private:
void ensureAllSectionsParsed(QConfFile *confFile) const;
void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const;
- QConfFile *confFiles[NumConfFiles];
+ QScopedSharedPointer<QConfFile> confFiles[NumConfFiles];
QSettings::ReadFunc readFunc;
QSettings::WriteFunc writeFunc;
QString extension;
diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp
index 9587ea3..b7933e8 100644
--- a/src/corelib/io/qsettings_win.cpp
+++ b/src/corelib/io/qsettings_win.cpp
@@ -130,25 +130,14 @@ static void mergeKeySets(NameSet *dest, const QStringList &src)
static QString errorCodeToString(DWORD errorCode)
{
- QString result;
- QT_WA({
- wchar_t *data = 0;
- FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- 0, errorCode, 0,
- data, 0, 0);
- result = QString::fromUtf16(reinterpret_cast<const ushort *> (data));
- if (data != 0)
- LocalFree(data);
- }, {
- char *data = 0;
- FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- 0, errorCode, 0,
- (char *)&data, 0, 0);
- result = QString::fromLocal8Bit(data);
- if (data != 0)
- LocalFree(data);
- })
- if (result.endsWith(QLatin1String("\n")))
+ wchar_t *data = 0;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, data, 0, 0);
+ QString result = QString::fromWCharArray(data);
+
+ if (data != 0)
+ LocalFree(data);
+
+ if (result.endsWith(QLatin1Char('\n')))
result.truncate(result.length() - 1);
return result;
@@ -158,15 +147,8 @@ static QString errorCodeToString(DWORD errorCode)
static HKEY openKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey)
{
HKEY resultHandle = 0;
-
- LONG res;
- QT_WA( {
- res = RegOpenKeyExW(parentHandle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()),
- 0, perms, &resultHandle);
- } , {
- res = RegOpenKeyExA(parentHandle, rSubKey.toLocal8Bit(),
+ LONG res = RegOpenKeyEx(parentHandle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()),
0, perms, &resultHandle);
- } );
if (res == ERROR_SUCCESS)
return resultHandle;
@@ -183,14 +165,8 @@ static HKEY createOrOpenKey(HKEY parentHandle, REGSAM perms, const QString &rSub
return resultHandle;
// try to create it
- LONG res;
- QT_WA( {
- res = RegCreateKeyExW(parentHandle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()), 0, 0,
- REG_OPTION_NON_VOLATILE, perms, 0, &resultHandle, 0);
- } , {
- res = RegCreateKeyExA(parentHandle, rSubKey.toLocal8Bit(), 0, 0,
+ LONG res = RegCreateKeyEx(parentHandle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()), 0, 0,
REG_OPTION_NON_VOLATILE, perms, 0, &resultHandle, 0);
- } );
if (res == ERROR_SUCCESS)
return resultHandle;
@@ -225,20 +201,14 @@ static HKEY createOrOpenKey(HKEY parentHandle, const QString &rSubKey, bool *rea
static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildSpec spec)
{
QStringList result;
- LONG res;
DWORD numKeys;
DWORD maxKeySize;
DWORD numSubgroups;
DWORD maxSubgroupSize;
// Find the number of keys and subgroups, as well as the max of their lengths.
- QT_WA( {
- res = RegQueryInfoKeyW(parentHandle, 0, 0, 0, &numSubgroups, &maxSubgroupSize, 0,
+ LONG res = RegQueryInfoKey(parentHandle, 0, 0, 0, &numSubgroups, &maxSubgroupSize, 0,
&numKeys, &maxKeySize, 0, 0, 0);
- }, {
- res = RegQueryInfoKeyA(parentHandle, 0, 0, 0, &numSubgroups, &maxSubgroupSize, 0,
- &numKeys, &maxKeySize, 0, 0, 0);
- } );
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegQueryInfoKey() failed: %s", errorCodeToString(res).toLatin1().data());
@@ -258,36 +228,21 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS
m = maxSubgroupSize;
}
- /* Windows NT/2000/XP: The size does not include the terminating null character.
- Windows Me/98/95: The size includes the terminating null character. */
+ /* The size does not include the terminating null character. */
++m;
// Get the list
- QByteArray buff(m*sizeof(ushort), 0);
+ QByteArray buff(m * sizeof(wchar_t), 0);
for (int i = 0; i < n; ++i) {
QString item;
- QT_WA( {
- DWORD l = buff.size() / sizeof(ushort);
- if (spec == QSettingsPrivate::ChildKeys) {
- res = RegEnumValueW(parentHandle, i,
- reinterpret_cast<wchar_t *>(buff.data()),
- &l, 0, 0, 0, 0);
- } else {
- res = RegEnumKeyExW(parentHandle, i,
- reinterpret_cast<wchar_t *>(buff.data()),
- &l, 0, 0, 0, 0);
- }
- if (res == ERROR_SUCCESS)
- item = QString::fromUtf16(reinterpret_cast<ushort*>(buff.data()), l);
- }, {
- DWORD l = buff.size();
- if (spec == QSettingsPrivate::ChildKeys)
- res = RegEnumValueA(parentHandle, i, buff.data(), &l, 0, 0, 0, 0);
- else
- res = RegEnumKeyExA(parentHandle, i, buff.data(), &l, 0, 0, 0, 0);
- if (res == ERROR_SUCCESS)
- item = QString::fromLocal8Bit(buff.data(), l);
- } );
+ DWORD l = buff.size() / sizeof(wchar_t);
+ if (spec == QSettingsPrivate::ChildKeys) {
+ res = RegEnumValue(parentHandle, i, reinterpret_cast<wchar_t *>(buff.data()), &l, 0, 0, 0, 0);
+ } else {
+ res = RegEnumKeyEx(parentHandle, i, reinterpret_cast<wchar_t *>(buff.data()), &l, 0, 0, 0, 0);
+ }
+ if (res == ERROR_SUCCESS)
+ item = QString::fromWCharArray((const wchar_t *)buff.constData(), l);
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegEnumValue failed: %s", errorCodeToString(res).toLatin1().data());
@@ -342,12 +297,7 @@ static void deleteChildGroups(HKEY parentHandle)
RegCloseKey(childGroupHandle);
// delete group itself
- LONG res;
- QT_WA( {
- res = RegDeleteKeyW(parentHandle, reinterpret_cast<const wchar_t *>(group.utf16()));
- }, {
- res = RegDeleteKeyA(parentHandle, group.toLocal8Bit());
- } );
+ LONG res = RegDeleteKey(parentHandle, reinterpret_cast<const wchar_t *>(group.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteKey failed on subkey \"%s\": %s",
group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
@@ -519,12 +469,7 @@ bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVa
// get the size and type of the value
DWORD dataType;
DWORD dataSize;
- LONG res;
- QT_WA( {
- res = RegQueryValueExW(handle, reinterpret_cast<const wchar_t *>(rSubkeyName.utf16()), 0, &dataType, 0, &dataSize);
- }, {
- res = RegQueryValueExA(handle, rSubkeyName.toLocal8Bit(), 0, &dataType, 0, &dataSize);
- } );
+ LONG res = RegQueryValueEx(handle, reinterpret_cast<const wchar_t *>(rSubkeyName.utf16()), 0, &dataType, 0, &dataSize);
if (res != ERROR_SUCCESS) {
RegCloseKey(handle);
return false;
@@ -532,13 +477,8 @@ bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVa
// get the value
QByteArray data(dataSize, 0);
- QT_WA( {
- res = RegQueryValueExW(handle, reinterpret_cast<const wchar_t *>(rSubkeyName.utf16()), 0, 0,
- reinterpret_cast<unsigned char*>(data.data()), &dataSize);
- }, {
- res = RegQueryValueExA(handle, rSubkeyName.toLocal8Bit(), 0, 0,
- reinterpret_cast<unsigned char*>(data.data()), &dataSize);
- } );
+ res = RegQueryValueEx(handle, reinterpret_cast<const wchar_t *>(rSubkeyName.utf16()), 0, 0,
+ reinterpret_cast<unsigned char*>(data.data()), &dataSize);
if (res != ERROR_SUCCESS) {
RegCloseKey(handle);
return false;
@@ -549,11 +489,7 @@ bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVa
case REG_SZ: {
QString s;
if (dataSize) {
- QT_WA( {
- s = QString::fromUtf16(((const ushort*)data.constData()));
- }, {
- s = QString::fromLocal8Bit(data.constData());
- } );
+ s = QString::fromWCharArray(((const wchar_t *)data.constData()));
}
if (value != 0)
*value = stringToVariant(s);
@@ -565,12 +501,7 @@ bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVa
if (dataSize) {
int i = 0;
for (;;) {
- QString s;
- QT_WA( {
- s = QString::fromUtf16((const ushort*)data.constData() + i);
- }, {
- s = QString::fromLocal8Bit(data.constData() + i);
- } );
+ QString s = QString::fromWCharArray((const wchar_t *)data.constData() + i);
i += s.length() + 1;
if (s.isEmpty())
@@ -587,11 +518,7 @@ bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVa
case REG_BINARY: {
QString s;
if (dataSize) {
- QT_WA( {
- s = QString::fromUtf16((const ushort*)data.constData(), data.size()/2);
- }, {
- s = QString::fromLocal8Bit(data.constData(), data.size());
- } );
+ s = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2);
}
if (value != 0)
*value = stringToVariant(s);
@@ -635,13 +562,8 @@ QWinSettingsPrivate::~QWinSettingsPrivate()
#if defined(Q_OS_WINCE)
remove(regList.at(0).key());
#else
- DWORD res;
QString emptyKey;
- QT_WA( {
- res = RegDeleteKeyW(writeHandle(), reinterpret_cast<const wchar_t *>(emptyKey.utf16()));
- }, {
- res = RegDeleteKeyA(writeHandle(), emptyKey.toLocal8Bit());
- } );
+ DWORD res = RegDeleteKey(writeHandle(), reinterpret_cast<const wchar_t *>(emptyKey.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: Failed to delete key \"%s\": %s",
regList.at(0).key().toLatin1().data(), errorCodeToString(res).toLatin1().data());
@@ -666,11 +588,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
LONG res;
HKEY handle = openKey(writeHandle(), registryPermissions, keyPath(rKey));
if (handle != 0) {
- QT_WA( {
- res = RegDeleteValueW(handle, reinterpret_cast<const wchar_t *>(keyName(rKey).utf16()));
- }, {
- res = RegDeleteValueA(handle, keyName(rKey).toLocal8Bit());
- } );
+ res = RegDeleteValue(handle, reinterpret_cast<const wchar_t *>(keyName(rKey).utf16()));
RegCloseKey(handle);
}
@@ -685,12 +603,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
for (int i = 0; i < childKeys.size(); ++i) {
QString group = childKeys.at(i);
- LONG res;
- QT_WA( {
- res = RegDeleteValueW(handle, reinterpret_cast<const wchar_t *>(group.utf16()));
- }, {
- res = RegDeleteValueA(handle, group.toLocal8Bit());
- } );
+ LONG res = RegDeleteValue(handle, reinterpret_cast<const wchar_t *>(group.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteValue failed on subkey \"%s\": %s",
group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
@@ -701,11 +614,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
// For WinCE always Close the handle first.
RegCloseKey(handle);
#endif
- QT_WA( {
- res = RegDeleteKeyW(writeHandle(), reinterpret_cast<const wchar_t *>(rKey.utf16()));
- }, {
- res = RegDeleteKeyA(writeHandle(), rKey.toLocal8Bit());
- } );
+ res = RegDeleteKey(writeHandle(), reinterpret_cast<const wchar_t *>(rKey.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteKey failed on key \"%s\": %s",
@@ -761,27 +670,15 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
if (type == REG_BINARY) {
QString s = variantToString(value);
- QT_WA( {
- regValueBuff = QByteArray((const char*)s.utf16(), s.length()*2);
- }, {
- regValueBuff = QByteArray((const char*)s.toLocal8Bit(), s.length());
- } );
+ regValueBuff = QByteArray((const char*)s.utf16(), s.length() * 2);
} else {
QStringList::const_iterator it = l.constBegin();
for (; it != l.constEnd(); ++it) {
const QString &s = *it;
- QT_WA( {
- regValueBuff += QByteArray((const char*)s.utf16(), (s.length() + 1)*2);
- }, {
- regValueBuff += QByteArray((const char*)s.toLocal8Bit(), s.length() + 1);
- } );
+ regValueBuff += QByteArray((const char*)s.utf16(), (s.length() + 1) * 2);
}
- QT_WA( {
- regValueBuff.append((char)0);
- regValueBuff.append((char)0);
- }, {
- regValueBuff.append((char)0);
- } );
+ regValueBuff.append((char)0);
+ regValueBuff.append((char)0);
}
break;
}
@@ -794,21 +691,6 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
}
case QVariant::ByteArray:
- // On Win95/98/Me QString::toLocal8Bit() fails to handle chars > 0x7F. So we don't go through variantToString() at all.
- if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) {
- QByteArray ba = value.toByteArray();
- regValueBuff = "@ByteArray(";
- regValueBuff += ba;
- regValueBuff += ')';
- if (ba.contains('\0')) {
- type = REG_BINARY;
- } else {
- type = REG_SZ;
- regValueBuff += '\0';
- }
-
- break;
- }
// fallthrough intended
default: {
@@ -817,33 +699,18 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
QString s = variantToString(value);
type = stringContainsNullChar(s) ? REG_BINARY : REG_SZ;
if (type == REG_BINARY) {
- QT_WA( {
- regValueBuff = QByteArray((const char*)s.utf16(), s.length()*2);
- }, {
- regValueBuff = QByteArray((const char*)s.toLocal8Bit(), s.length());
- } );
+ regValueBuff = QByteArray((const char*)s.utf16(), s.length() * 2);
} else {
- QT_WA( {
- regValueBuff = QByteArray((const char*)s.utf16(), (s.length() + 1)*2);
- }, {
- regValueBuff = QByteArray((const char*)s.toLocal8Bit(), s.length() + 1);
- } );
+ regValueBuff = QByteArray((const char*)s.utf16(), (s.length() + 1) * 2);
}
break;
}
}
// set the value
- LONG res;
- QT_WA( {
- res = RegSetValueExW(handle, reinterpret_cast<const wchar_t *>(keyName(rKey).utf16()), 0, type,
- reinterpret_cast<const unsigned char*>(regValueBuff.constData()),
- regValueBuff.size());
- }, {
- res = RegSetValueExA(handle, keyName(rKey).toLocal8Bit(), 0, type,
+ LONG res = RegSetValueEx(handle, reinterpret_cast<const wchar_t *>(keyName(rKey).utf16()), 0, type,
reinterpret_cast<const unsigned char*>(regValueBuff.constData()),
regValueBuff.size());
- } );
if (res == ERROR_SUCCESS) {
deleteWriteHandleOnExit = false;
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index bd039c8..48f34d6 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -60,6 +60,10 @@
#include <time.h>
#include <ctype.h>
+#if defined(Q_OS_UNIX)
+# include "private/qcore_unix_p.h" // overrides QT_OPEN
+#endif
+
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
# include <process.h>
# if defined(_MSC_VER) && _MSC_VER >= 1400
@@ -69,9 +73,11 @@
#if defined(Q_OS_WINCE)
# include <types.h>
-# include "qfunctions_wince.h"
#endif
+#if defined(Q_OS_VXWORKS)
+# include <taskLib.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -130,6 +136,8 @@ static int _gettemp(char *path, int *doopen, int domkdir, int slen)
}
#if defined(Q_OS_WIN) && defined(_MSC_VER) && _MSC_VER >= 1400
pid = _getpid();
+#elif defined(Q_OS_VXWORKS)
+ pid = (pid_t) taskIdCurrent;
#else
pid = getpid();
#endif
@@ -203,13 +211,14 @@ static int _gettemp(char *path, int *doopen, int domkdir, int slen)
if (QDir::isAbsolutePath(QString::fromLatin1(path)))
targetPath = QLatin1String(path);
else
- targetPath = QDir::currentPath().append(QLatin1String("/")) + QLatin1String(path);
+ targetPath = QDir::currentPath().append(QLatin1Char('/')) + QLatin1String(path);
if ((*doopen =
QT_OPEN(targetPath.toLocal8Bit(), O_CREAT|O_EXCL|O_RDWR
# else // CE
+ // this is Unix or older MSVC
if ((*doopen =
- open(path, QT_OPEN_CREAT|O_EXCL|QT_OPEN_RDWR
+ QT_OPEN(path, QT_OPEN_CREAT|O_EXCL|QT_OPEN_RDWR
# endif
# ifdef QT_LARGEFILE_SUPPORT
|QT_OPEN_LARGEFILE
@@ -219,18 +228,9 @@ static int _gettemp(char *path, int *doopen, int domkdir, int slen)
# elif defined(Q_OS_WIN)
|O_BINARY
# endif
-# ifdef O_CLOEXEC
- // supported on Linux >= 2.6.23; avoids one extra system call
- // and avoids a race condition: if another thread forks, we could
- // end up leaking a file descriptor...
- |O_CLOEXEC
-# endif
, 0600)) >= 0)
#endif // WIN && !CE
{
-#if defined(Q_OS_UNIX) && !defined(O_CLOEXEC)
- fcntl(*doopen, F_SETFD, FD_CLOEXEC);
-#endif
return 1;
}
if (errno != EEXIST)
@@ -239,7 +239,7 @@ static int _gettemp(char *path, int *doopen, int domkdir, int slen)
#ifdef Q_OS_WIN
if (QT_MKDIR(path) == 0)
#else
- if (mkdir(path, 0700) == 0)
+ if (QT_MKDIR(path, 0700) == 0)
#endif
return 1;
if (errno != EEXIST)
@@ -447,7 +447,7 @@ QTemporaryFilePrivate::~QTemporaryFilePrivate()
\brief The QTemporaryFile class is an I/O device that operates on temporary files.
\ingroup io
- \mainclass
+
QTemporaryFile is used to create unique temporary files safely.
The file itself is created by calling open(). The name of the
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index 1cb05d3..72388b5 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -49,7 +49,7 @@ static const int QTEXTSTREAM_BUFFERSIZE = 16384;
reading and writing text.
\ingroup io
- \ingroup text
+ \ingroup string-processing
\reentrant
QTextStream can operate on a QIODevice, a QByteArray or a
@@ -333,7 +333,7 @@ public:
this->stream = stream;
}
-public slots:
+public Q_SLOTS:
inline void flushStream() { stream->flush(); }
private:
@@ -411,6 +411,7 @@ public:
QString writeBuffer;
QString readBuffer;
int readBufferOffset;
+ int readConverterSavedStateOffset; //the offset between readBufferStartDevicePos and that start of the buffer
qint64 readBufferStartDevicePos;
// streaming parameters
@@ -437,6 +438,7 @@ QTextStreamPrivate::QTextStreamPrivate(QTextStream *q_ptr)
#ifndef QT_NO_TEXTCODEC
readConverterSavedState(0),
#endif
+ readConverterSavedStateOffset(0),
locale(QLocale::C)
{
this->q_ptr = q_ptr;
@@ -559,13 +561,8 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes)
if (!codec || autoDetectUnicode) {
autoDetectUnicode = false;
- if (bytesRead >= 4 && ((uchar(buf[0]) == 0xff && uchar(buf[1]) == 0xfe && uchar(buf[2]) == 0 && uchar(buf[3]) == 0)
- || (uchar(buf[0]) == 0 && uchar(buf[1]) == 0 && uchar(buf[2]) == 0xfe && uchar(buf[3]) == 0xff))) {
- codec = QTextCodec::codecForName("UTF-32");
- } else if (bytesRead >= 2 && ((uchar(buf[0]) == 0xff && uchar(buf[1]) == 0xfe)
- || (uchar(buf[0]) == 0xfe && uchar(buf[1]) == 0xff))) {
- codec = QTextCodec::codecForName("UTF-16");
- } else if (!codec) {
+ codec = QTextCodec::codecForUtfText(QByteArray::fromRawData(buf, bytesRead), codec);
+ if (!codec) {
codec = QTextCodec::codecForLocale();
writeConverterState.flags |= QTextCodec::IgnoreHeader;
}
@@ -835,6 +832,10 @@ inline void QTextStreamPrivate::consume(int size)
readBufferOffset = 0;
readBuffer.clear();
saveConverterState(device->pos());
+ } else if (readBufferOffset > QTEXTSTREAM_BUFFERSIZE) {
+ readBuffer = readBuffer.remove(0,readBufferOffset);
+ readConverterSavedStateOffset += readBufferOffset;
+ readBufferOffset = 0;
}
}
}
@@ -856,6 +857,7 @@ inline void QTextStreamPrivate::saveConverterState(qint64 newPos)
#endif
readBufferStartDevicePos = newPos;
+ readConverterSavedStateOffset = 0;
}
/*! \internal
@@ -1112,9 +1114,6 @@ QTextStream::~QTextStream()
#endif
if (!d->writeBuffer.isEmpty())
d->flushWriteBuffer();
-
- delete d;
- d_ptr = 0;
}
/*!
@@ -1220,7 +1219,7 @@ qint64 QTextStream::pos() const
// Rewind the device to get to the current position Ensure that
// readBufferOffset is unaffected by fillReadBuffer()
- int oldReadBufferOffset = d->readBufferOffset;
+ int oldReadBufferOffset = d->readBufferOffset + d->readConverterSavedStateOffset;
while (d->readBuffer.size() < oldReadBufferOffset) {
if (!thatd->fillReadBuffer(1))
return qint64(-1);
@@ -2290,7 +2289,7 @@ bool QTextStreamPrivate::putNumber(qulonglong number, bool negative)
// ShowBase flag set zero should be written as '00'
if (number == 0 && base == 8 && numberFlags & QTextStream::ShowBase
&& result == QLatin1String("0")) {
- result.prepend(QLatin1String("0"));
+ result.prepend(QLatin1Char('0'));
}
}
return putString(result, true);
@@ -3086,8 +3085,6 @@ QLocale QTextStream::locale() const
\compat
\reentrant
- \ingroup io
- \ingroup text
Use QTextStream instead.
*/
@@ -3114,8 +3111,6 @@ QLocale QTextStream::locale() const
\compat
\reentrant
- \ingroup io
- \ingroup text
Use QTextStream instead.
*/
diff --git a/src/corelib/io/qtextstream.h b/src/corelib/io/qtextstream.h
index aae0e8a..c922833 100644
--- a/src/corelib/io/qtextstream.h
+++ b/src/corelib/io/qtextstream.h
@@ -46,6 +46,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qchar.h>
#include <QtCore/qlocale.h>
+#include <QtCore/qscopedpointer.h>
#ifndef QT_NO_TEXTCODEC
# ifdef QT3_SUPPORT
@@ -256,7 +257,7 @@ private:
Q_DISABLE_COPY(QTextStream)
- QTextStreamPrivate *d_ptr;
+ QScopedPointer<QTextStreamPrivate> d_ptr;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QTextStream::NumberFlags)
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index 3802771..d219fd3 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -47,9 +47,9 @@
\reentrant
\ingroup io
- \ingroup misc
+ \ingroup network
\ingroup shared
- \mainclass
+
It can parse and construct URLs in both encoded and unencoded
form. QUrl also has support for internationalized domain names
@@ -2336,12 +2336,12 @@ static const NameprepCaseFoldingEntry NameprepCaseFolding[] = {
{ 0x1D7BB, { 0x03C3, 0x0000, 0x0000, 0x0000 } }
};
-static void mapToLowerCase(QString *str)
+static void mapToLowerCase(QString *str, int from)
{
int N = sizeof(NameprepCaseFolding) / sizeof(NameprepCaseFolding[0]);
QChar *d = 0;
- for (int i = 0; i < str->size(); ++i) {
+ for (int i = from; i < str->size(); ++i) {
int uc = str->at(i).unicode();
if (uc < 0x80) {
if (uc <= 'Z' && uc >= 'A') {
@@ -2388,11 +2388,11 @@ static bool isMappedToNothing(const QChar &ch)
}
-static void stripProhibitedOutput(QString *str)
+static void stripProhibitedOutput(QString *str, int from)
{
- ushort *out = (ushort *)str->data();
+ ushort *out = (ushort *)str->data() + from;
const ushort *in = out;
- const ushort *end = out + str->size();
+ const ushort *end = (ushort *)str->data() + str->size();
while (in < end) {
ushort uc = *in;
if (uc < 0x80 ||
@@ -2901,66 +2901,99 @@ static bool isBidirectionalL(const QChar &ch)
return false;
}
+#ifdef QT_BUILD_INTERNAL
+// export for tst_qurl.cpp
+Q_AUTOTEST_EXPORT void qt_nameprep(QString *source, int from);
+Q_AUTOTEST_EXPORT bool qt_check_std3rules(const QChar *uc, int len);
+#else
+// non-test build, keep the symbols for ourselves
+static void qt_nameprep(QString *source, int from);
+static bool qt_check_std3rules(const QChar *uc, int len);
+#endif
-Q_AUTOTEST_EXPORT QString qt_nameprep(const QString &source)
+void qt_nameprep(QString *source, int from)
{
- QString mapped = source;
-
- bool simple = true;
- for (int i = 0; i < mapped.size(); ++i) {
- ushort uc = mapped.at(i).unicode();
+ QChar *src = source->data(); // causes a detach, so we're sure the only one using it
+ QChar *out = src + from;
+ const QChar *e = src + source->size();
+
+ for ( ; out < e; ++out) {
+ register ushort uc = out->unicode();
if (uc > 0x80) {
- simple = false;
break;
} else if (uc >= 'A' && uc <= 'Z') {
- mapped[i] = QChar(uc | 0x20);
+ *out = QChar(uc | 0x20);
}
}
- if (simple)
- return mapped;
-
+ if (out == e)
+ return; // everything was mapped easily (lowercased, actually)
+ int firstNonAscii = out - src;
+
// Characters commonly mapped to nothing are simply removed
// (Table B.1)
- QChar *out = mapped.data();
const QChar *in = out;
- const QChar *e = in + mapped.size();
while (in < e) {
if (!isMappedToNothing(*in))
*out++ = *in;
++in;
}
if (out != in)
- mapped.truncate(out - mapped.constData());
+ source->truncate(out - src);
// Map to lowercase (Table B.2)
- mapToLowerCase(&mapped);
+ mapToLowerCase(source, firstNonAscii);
// Normalize to Unicode 3.2 form KC
- mapped = mapped.normalized(QString::NormalizationForm_KC, QChar::Unicode_3_2);
+ extern void qt_string_normalize(QString *data, QString::NormalizationForm mode,
+ QChar::UnicodeVersion version, int from);
+ qt_string_normalize(source, QString::NormalizationForm_KC, QChar::Unicode_3_2, firstNonAscii);
// Strip prohibited output
- stripProhibitedOutput(&mapped);
+ stripProhibitedOutput(source, firstNonAscii);
// Check for valid bidirectional characters
bool containsLCat = false;
bool containsRandALCat = false;
- for (int j = 0; j < mapped.size() && (!containsLCat || !containsRandALCat); ++j) {
- if (isBidirectionalL(mapped.at(j)))
+ src = source->data();
+ e = src + source->size();
+ for (in = src + from; in < e && (!containsLCat || !containsRandALCat); ++in) {
+ if (isBidirectionalL(*in))
containsLCat = true;
- else if (isBidirectionalRorAL(mapped.at(j)))
+ else if (isBidirectionalRorAL(*in))
containsRandALCat = true;
}
if (containsRandALCat) {
- if (containsLCat || (!isBidirectionalRorAL(mapped.at(0))
- || !isBidirectionalRorAL(mapped.at(mapped.size() - 1))))
- mapped.clear();
+ if (containsLCat || (!isBidirectionalRorAL(src[from])
+ || !isBidirectionalRorAL(e[-1])))
+ source->resize(from); // not allowed, clear the label
}
+}
- return mapped;
+bool qt_check_std3rules(const QChar *uc, int len)
+{
+ if (len > 63)
+ return false;
+
+ for (int i = 0; i < len; ++i) {
+ register ushort c = uc[i].unicode();
+ if (c == '-' && (i == 0 || i == len - 1))
+ return false;
+
+ // verifying the absence of LDH is the same as verifying that
+ // only LDH is present
+ if (c == '-' || (c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z'))
+ continue;
+
+ return false;
+ }
+
+ return true;
}
-static inline char encodeDigit(uint digit)
+static inline uint encodeDigit(uint digit)
{
return digit + 22 + 75 * (digit < 26);
}
@@ -2977,7 +3010,7 @@ static inline uint adapt(uint delta, uint numpoints, bool firsttime)
return k + (((base - tmin + 1) * delta) / (delta + skew));
}
-static inline void appendEncode(QByteArray* output, uint& delta, uint& bias, uint& b, uint& h)
+static inline void appendEncode(QString* output, uint& delta, uint& bias, uint& b, uint& h)
{
uint qq;
uint k;
@@ -2991,17 +3024,17 @@ static inline void appendEncode(QByteArray* output, uint& delta, uint& bias, uin
t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias;
if (qq < t) break;
- *output += encodeDigit(t + (qq - t) % (base - t));
+ *output += QChar(encodeDigit(t + (qq - t) % (base - t)));
qq = (qq - t) / (base - t);
}
- *output += encodeDigit(qq);
+ *output += QChar(encodeDigit(qq));
bias = adapt(delta, h + 1, h == b);
delta = 0;
++h;
}
-static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output)
+static void toPunycodeHelper(const QChar *s, int ucLength, QString *output)
{
uint n = initial_n;
uint delta = 0;
@@ -3010,7 +3043,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output)
int outLen = output->length();
output->resize(outLen + ucLength);
- char *d = output->data() + outLen;
+ QChar *d = output->data() + outLen;
bool skipped = false;
// copy all basic code points verbatim to output.
for (uint j = 0; j < (uint) ucLength; ++j) {
@@ -3035,7 +3068,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output)
// if basic code points were copied, add the delimiter character.
if (h > 0)
- *output += 0x2d;
+ *output += QChar(0x2d);
// while there are still unprocessed non-basic code points left in
// the input string...
@@ -3083,7 +3116,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output)
}
// prepend ACE prefix
- output->insert(outLen, "xn--");
+ output->insert(outLen, QLatin1String("xn--"));
return;
}
@@ -3144,11 +3177,15 @@ static bool qt_is_idn_enabled(const QString &domain)
int idx = domain.lastIndexOf(QLatin1Char('.'));
if (idx == -1)
return false;
- const QChar *tld = domain.constData() + idx + 1;
+
int len = domain.size() - idx - 1;
+ QString tldString(domain.constData() + idx + 1, len);
+ qt_nameprep(&tldString, 0);
+
+ const QChar *tld = tldString.constData();
if (user_idn_whitelist)
- return user_idn_whitelist->contains(QString(tld, len));
+ return user_idn_whitelist->contains(tldString);
int l = 0;
int r = sizeof(idn_whitelist)/sizeof(const char *) - 1;
@@ -3164,46 +3201,127 @@ static bool qt_is_idn_enabled(const QString &domain)
return equal(tld, len, idn_whitelist[i]);
}
-static QString qt_from_ACE(const QString &domainMC)
+static inline bool isDotDelimiter(ushort uc)
{
- QString domain = domainMC.toLower();
- int idx = domain.indexOf(QLatin1Char('.'));
- if (idx != -1) {
- if (!domain.contains(QLatin1String("xn--"))) {
- bool simple = true;
- for (int i = 0; i < domain.size(); ++i) {
- ushort ch = domain.at(i).unicode();
- if (ch > 'z' || ch < '-' || ch == '/' || (ch > '9' && ch < 'A') || (ch > 'Z' && ch < 'a')) {
+ // IDNA / rfc3490 describes these four delimiters used for
+ // separating labels in unicode international domain
+ // names.
+ return uc == 0x2e || uc == 0x3002 || uc == 0xff0e || uc == 0xff61;
+}
+
+static int nextDotDelimiter(const QString &domain, int from = 0)
+{
+ const QChar *b = domain.unicode();
+ const QChar *ch = b + from;
+ const QChar *e = b + domain.length();
+ while (ch < e) {
+ if (isDotDelimiter(ch->unicode()))
+ break;
+ else
+ ++ch;
+ }
+ return ch - b;
+}
+
+enum AceOperation { ToAceOnly, NormalizeAce };
+static QString qt_ACE_do(const QString &domain, AceOperation op)
+{
+ if (domain.isEmpty())
+ return domain;
+
+ QString result;
+ result.reserve(domain.length());
+
+ const bool isIdnEnabled = op == NormalizeAce ? qt_is_idn_enabled(domain) : false;
+ int lastIdx = 0;
+ QString aceForm; // this variable is here for caching
+
+ while (1) {
+ int idx = nextDotDelimiter(domain, lastIdx);
+ int labelLength = idx - lastIdx;
+ if (labelLength == 0)
+ return QString(); // two delimiters in a row -- empty label not allowed
+
+ // RFC 3490 says, about the ToASCII operation:
+ // 3. If the UseSTD3ASCIIRules flag is set, then perform these checks:
+ //
+ // (a) Verify the absence of non-LDH ASCII code points; that is, the
+ // absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
+ //
+ // (b) Verify the absence of leading and trailing hyphen-minus; that
+ // is, the absence of U+002D at the beginning and end of the
+ // sequence.
+ // and:
+ // 8. Verify that the number of code points is in the range 1 to 63
+ // inclusive.
+
+ // copy the label to the destination, which also serves as our scratch area, lowercasing it
+ int prevLen = result.size();
+ bool simple = true;
+ result.resize(prevLen + labelLength);
+ {
+ QChar *out = result.data() + prevLen;
+ const QChar *in = domain.constData() + lastIdx;
+ const QChar *e = in + labelLength;
+ for (; in < e; ++in, ++out) {
+ register ushort uc = in->unicode();
+ if (uc > 0x7f)
simple = false;
- break;
- }
+ if (uc >= 'A' && uc <= 'Z')
+ *out = QChar(uc | 0x20);
+ else
+ *out = *in;
}
- if (simple)
- return domain;
}
-
- const bool isIdnEnabled = qt_is_idn_enabled(domain);
- int lastIdx = 0;
- QString result;
- while (1) {
- // Nameprep the host. If the labels in the hostname are Punycode
- // encoded, we decode them immediately, then nameprep them.
- QByteArray label;
- toPunycodeHelper(domain.constData() + lastIdx, idx - lastIdx, &label);
- result += qt_nameprep(isIdnEnabled ? QUrl::fromPunycode(label) : QString::fromLatin1(label));
- lastIdx = idx + 1;
- if (lastIdx < domain.size() + 1)
- result += QLatin1Char('.');
- else
- break;
- idx = domain.indexOf(QLatin1Char('.'), lastIdx);
- if (idx == -1)
- idx = domain.size();
+
+ if (simple && labelLength > 6) {
+ // ACE form domains contain only ASCII characters, but we can't consider them simple
+ // is this an ACE form?
+ // the shortest valid ACE domain is 6 characters long (U+0080 would be 1, but it's not allowed)
+ static const ushort acePrefixUtf16[] = { 'x', 'n', '-', '-' };
+ if (memcmp(result.constData() + prevLen, acePrefixUtf16, sizeof acePrefixUtf16) == 0)
+ simple = false;
}
- return result;
- } else {
- return qt_nameprep(domain);
+
+ if (simple) {
+ // fastest case: this is the common case (non IDN-domains)
+ // so we're done
+ if (!qt_check_std3rules(result.constData() + prevLen, labelLength))
+ return QString();
+ } else {
+ // Punycode encoding and decoding cannot be done in-place
+ // That means we need one or two temporaries
+ qt_nameprep(&result, prevLen);
+ labelLength = result.length() - prevLen;
+ register int toReserve = labelLength + 4 + 6; // "xn--" plus some extra bytes
+ if (toReserve > aceForm.capacity())
+ aceForm.reserve(toReserve);
+ toPunycodeHelper(result.constData() + prevLen, result.size() - prevLen, &aceForm);
+
+ // We use resize()+memcpy() here because we're overwriting the data we've copied
+ if (isIdnEnabled) {
+ QString tmp = QUrl::fromPunycode(aceForm.toLatin1());
+ if (tmp.isEmpty())
+ return QString(); // shouldn't happen, since we've just punycode-encoded it
+ result.resize(prevLen + tmp.size());
+ memcpy(result.data() + prevLen, tmp.constData(), tmp.size() * sizeof(QChar));
+ } else {
+ result.resize(prevLen + aceForm.size());
+ memcpy(result.data() + prevLen, aceForm.constData(), aceForm.size() * sizeof(QChar));
+ }
+
+ if (!qt_check_std3rules(aceForm.constData(), aceForm.size()))
+ return QString();
+ }
+
+
+ lastIdx = idx + 1;
+ if (lastIdx < domain.size() + 1)
+ result += QLatin1Char('.');
+ else
+ break;
}
+ return result;
}
@@ -3246,12 +3364,27 @@ QUrlPrivate::QUrlPrivate(const QUrlPrivate &copy)
QString QUrlPrivate::canonicalHost() const
{
- if (QURL_HASFLAG(stateFlags, HostCanonicalized))
+ if (QURL_HASFLAG(stateFlags, HostCanonicalized) || host.isEmpty())
return host;
QUrlPrivate *that = const_cast<QUrlPrivate *>(this);
QURL_SETFLAG(that->stateFlags, HostCanonicalized);
- that->host = qt_from_ACE(host);
+ if (host.contains(QLatin1Char(':'))) {
+ // This is an IP Literal, use _IPLiteral to validate
+ QByteArray ba = host.toLatin1();
+ if (!ba.startsWith('[')) {
+ // surround the IP Literal with [ ] if it's not already done so
+ ba.reserve(ba.length() + 2);
+ ba.prepend('[');
+ ba.append(']');
+ }
+
+ const char *ptr = ba.constData();
+ if (!_IPLiteral(&ptr))
+ that->host.clear();
+ } else {
+ that->host = qt_ACE_do(host, NormalizeAce);
+ }
return that->host;
}
@@ -3737,7 +3870,10 @@ QByteArray QUrlPrivate::toEncoded(QUrl::FormattingOptions options) const
}
}
- url += QUrl::toAce(host);
+ if (host.startsWith(QLatin1Char('[')))
+ url += host.toLatin1();
+ else
+ url += QUrl::toAce(host);
if (!(options & QUrl::RemovePort) && port != -1) {
url += ':';
url += QString::number(port).toAscii();
@@ -3888,6 +4024,29 @@ QString QUrlPrivate::createErrorString()
}
/*!
+ \macro QT_NO_URL_CAST_FROM_STRING
+ \relates QUrl
+
+ Disables automatic conversions from QString (or char *) to QUrl.
+
+ Compiling your code with this define is useful when you have a lot of
+ code that uses QString for file names and you wish to convert it to
+ use QUrl for network transparency. In any code that uses QUrl, it can
+ help avoid missing QUrl::resolved() calls, and other misuses of
+ QString to QUrl conversions.
+
+ \oldcode
+ url = filename; // probably not what you want
+ \newcode
+ url = QUrl::fromLocalFile(filename);
+ url = baseurl.resolved(QUrl(filename));
+ \endcode
+
+ \sa QT_NO_CAST_FROM_ASCII
+*/
+
+
+/*!
Constructs a URL by parsing \a url. \a url is assumed to be in human
readable representation, with no percent encoding. QUrl will automatically
percent encode all characters that are not allowed in a URL.
@@ -4412,8 +4571,6 @@ void QUrl::setHost(const QString &host)
QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized | QUrlPrivate::HostCanonicalized);
d->host = host;
- if (d->host.contains(QLatin1Char(':')))
- d->host = QLatin1Char('[') + d->host + QLatin1Char(']');
}
/*!
@@ -5330,7 +5487,7 @@ QString QUrl::toString(FormattingOptions options) const
url += QLatin1Char('/');
url += ourPath;
// check if we need to remove trailing slashes
- while ((options & StripTrailingSlash) && url.right(1) == QLatin1String("/"))
+ while ((options & StripTrailingSlash) && url.endsWith(QLatin1Char('/')))
url.chop(1);
}
@@ -5425,9 +5582,9 @@ QByteArray QUrl::toPercentEncoding(const QString &input, const QByteArray &exclu
*/
QByteArray QUrl::toPunycode(const QString &uc)
{
- QByteArray output;
+ QString output;
toPunycodeHelper(uc.constData(), uc.size(), &output);
- return output;
+ return output.toLatin1();
}
/*!
@@ -5528,7 +5685,7 @@ QString QUrl::fromPunycode(const QByteArray &pc)
*/
QString QUrl::fromAce(const QByteArray &domain)
{
- return qt_from_ACE(QString::fromLatin1(domain));
+ return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce);
}
/*!
@@ -5542,29 +5699,15 @@ QString QUrl::fromAce(const QByteArray &domain)
Applications (IDNA) specification, which allows for domain names
(like \c "example.com") to be written using international
characters.
+
+ This function return an empty QByteArra if \a domain is not a valid
+ hostname. Note, in particular, that IPv6 literals are not valid domain
+ names.
*/
QByteArray QUrl::toAce(const QString &domain)
{
- // IDNA / rfc3490 describes these four delimiters used for
- // separating labels in unicode international domain
- // names.
- QString nameprepped = qt_nameprep(domain);
- int lastIdx = 0;
- QByteArray result;
- for (int i = 0; i < nameprepped.size(); ++i) {
- ushort uc = nameprepped.at(i).unicode();
- if (uc == 0x2e || uc == 0x3002 || uc == 0xff0e || uc == 0xff61) {
- if (lastIdx)
- result += '.';
- toPunycodeHelper(nameprepped.constData() + lastIdx, i - lastIdx, &result);
- lastIdx = i + 1;
- }
- }
- if (lastIdx)
- result += '.';
- toPunycodeHelper(nameprepped.constData() + lastIdx, nameprepped.size() - lastIdx, &result);
-
- return result;
+ QString result = qt_ACE_do(domain, ToAceOnly);
+ return result.toLatin1();
}
/*!
@@ -5698,7 +5841,7 @@ QUrl QUrl::fromLocalFile(const QString &localFile)
// magic for drives on windows
if (deslashified.length() > 1 && deslashified.at(1) == QLatin1Char(':') && deslashified.at(0) != QLatin1Char('/')) {
- url.setPath(QLatin1String("/") + deslashified);
+ url.setPath(QLatin1Char('/') + deslashified);
// magic for shared drive on windows
} else if (deslashified.startsWith(QLatin1String("//"))) {
int indexOfPath = deslashified.indexOf(QLatin1Char('/'), 2);
@@ -5728,7 +5871,7 @@ QString QUrl::toLocalFile() const
// magic for shared drive on windows
if (!d->host.isEmpty()) {
tmp = QLatin1String("//") + d->host + (ourPath.length() > 0 && ourPath.at(0) != QLatin1Char('/')
- ? QLatin1String("/") + ourPath : ourPath);
+ ? QLatin1Char('/') + ourPath : ourPath);
} else {
tmp = ourPath;
// magic for drives on windows
@@ -5850,10 +5993,10 @@ bool QUrl::isParentOf(const QUrl &childUrl) const
Use resolved("..") instead.
\oldcode
- QUrl url("http://qt.nokia.com/Developer/");
+ QUrl url("http://example.com/Developer/");
url.cdUp();
\newcode
- QUrl url("http://qt.nokia.com/Developer/");
+ QUrl url("http://example.com/Developer/");
url = url.resolved("..");
\endcode
*/
@@ -5976,7 +6119,7 @@ QDataStream &operator>>(QDataStream &in, QUrl &url)
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const QUrl &url)
{
- d.maybeSpace() << "QUrl(" << url.toString() << ")";
+ d.maybeSpace() << "QUrl(" << url.toString() << ')';
return d.space();
}
#endif
diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h
index c867cc3..893459e 100644
--- a/src/corelib/io/qurl.h
+++ b/src/corelib/io/qurl.h
@@ -81,12 +81,17 @@ public:
Q_DECLARE_FLAGS(FormattingOptions, FormattingOption)
QUrl();
+#ifdef QT_NO_URL_CAST_FROM_STRING
+ explicit
+#endif
QUrl(const QString &url);
QUrl(const QString &url, ParsingMode mode);
// ### Qt 5: merge the two constructors, with mode = TolerantMode
QUrl(const QUrl &copy);
QUrl &operator =(const QUrl &copy);
+#ifndef QT_NO_URL_CAST_FROM_STRING
QUrl &operator =(const QString &url);
+#endif
~QUrl();
void setUrl(const QString &url);
@@ -223,7 +228,7 @@ public:
inline QT3_SUPPORT QString ref() const { return fragment(); }
inline QT3_SUPPORT void setRef(const QString &txt) { setFragment(txt); }
inline QT3_SUPPORT bool hasRef() const { return !fragment().isEmpty(); }
- inline QT3_SUPPORT void addPath(const QString &p) { setPath(path() + QLatin1String("/") + p); }
+ inline QT3_SUPPORT void addPath(const QString &p) { setPath(path() + QLatin1Char('/') + p); }
QT3_SUPPORT void setFileName(const QString &txt);
QT3_SUPPORT QString fileName() const;
QT3_SUPPORT QString dirPath() const;
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index d90ecae..003693b 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -12,7 +12,7 @@ HEADERS += \
kernel/qcoreevent.h \
kernel/qmetaobject.h \
kernel/qmetatype.h \
- kernel/qmimedata.h \
+ kernel/qmimedata.h \
kernel/qobject.h \
kernel/qobjectdefs.h \
kernel/qsignalmapper.h \
@@ -27,12 +27,13 @@ HEADERS += \
kernel/qvariant_p.h \
kernel/qmetaobject_p.h \
kernel/qobject_p.h \
- kernel/qcoreglobaldata_p.h \
- kernel/qsharedmemory.h \
+ kernel/qcoreglobaldata_p.h \
+ kernel/qsharedmemory.h \
kernel/qsharedmemory_p.h \
kernel/qsystemsemaphore.h \
kernel/qsystemsemaphore_p.h \
- kernel/qfunctions_p.h
+ kernel/qfunctions_p.h \
+ kernel/qguard_p.h
SOURCES += \
kernel/qabstracteventdispatcher.cpp \
@@ -43,7 +44,7 @@ SOURCES += \
kernel/qcoreevent.cpp \
kernel/qmetaobject.cpp \
kernel/qmetatype.cpp \
- kernel/qmimedata.cpp \
+ kernel/qmimedata.cpp \
kernel/qobject.cpp \
kernel/qobjectcleanuphandler.cpp \
kernel/qsignalmapper.cpp \
@@ -53,7 +54,8 @@ SOURCES += \
kernel/qvariant.cpp \
kernel/qcoreglobaldata.cpp \
kernel/qsharedmemory.cpp \
- kernel/qsystemsemaphore.cpp
+ kernel/qsystemsemaphore.cpp \
+ kernel/qpointer.cpp
win32 {
SOURCES += \
@@ -85,12 +87,14 @@ mac {
kernel/qcore_mac.cpp
}
-unix {
+unix:!symbian {
SOURCES += \
+ kernel/qcore_unix.cpp \
kernel/qcrashhandler.cpp \
kernel/qsharedmemory_unix.cpp \
kernel/qsystemsemaphore_unix.cpp
HEADERS += \
+ kernel/qcore_unix_p.h \
kernel/qcrashhandler_p.h
contains(QT_CONFIG, glib) {
@@ -99,7 +103,7 @@ unix {
HEADERS += \
kernel/qeventdispatcher_glib_p.h
QMAKE_CXXFLAGS += $$QT_CFLAGS_GLIB
- LIBS +=$$QT_LIBS_GLIB
+ LIBS_PRIVATE +=$$QT_LIBS_GLIB
}
SOURCES += \
kernel/qeventdispatcher_unix.cpp
@@ -109,3 +113,26 @@ unix {
contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri)
}
+symbian {
+ SOURCES += \
+ kernel/qcore_unix.cpp \
+ kernel/qcrashhandler.cpp \
+ kernel/qeventdispatcher_symbian.cpp \
+ kernel/qcore_symbian_p.cpp \
+ kernel/qsharedmemory_symbian.cpp \
+ kernel/qsystemsemaphore_symbian.cpp
+
+ HEADERS += \
+ kernel/qcore_unix_p.h \
+ kernel/qcrashhandler_p.h \
+ kernel/qeventdispatcher_symbian_p.h \
+ kernel/qcore_symbian_p.h
+}
+
+vxworks {
+ SOURCES += \
+ kernel/qfunctions_vxworks.cpp
+ HEADERS += \
+ kernel/qfunctions_vxworks.h
+}
+
diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp
index 5d5a386..f1e7b06 100644
--- a/src/corelib/kernel/qabstracteventdispatcher.cpp
+++ b/src/corelib/kernel/qabstracteventdispatcher.cpp
@@ -168,7 +168,6 @@ void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId)
\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
@@ -398,20 +397,23 @@ void QAbstractEventDispatcher::closingDown()
*/
/*!
- 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
+ Replaces the event filter function for this
+ QAbstractEventDispatcher with \a filter and returns the replaced
+ event filter function. Only the current event filter function is
+ called. If you want to use both filter functions, save the
+ replaced EventFilter in a place where yours can call it.
+
+ The event filter function set here is called for all messages
+ taken from the system event loop before the event is dispatched to
+ the respective target, including the messages not meant for 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.
+ The event filter function should return true if the message should
+ be filtered, (i.e. stopped). It should return false to allow
+ processing the message to continue.
- 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).
+ By default, no event filter function is set (i.e., this function
+ returns a null EventFilter the first time it is called).
*/
QAbstractEventDispatcher::EventFilter QAbstractEventDispatcher::setEventFilter(EventFilter filter)
{
diff --git a/src/corelib/kernel/qabstracteventdispatcher_p.h b/src/corelib/kernel/qabstracteventdispatcher_p.h
index a50dd67..381b06a 100644
--- a/src/corelib/kernel/qabstracteventdispatcher_p.h
+++ b/src/corelib/kernel/qabstracteventdispatcher_p.h
@@ -58,6 +58,8 @@
QT_BEGIN_NAMESPACE
+Q_CORE_EXPORT uint qGlobalPostedEventsCount();
+
class Q_CORE_EXPORT QAbstractEventDispatcherPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QAbstractEventDispatcher)
diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp
index 39eb88e..0a6c628 100644
--- a/src/corelib/kernel/qabstractitemmodel.cpp
+++ b/src/corelib/kernel/qabstractitemmodel.cpp
@@ -251,8 +251,9 @@ QPersistentModelIndex::operator const QModelIndex&() 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.
+
+ All values in the persistent model index are used when comparing with
+ another model index.
*/
bool QPersistentModelIndex::operator==(const QModelIndex &other) const
@@ -335,10 +336,10 @@ qint64 QPersistentModelIndex::internalId() const
}
/*!
- Returns the parent QModelIndex for this persistent index, or
- QModelIndex() if it has no parent.
+ Returns the parent QModelIndex for this persistent index, or an invalid
+ QModelIndex if it has no parent.
- \sa child() sibling() model()
+ \sa child() sibling() model()
*/
QModelIndex QPersistentModelIndex::parent() const
{
@@ -348,10 +349,10 @@ QModelIndex QPersistentModelIndex::parent() const
}
/*!
- Returns the sibling at \a row and \a column or an invalid
- QModelIndex if there is no sibling at this position.
+ Returns the sibling at \a row and \a column or an invalid QModelIndex if
+ there is no sibling at this position.
- \sa parent() child()
+ \sa parent() child()
*/
QModelIndex QPersistentModelIndex::sibling(int row, int column) const
@@ -362,10 +363,10 @@ QModelIndex QPersistentModelIndex::sibling(int row, int column) const
}
/*!
- Returns the child of the model index that is stored in the given
- \a row and \a column.
+ Returns the child of the model index that is stored in the given \a row
+ and \a column.
- \sa parent() sibling()
+ \sa parent() sibling()
*/
QModelIndex QPersistentModelIndex::child(int row, int column) const
@@ -376,9 +377,10 @@ QModelIndex QPersistentModelIndex::child(int row, int column) const
}
/*!
- Returns the data for the given \a role for the item referred to by the index.
+ Returns the data for the given \a role for the item referred to by the
+ index.
- \sa Qt::ItemDataRole, QAbstractItemModel::setData()
+ \sa Qt::ItemDataRole, QAbstractItemModel::setData()
*/
QVariant QPersistentModelIndex::data(int role) const
{
@@ -388,9 +390,9 @@ QVariant QPersistentModelIndex::data(int role) const
}
/*!
- \since 4.2
+ \since 4.2
- Returns the flags for the item referred to by the index.
+ Returns the flags for the item referred to by the index.
*/
Qt::ItemFlags QPersistentModelIndex::flags() const
{
@@ -400,7 +402,7 @@ Qt::ItemFlags QPersistentModelIndex::flags() const
}
/*!
- Returns the model that the index belongs to.
+ Returns the model that the index belongs to.
*/
const QAbstractItemModel *QPersistentModelIndex::model() const
{
@@ -414,7 +416,9 @@ const QAbstractItemModel *QPersistentModelIndex::model() 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.
+
+ A valid index belongs to a model, and has non-negative row and column
+ numbers.
\sa model(), row(), column()
*/
@@ -428,8 +432,8 @@ bool QPersistentModelIndex::isValid() const
QDebug operator<<(QDebug dbg, const QModelIndex &idx)
{
#ifndef Q_BROKEN_DEBUG_STREAM
- dbg.nospace() << "QModelIndex(" << idx.row() << "," << idx.column()
- << "," << idx.internalPointer() << "," << idx.model() << ")";
+ 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");
@@ -467,6 +471,71 @@ QAbstractItemModel *QAbstractItemModelPrivate::staticEmptyModel()
return qEmptyModel();
}
+namespace {
+ struct DefaultRoleNames : public QHash<int, QByteArray>
+ {
+ DefaultRoleNames() {
+ (*this)[Qt::DisplayRole] = "display";
+ (*this)[Qt::DecorationRole] = "decoration";
+ (*this)[Qt::EditRole] = "edit";
+ (*this)[Qt::ToolTipRole] = "toolTip";
+ (*this)[Qt::StatusTipRole] = "statusTip";
+ (*this)[Qt::WhatsThisRole] = "whatsThis";
+ }
+ };
+}
+
+Q_GLOBAL_STATIC(DefaultRoleNames, qDefaultRoleNames)
+
+const QHash<int,QByteArray> &QAbstractItemModelPrivate::defaultRoleNames()
+{
+ return *qDefaultRoleNames();
+}
+
+
+static uint typeOfVariant(const QVariant &value)
+{
+ //return 0 for integer, 1 for floating point and 2 for other
+ switch (value.userType()) {
+ case QVariant::Bool:
+ case QVariant::Int:
+ case QVariant::UInt:
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ case QVariant::Char:
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::UChar:
+ case QMetaType::ULong:
+ case QMetaType::Long:
+ return 0;
+ case QVariant::Double:
+ case QMetaType::Float:
+ return 1;
+ default:
+ return 2;
+ }
+}
+
+/*!
+ \internal
+ return true if \a value contains a numerical type
+
+ This function is used by our Q{Tree,Widget,Table}WidgetModel classes to sort.
+*/
+bool QAbstractItemModelPrivate::variantLessThan(const QVariant &v1, const QVariant &v2)
+{
+ switch(qMax(typeOfVariant(v1), typeOfVariant(v2)))
+ {
+ case 0: //integer type
+ return v1.toLongLong() < v2.toLongLong();
+ case 1: //floating point
+ return v1.toReal() < v2.toReal();
+ default:
+ return v1.toString() < v2.toString();
+ }
+}
+
void QAbstractItemModelPrivate::removePersistentIndexData(QPersistentModelIndexData *data)
{
if (data->index.isValid()) {
@@ -525,11 +594,123 @@ void QAbstractItemModelPrivate::rowsInserted(const QModelIndex &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();
+ qWarning() << "QAbstractItemModel::endInsertRows: Invalid index (" << old.row() + count << ',' << old.column() << ") in model" << q_func();
+ }
+ }
+}
+
+void QAbstractItemModelPrivate::itemsAboutToBeMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation)
+{
+ Q_Q(QAbstractItemModel);
+ QVector<QPersistentModelIndexData *> persistent_moved_explicitly;
+ QVector<QPersistentModelIndexData *> persistent_moved_in_source;
+ QVector<QPersistentModelIndexData *> persistent_moved_in_destination;
+
+ QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it;
+ const QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator begin = persistent.indexes.constBegin();
+ const QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator end = persistent.indexes.constEnd();
+
+ const bool sameParent = (srcParent == destinationParent);
+ const bool movingUp = (srcFirst > destinationChild);
+
+ for ( it = begin; it != end; ++it) {
+ QPersistentModelIndexData *data = *it;
+ const QModelIndex &index = data->index;
+ const QModelIndex &parent = index.parent();
+ const bool isSourceIndex = (parent == srcParent);
+ const bool isDestinationIndex = (parent == destinationParent);
+
+ int childPosition;
+ if (orientation == Qt::Vertical)
+ childPosition = index.row();
+ else
+ childPosition = index.column();
+
+ if (!index.isValid() || !(isSourceIndex || isDestinationIndex ) )
+ continue;
+
+ if (!sameParent && isDestinationIndex) {
+ if (childPosition >= destinationChild)
+ persistent_moved_in_destination.append(data);
+ continue;
+ }
+
+ if (sameParent && movingUp && childPosition < destinationChild)
+ continue;
+
+ if (sameParent && !movingUp && childPosition < srcFirst )
+ continue;
+
+ if (!sameParent && childPosition < srcFirst)
+ continue;
+
+ if (sameParent && (childPosition > srcLast) && (childPosition >= destinationChild ))
+ continue;
+
+ if ((childPosition <= srcLast) && (childPosition >= srcFirst)) {
+ persistent_moved_explicitly.append(data);
+ } else {
+ persistent_moved_in_source.append(data);
+ }
+ }
+ persistent.moved.push(persistent_moved_explicitly);
+ persistent.moved.push(persistent_moved_in_source);
+ persistent.moved.push(persistent_moved_in_destination);
+}
+
+/*!
+ \internal
+
+ Moves persistent indexes \a indexes by amount \a change. The change will be either a change in row value or a change in
+ column value depending on the value of \a orientation. The indexes may also be moved to a different parent if \a parent
+ differs from the existing parent for the index.
+*/
+void QAbstractItemModelPrivate::movePersistentIndexes(QVector<QPersistentModelIndexData *> indexes, int change, const QModelIndex &parent, Qt::Orientation orientation)
+{
+ QVector<QPersistentModelIndexData *>::const_iterator it;
+ const QVector<QPersistentModelIndexData *>::const_iterator begin = indexes.constBegin();
+ const QVector<QPersistentModelIndexData *>::const_iterator end = indexes.constEnd();
+
+ for (it = begin; it != end; ++it)
+ {
+ QPersistentModelIndexData *data = *it;
+
+ int row = data->index.row();
+ int column = data->index.column();
+
+ if (Qt::Vertical == orientation)
+ row += change;
+ else
+ column += change;
+
+ persistent.indexes.erase(persistent.indexes.find(data->index));
+ data->index = q_func()->index(row, column, parent);
+ if (data->index.isValid()) {
+ persistent.insertMultiAtEnd(data->index, data);
+ } else {
+ qWarning() << "QAbstractItemModel::endMoveRows: Invalid index (" << row << "," << column << ") in model" << q_func();
}
}
}
+void QAbstractItemModelPrivate::itemsMoved(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation)
+{
+ QVector<QPersistentModelIndexData *> moved_in_destination = persistent.moved.pop();
+ QVector<QPersistentModelIndexData *> moved_in_source = persistent.moved.pop();
+ QVector<QPersistentModelIndexData *> moved_explicitly = persistent.moved.pop();
+
+ const bool sameParent = (sourceParent == destinationParent);
+ const bool movingUp = (sourceFirst > destinationChild);
+
+ const int explicit_change = (!sameParent || movingUp) ? destinationChild - sourceFirst : destinationChild - sourceLast - 1 ;
+ const int source_change = (!sameParent || !movingUp) ? -1*(sourceLast - sourceFirst + 1) : sourceLast - sourceFirst + 1 ;
+ const int destination_change = sourceLast - sourceFirst + 1;
+
+ movePersistentIndexes(moved_explicitly, explicit_change, destinationParent, orientation);
+ movePersistentIndexes(moved_in_source, source_change, sourceParent, orientation);
+ movePersistentIndexes(moved_in_destination, destination_change, destinationParent, orientation);
+}
+
void QAbstractItemModelPrivate::rowsAboutToBeRemoved(const QModelIndex &parent,
int first, int last)
{
@@ -574,7 +755,7 @@ void QAbstractItemModelPrivate::rowsRemoved(const QModelIndex &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();
+ qWarning() << "QAbstractItemModel::endRemoveRows: Invalid index (" << old.row() - count << ',' << old.column() << ") in model" << q_func();
}
}
QVector<QPersistentModelIndexData *> persistent_invalidated = persistent.invalidated.pop();
@@ -619,7 +800,7 @@ void QAbstractItemModelPrivate::columnsInserted(const QModelIndex &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();
+ qWarning() << "QAbstractItemModel::endInsertColumns: Invalid index (" << old.row() << ',' << old.column() + count << ") in model" << q_func();
}
}
}
@@ -669,7 +850,7 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &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();
+ qWarning() << "QAbstractItemModel::endRemoveColumns: Invalid index (" << old.row() << ',' << old.column() - count << ") in model" << q_func();
}
}
QVector<QPersistentModelIndexData *> persistent_invalidated = persistent.invalidated.pop();
@@ -688,51 +869,49 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
\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.
+ 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.
+ 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.
+ 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.
+ QAbstractItemModel. The child() function is used to examine items held
+ under 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
+ \sa {Model/View Programming}, 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.
+ 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
*/
@@ -795,7 +974,9 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
\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.
+
+ A valid index belongs to a model, and has non-negative row and column
+ numbers.
\sa model(), row(), column()
*/
@@ -806,33 +987,34 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
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.
+ A const pointer to the model is returned 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.
+ Returns the sibling at \a row and \a column. If there is no sibling at this
+ position, an invalid QModelIndex is returned.
- \sa parent() child()
+ \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.
+ Returns the child of the model index that is stored in the given \a row and
+ \a column.
- \sa parent() sibling()
+ \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.
+ Returns the data for the given \a role for the item referred to by the
+ index.
*/
/*!
@@ -845,28 +1027,29 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
/*!
\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.
+ Returns true if this model index refers to the same location as the
+ \a other model index; otherwise returns false.
+
+ 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.
+ 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
+ \fn QModelIndex QModelIndex::parent() const
- Returns the parent of the model index, or QModelIndex() if it has no
- parent.
+ Returns the parent of the model index, or QModelIndex() if it has no
+ parent.
- \sa child() sibling() model()
+ \sa child(), sibling(), model()
*/
/*!
@@ -876,7 +1059,7 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
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
@@ -895,7 +1078,7 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
simple table of rows and columns. Each item has a unique index specified by
a QModelIndex.
- \img modelindex-no-parent.png
+ \image 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
@@ -1013,9 +1196,8 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
\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}
+ {Simple DOM Model Example}, {Simple Tree Model Example},
+ {Editable Tree Model Example}, {Fetch More Example}
*/
/*!
@@ -1024,8 +1206,9 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
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.
+ 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()
*/
@@ -1034,8 +1217,9 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
\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.
+ the \a parent specified.
+
+ Returns true if the column is inserted; otherwise returns false.
\sa insertColumns() insertRow() removeColumn()
*/
@@ -1044,8 +1228,9 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
\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.
+ \a parent specified.
+
+ Returns true if the row is inserted; otherwise returns false.
\sa insertRows() insertColumn() removeRow()
*/
@@ -1058,17 +1243,18 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
/*!
\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.
+ Returns the parent of the model item with the given \a index. If the model
+ has no parent, an invalid QModelIndex is returned.
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.
+ 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
+ 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.
+ indexes belonging to your model will simply call your implementation,
+ leading to infinite recursion.
\sa createIndex()
*/
@@ -1076,7 +1262,9 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
/*!
\fn bool QAbstractItemModel::removeColumn(int column, const QModelIndex &parent)
- Removes the given \a column from the child items of the \a parent specified.
+ 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()
@@ -1086,10 +1274,11 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
\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.
+ This is a convenience function that calls removeRows(). The
+ QAbstractItemModel implementation of removeRows() does nothing.
\sa removeRows(), removeColumn(), insertRow()
*/
@@ -1101,13 +1290,12 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
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.
+ When reimplementing the setHeaderData() function, this signal must be
+ emitted explicitly.
- 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).
+ If you are changing the number of columns or rows you do not need to emit
+ this signal, but use the begin/end functions (refer to the section on
+ subclassing in the QAbstractItemModel class description for details).
\sa headerData(), setHeaderData(), dataChanged()
*/
@@ -1117,8 +1305,8 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
\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.
+ 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().
@@ -1130,19 +1318,29 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
\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
+ 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
+ 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().
+ Subclasses should update any persistent model indexes before emitting
+ layoutChanged(). In other words, when the structure changes:
+
+ \list
+ \o Call beginLayoutChanged()
+ \o Remember the QModelIndex that will change
+ \o Update your internal data
+ \o Call changePersistentIndex()
+ \o Call endLayoutChanged()
+ \endlist
+
- \sa layoutAboutToBeChanged(), dataChanged(), headerDataChanged(), reset(), changePersistentIndex()
+ \sa layoutAboutToBeChanged(), dataChanged(), headerDataChanged(), modelReset(),
+ changePersistentIndex()
*/
/*!
@@ -1172,12 +1370,12 @@ QAbstractItemModel::~QAbstractItemModel()
/*!
\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.
+ 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.
+ uses it to retrieve the index of the child item in the specified \a row and
+ \a column.
\sa index(), QModelIndex::row(), QModelIndex::column()
*/
@@ -1186,11 +1384,11 @@ QAbstractItemModel::~QAbstractItemModel()
/*!
\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.
+ 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.
+ \note When implementing a table based model, rowCount() should return 0
+ when the parent is valid.
\sa columnCount()
*/
@@ -1200,13 +1398,14 @@ QAbstractItemModel::~QAbstractItemModel()
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:
+ 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.
+ \note When implementing a table based model, columnCount() should return 0
+ when the parent is valid.
\sa rowCount()
*/
@@ -1233,8 +1432,8 @@ QAbstractItemModel::~QAbstractItemModel()
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
+ \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()
@@ -1243,11 +1442,11 @@ QAbstractItemModel::~QAbstractItemModel()
/*!
\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.
+ 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
+ \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.
@@ -1257,11 +1456,11 @@ QAbstractItemModel::~QAbstractItemModel()
/*!
\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.
+ 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
+ \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.
@@ -1271,11 +1470,11 @@ QAbstractItemModel::~QAbstractItemModel()
/*!
\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.
+ 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
+ \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.
@@ -1283,64 +1482,128 @@ QAbstractItemModel::~QAbstractItemModel()
*/
/*!
- \fn void QAbstractItemModel::columnsInserted(const QModelIndex &parent, int start, int end)
+ \fn void QAbstractItemModel::rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
+ \since 4.6
- 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.
+ This signal is emitted after rows have been moved within the
+ model. The items between \a sourceStart and \a sourceEnd
+ inclusive, under the given \a sourceParent item have been moved to \a destinationParent
+ starting at the row \a destinationRow.
\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()
+ \sa beginMoveRows()
*/
/*!
- \fn void QAbstractItemModel::columnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
+ \fn void QAbstractItemModel::rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
+ \since 4.6
- 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.
+ This signal is emitted just before rows are moved within the
+ model. The items that will be moved are those between \a sourceStart and \a sourceEnd
+ inclusive, under the given \a sourceParent item. They will be moved to \a destinationParent
+ starting at the row \a destinationRow.
\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()
+ \sa beginMoveRows()
*/
/*!
- \fn void QAbstractItemModel::columnsRemoved(const QModelIndex &parent, int start, int end)
+ \fn void QAbstractItemModel::columnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn)
+ \since 4.6
- 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.
+ This signal is emitted after columns have been moved within the
+ model. The items between \a sourceStart and \a sourceEnd
+ inclusive, under the given \a sourceParent item have been moved to \a destinationParent
+ starting at the column \a destinationColumn.
\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()
+ \sa beginMoveRows()
*/
/*!
- \fn void QAbstractItemModel::columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+ \fn void QAbstractItemModel::columnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn)
+ \since 4.6
- 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.
+ This signal is emitted just before columns are moved within the
+ model. The items that will be moved are those between \a sourceStart and \a sourceEnd
+ inclusive, under the given \a sourceParent item. They will be moved to \a destinationParent
+ starting at the column \a destinationColumn.
\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 beginMoveRows()
+*/
+
+/*!
+ \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.
+
+ \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.
+
+ \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.
+
+ \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.
+ \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.
+
+ \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
{
@@ -1351,10 +1614,11 @@ bool QAbstractItemModel::hasIndex(int row, int column, const QModelIndex &parent
/*!
- Returns true if \a parent has any children; otherwise returns false.
- Use rowCount() on the parent to find out the number of children.
+ 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()
+ \sa parent() index()
*/
bool QAbstractItemModel::hasChildren(const QModelIndex &parent) const
{
@@ -1363,11 +1627,11 @@ bool QAbstractItemModel::hasChildren(const QModelIndex &parent) const
/*!
- Returns a map with values for all predefined roles in the model
- for the item at the given \a index.
+ 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.
+ Reimplement this function if you want to extend the default behavior of
+ this function to include custom roles in the map.
\sa Qt::ItemDataRole, data()
*/
@@ -1376,7 +1640,7 @@ 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)
+ if (variantData.isValid())
roles.insert(i, variantData);
}
return roles;
@@ -1384,14 +1648,14 @@ QMap<int, QVariant> QAbstractItemModel::itemData(const QModelIndex &index) const
/*!
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 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.
+ The base class implementation returns false. This function and data() must
+ be reimplemented for editable models.
\sa Qt::ItemDataRole, data(), itemData()
*/
@@ -1410,15 +1674,16 @@ bool QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value
by the \a index.
\note If you do not have a value to return, return an \bold invalid
- QVariant() instead of returning 0.
+ 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.
+ \a roles, for every Qt::ItemDataRole.
+
+ Returns true if successful; otherwise returns false.
Roles that are not in \a roles will not be modified.
@@ -1433,8 +1698,8 @@ bool QAbstractItemModel::setItemData(const QModelIndex &index, const QMap<int, Q
}
/*!
- Returns a list of MIME types that can be used to describe a list of
- model indexes.
+ Returns a list of MIME types that can be used to describe a list of model
+ indexes.
\sa mimeData()
*/
@@ -1446,12 +1711,12 @@ QStringList QAbstractItemModel::mimeTypes() const
}
/*!
- 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.
+ 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.
+ 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()
*/
@@ -1473,22 +1738,23 @@ QMimeData *QAbstractItemModel::mimeData(const QModelIndexList &indexes) const
/*!
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.
+ the given \a action.
- 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.
+ Returns true if the data and action can be handled by the model; otherwise
+ returns false.
- 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.
+ 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.
- 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.
+ 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.
- Returns true if the dropping was successful otherwise false.
+ 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.
\sa supportedDropActions(), {Using Drag and Drop with Item Views}
*/
@@ -1518,17 +1784,17 @@ bool QAbstractItemModel::dropMimeData(const QMimeData *data, Qt::DropAction acti
}
/*!
- \since 4.2
+ \since 4.2
- Returns the drop actions supported by this model.
+ 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.
+ The default implementation returns Qt::CopyAction. Reimplement this
+ function if you wish to support additional actions. You must also
+ reimplement the dropMimeData() function to handle the additional
+ operations.
- \sa dropMimeData(), Qt::DropActions, {Using Drag and Drop with Item
- Views}
+ \sa dropMimeData(), Qt::DropActions, {Using Drag and Drop with Item
+ Views}
*/
Qt::DropActions QAbstractItemModel::supportedDropActions() const
{
@@ -1536,15 +1802,15 @@ Qt::DropActions QAbstractItemModel::supportedDropActions() const
}
/*!
- Returns the actions supported by the data in this model.
+ Returns the actions supported by the data in this model.
- The default implementation returns supportedDropActions() unless
- specific values have been set with setSupportedDragActions().
+ 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.
+ supportedDragActions() is used by QAbstractItemView::startDrag() as the
+ default values when a drag occurs.
- \sa Qt::DropActions, {Using Drag and Drop with Item Views}
+ \sa Qt::DropActions, {Using Drag and Drop with Item Views}
*/
Qt::DropActions QAbstractItemModel::supportedDragActions() const
{
@@ -1569,25 +1835,28 @@ void QAbstractItemModel::setSupportedDragActions(Qt::DropActions 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.
+ On models that support this, inserts \a count rows into the model before
+ the given \a row. 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.
+ If \a row is 0, the rows are prepended to any existing rows in the parent.
- Returns true if the rows were successfully inserted; otherwise returns
- false.
+ If \a row is rowCount(), the rows are appended to any existing rows in the
+ parent.
- The base class implementation does nothing and returns false.
+ If \a parent has no children, a single column with \a count rows is
+ inserted.
- 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.
+ Returns true if the rows were successfully inserted; otherwise returns
+ false.
+
+ The base class implementation does nothing and returns false.
- \sa insertColumns(), removeRows(), beginInsertRows(), endInsertRows()
+ If you implement your own model, you can reimplement this function if you
+ want to support insertions. Alternatively, you can provide your own API for
+ altering the data.
+
+ \sa insertColumns(), removeRows(), beginInsertRows(), endInsertRows()
*/
bool QAbstractItemModel::insertRows(int, int, const QModelIndex &)
{
@@ -1595,25 +1864,28 @@ bool QAbstractItemModel::insertRows(int, int, const QModelIndex &)
}
/*!
- 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.
+ 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 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.
+ If \a column is columnCount(), the columns are appended to any existing
+ columns.
- Returns true if the columns were successfully inserted; otherwise returns
- false.
+ If \a parent has no children, a single row with \a count columns is
+ inserted.
- The base class implementation does nothing and returns false.
+ 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.
+ If you implement your own model, you can reimplement this function if you
+ want to support insertions. Alternatively, you can provide your own API for
+ altering the data.
- \sa insertRows(), removeColumns(), beginInsertColumns(), endInsertColumns()
+ \sa insertRows(), removeColumns(), beginInsertColumns(), endInsertColumns()
*/
bool QAbstractItemModel::insertColumns(int, int, const QModelIndex &)
{
@@ -1622,16 +1894,19 @@ bool QAbstractItemModel::insertColumns(int, int, const QModelIndex &)
/*!
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.
+ \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.
+ If you implement your own model, you can reimplement this function if you
+ want to support removing. Alternatively, you can provide your own API for
+ altering the data.
- \sa removeRow(), removeColumns(), insertColumns(), beginRemoveRows(), endRemoveRows()
+ \sa removeRow(), removeColumns(), insertColumns(), beginRemoveRows(),
+ endRemoveRows()
*/
bool QAbstractItemModel::removeRows(int, int, const QModelIndex &)
{
@@ -1640,16 +1915,19 @@ bool QAbstractItemModel::removeRows(int, int, const QModelIndex &)
/*!
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.
+ 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.
+ If you implement your own model, you can reimplement this function if you
+ want to support removing. Alternatively, you can provide your own API for
+ altering the data.
- \sa removeColumn(), removeRows(), insertColumns(), beginRemoveColumns(), endRemoveColumns()
+ \sa removeColumn(), removeRows(), insertColumns(), beginRemoveColumns(),
+ endRemoveColumns()
*/
bool QAbstractItemModel::removeColumns(int, int, const QModelIndex &)
{
@@ -1672,9 +1950,9 @@ void QAbstractItemModel::fetchMore(const QModelIndex &)
}
/*!
- Returns true if there is more data available for \a parent; otherwise returns
- false.
-
+ 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().
@@ -1691,9 +1969,9 @@ bool QAbstractItemModel::canFetchMore(const QModelIndex &) const
/*!
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).
+ 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
*/
@@ -1719,12 +1997,13 @@ void QAbstractItemModel::sort(int column, Qt::SortOrder order)
}
/*!
- 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.
+ 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. Then, the
+ view will construct a delegate using the model index returned by the buddy
+ item.
- In the default implementation each item is its own buddy.
+ The default implementation of this function has each item as its own buddy.
*/
QModelIndex QAbstractItemModel::buddy(const QModelIndex &index) const
{
@@ -1732,23 +2011,23 @@ QModelIndex QAbstractItemModel::buddy(const QModelIndex &index) const
}
/*!
- 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.
+ Returns a list of indexes for the items in the column of the \a start index
+ where 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.
+ The search begins 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.
+
+ \note The default implementation of this function only searches columns.
+ Reimplement this function to include a different search behavior.
*/
QModelIndexList QAbstractItemModel::match(const QModelIndex &start, int role,
const QVariant &value, int hits,
@@ -1823,7 +2102,7 @@ QModelIndexList QAbstractItemModel::match(const QModelIndex &start, int role,
/*!
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.
+ \note Currently, span is not used.
*/
QSize QAbstractItemModel::span(const QModelIndex &) const
@@ -1832,10 +2111,43 @@ QSize QAbstractItemModel::span(const QModelIndex &) const
}
/*!
- Called to let the model know that it should submit whatever it has cached
- to the permanent storage. Typically used for row editing.
+ \since 4.6
+
+ Sets the model's role names to \a roleNames.
+
+ This function allows mapping of role identifiers to role property names in
+ Declarative UI. This function must be called before the model is used.
+ Modifying the role names after the model has been set may result in
+ undefined behaviour.
+
+ \sa roleNames()
+*/
+void QAbstractItemModel::setRoleNames(const QHash<int,QByteArray> &roleNames)
+{
+ Q_D(QAbstractItemModel);
+ d->roleNames = roleNames;
+}
+
+/*!
+ \since 4.6
+
+ Returns the model's role names.
+
+ \sa setRoleNames()
+*/
+const QHash<int,QByteArray> &QAbstractItemModel::roleNames() const
+{
+ Q_D(const QAbstractItemModel);
+ return d->roleNames;
+}
+
+/*!
+ Lets the model know that it should submit cached information to permanent
+ storage. This function is typically used for row editing.
+
+ Returns true if there is no error; otherwise returns false.
- Returns false on error, otherwise true.
+ \sa revert()
*/
bool QAbstractItemModel::submit()
@@ -1844,8 +2156,10 @@ bool QAbstractItemModel::submit()
}
/*!
- Called to let the model know that it should discard whatever it has cached.
- Typically used for row editing.
+ Lets the model know that it should discard cached information. This
+ function is typically used for row editing.
+
+ \sa submit()
*/
void QAbstractItemModel::revert()
@@ -1854,14 +2168,14 @@ void QAbstractItemModel::revert()
}
/*!
- Returns the data for the given \a role and \a section in the header
- with the specified \a orientation.
+ 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.
+ For horizontal headers, the section number corresponds to the column
+ number. Similarly, for vertical headers, the section number corresponds to
+ the row number.
- \sa Qt::ItemDataRole, setHeaderData(), QHeaderView
+ \sa Qt::ItemDataRole, setHeaderData(), QHeaderView
*/
QVariant QAbstractItemModel::headerData(int section, Qt::Orientation orientation, int role) const
@@ -1873,14 +2187,15 @@ QVariant QAbstractItemModel::headerData(int section, Qt::Orientation orientation
}
/*!
- 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.
+ Sets the data for the given \a role and \a section in the header with the
+ specified \a orientation to the \a value supplied.
- Note that the headerDataChanged() signal must be emitted explicitly
- when reimplementing this function.
+ Returns true if the header's data was updated; otherwise returns false.
- \sa Qt::ItemDataRole, headerData()
+ When reimplementing this function, the headerDataChanged() signal must be
+ emitted explicitly.
+
+ \sa Qt::ItemDataRole, headerData()
*/
bool QAbstractItemModel::setHeaderData(int section, Qt::Orientation orientation,
@@ -1896,11 +2211,12 @@ bool QAbstractItemModel::setHeaderData(int section, Qt::Orientation orientation,
/*!
\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.
+ 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.
+ When using a QSortFilterProxyModel, its indexes have their own internal
+ pointer. It is not advisable to access this internal pointer outside of the
+ model. Use the data() function instead.
This function provides a consistent interface that model subclasses must
use to create model indexes.
@@ -1910,7 +2226,8 @@ bool QAbstractItemModel::setHeaderData(int section, Qt::Orientation orientation,
\fn QModelIndex QAbstractItemModel::createIndex(int row, int column, int id) const
\obsolete
- Use QModelIndex QAbstractItemModel::createIndex(int row, int column, quint32 id) instead.
+ Use QModelIndex
+ QAbstractItemModel::createIndex(int row, int column, quint32 id) instead.
*/
/*!
@@ -1921,6 +2238,7 @@ bool QAbstractItemModel::setHeaderData(int section, Qt::Orientation orientation,
This function provides a consistent interface that model subclasses must
use to create model indexes.
+
\sa QModelIndex::internalId()
*/
@@ -2024,34 +2342,41 @@ bool QAbstractItemModel::decodeData(int row, int column, const QModelIndex &pare
/*!
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.
+ 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.
+ 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.
+ \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
+ \note This function emits the rowsAboutToBeInserted() signal which
+ connected views (or proxies) must handle before the data is inserted.
+ Otherwise, the views may end up in an invalid state.
\sa endInsertRows()
*/
void QAbstractItemModel::beginInsertRows(const QModelIndex &parent, int first, int last)
@@ -2067,9 +2392,8 @@ void QAbstractItemModel::beginInsertRows(const QModelIndex &parent, int first, i
/*!
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.
+ When reimplementing insertRows() in a subclass, you must call this function
+ \e after inserting data into the model's underlying data store.
\sa beginInsertRows()
*/
@@ -2085,23 +2409,28 @@ void QAbstractItemModel::endInsertRows()
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.
+ 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.
+ 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.
+ \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:
- 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
+ \snippet doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp 2
\endtable
+ \note This function emits the rowsAboutToBeRemoved() signal which connected
+ views (or proxies) must handle before the data is removed. Otherwise, the
+ views may end up in an invalid state.
+
\sa endRemoveRows()
*/
void QAbstractItemModel::beginRemoveRows(const QModelIndex &parent, int first, int last)
@@ -2117,9 +2446,8 @@ void QAbstractItemModel::beginRemoveRows(const QModelIndex &parent, int first, i
/*!
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.
+ When reimplementing removeRows() in a subclass, you must call this function
+ \e after removing data from the model's underlying data store.
\sa beginRemoveRows()
*/
@@ -2132,36 +2460,161 @@ void QAbstractItemModel::endRemoveRows()
}
/*!
+ Returns whether a move operation is valid.
+
+ A move operation is not allowed if it moves a continuous range of rows to a destination within
+ itself, or if it attempts to move a row to one of its own descendants.
+
+ \internal
+*/
+bool QAbstractItemModelPrivate::allowMove(const QModelIndex &srcParent, int start, int end, const QModelIndex &destinationParent, int destinationStart, Qt::Orientation orientation)
+{
+ Q_Q(QAbstractItemModel);
+ // Don't move the range within itself.
+ if ( ( destinationParent == srcParent )
+ && ( destinationStart >= start )
+ && ( destinationStart <= end + 1) )
+ return false;
+
+ QModelIndex destinationAncestor = destinationParent;
+ int pos = (Qt::Vertical == orientation) ? destinationAncestor.row() : destinationAncestor.column();
+ forever {
+ if (destinationAncestor == srcParent) {
+ if (pos >= start && pos <= end)
+ return false;
+ break;
+ }
+
+ if (!destinationAncestor.isValid())
+ break;
+
+ pos = (Qt::Vertical == orientation) ? destinationAncestor.row() : destinationAncestor.column();
+ destinationAncestor = destinationAncestor.parent();
+ }
+
+ return true;
+}
+
+/*!
+ Begins a row move operation.
+
+ When reimplementing a subclass, this method simplifies moving
+ entities in your model. This method is responsible for moving
+ persistent indexes in the model, which you would otherwise be
+ required to do yourself.
+
+ Using beginMoveRows and endMoveRows is an alternative to emitting
+ layoutAboutToBeChanged and layoutChanged directly along with
+ changePersistentIndexes. layoutAboutToBeChanged is emitted by
+ this method for compatibility reasons.
+
+ The \a sourceParent index corresponds to the parent from which the
+ rows are moved; \a sourceFirst and \a sourceLast are the row
+ numbers of the rows to be moved. The \a destinationParent index
+ corresponds to the parent into which the rows are moved. The \a
+ destinationChild is the row to which the rows will be moved. That
+ is, the index at row \a sourceFirst in \a sourceParent will become
+ row \a destinationChild in \a destinationParent. Its siblings will
+ be moved correspondingly.
+
+ Note that \a sourceParent and \a destinationParent may be the
+ same, in which case you must ensure that the \a destinationChild is
+ not within the range of \a sourceFirst and \a sourceLast. You
+ must also ensure that you do not attempt to move a row to one of
+ its own chilren or ancestors. This method returns false if either
+ condition is true, in which case you should abort your move
+ operation.
+
+ \sa endMoveRows()
+
+ \since 4.6
+*/
+bool QAbstractItemModel::beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationChild)
+{
+ Q_ASSERT(sourceFirst >= 0);
+ Q_ASSERT(sourceLast >= sourceFirst);
+ Q_ASSERT(destinationChild >= 0);
+ Q_D(QAbstractItemModel);
+
+ if (!d->allowMove(sourceParent, sourceFirst, sourceLast, destinationParent, destinationChild, Qt::Vertical)) {
+ return false;
+ }
+
+ d->changes.push(QAbstractItemModelPrivate::Change(sourceParent, sourceFirst, sourceLast));
+ int destinationLast = destinationChild + (sourceLast - sourceFirst);
+ d->changes.push(QAbstractItemModelPrivate::Change(destinationParent, destinationChild, destinationLast));
+
+ d->itemsAboutToBeMoved(sourceParent, sourceFirst, sourceLast, destinationParent, destinationChild, Qt::Vertical);
+ emit rowsAboutToBeMoved(sourceParent, sourceFirst, sourceLast, destinationParent, destinationChild);
+ emit layoutAboutToBeChanged();
+ return true;
+}
+
+/*!
+ Ends a row move operation.
+
+ When implementing a subclass, you must call this
+ function \e after moving data within the model's underlying data
+ store.
+
+ layoutChanged is emitted by this method for compatibility reasons.
+
+ \sa beginMoveRows()
+
+ \since 4.6
+*/
+void QAbstractItemModel::endMoveRows()
+{
+ Q_D(QAbstractItemModel);
+
+ QAbstractItemModelPrivate::Change insertChange = d->changes.pop();
+ QAbstractItemModelPrivate::Change removeChange = d->changes.pop();
+
+ d->itemsMoved(removeChange.parent, removeChange.first, removeChange.last, insertChange.parent, insertChange.first, Qt::Vertical);
+
+ emit rowsMoved(removeChange.parent, removeChange.first, removeChange.last, insertChange.parent, insertChange.first);
+ emit layoutChanged();
+}
+
+/*!
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.
+ 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.
+ 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.
+ \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
+ \note This function emits the columnsAboutToBeInserted() signal which
+ connected views (or proxies) must handle before the data is inserted.
+ Otherwise, the views may end up in an invalid state.
+
\sa endInsertColumns()
*/
void QAbstractItemModel::beginInsertColumns(const QModelIndex &parent, int first, int last)
@@ -2195,23 +2648,28 @@ void QAbstractItemModel::endInsertColumns()
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.
+ 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.
+ 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.
+ \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
+ 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
+ \note This function emits the columnsAboutToBeRemoved() signal which
+ connected views (or proxies) must handle before the data is removed.
+ Otherwise, the views may end up in an invalid state.
+
\sa endRemoveColumns()
*/
void QAbstractItemModel::beginRemoveColumns(const QModelIndex &parent, int first, int last)
@@ -2228,8 +2686,7 @@ void QAbstractItemModel::beginRemoveColumns(const QModelIndex &parent, int first
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.
+ function \e after removing data from the model's underlying data store.
\sa beginRemoveColumns()
*/
@@ -2242,35 +2699,152 @@ void QAbstractItemModel::endRemoveColumns()
}
/*!
+ Begins a column move operation.
+
+ When reimplementing a subclass, this method simplifies moving
+ entities in your model. This method is responsible for moving
+ persistent indexes in the model, which you would otherwise be
+ required to do yourself.
+
+ Using beginMoveColumns and endMoveColumns is an alternative to
+ emitting layoutAboutToBeChanged and layoutChanged directly along
+ with changePersistentIndexes. layoutAboutToBeChanged is emitted
+ by this method for compatibility reasons.
+
+ The \a sourceParent index corresponds to the parent from which the
+ columns are moved; \a sourceFirst and \a sourceLast are the column
+ numbers of the columns to be moved. The \a destinationParent index
+ corresponds to the parent into which the columns are moved. The \a
+ destinationChild is the column to which the columns will be
+ moved. That is, the index at column \a sourceFirst in \a
+ sourceParent will become column \a destinationChild in \a
+ destinationParent. Its siblings will be moved correspondingly.
+
+ Note that \a sourceParent and \a destinationParent may be the
+ same, in which case you must ensure that the \a destinationChild
+ is not within the range of \a sourceFirst and \a sourceLast. You
+ must also ensure that you do not attempt to move a row to one of
+ its own chilren or ancestors. This method returns false if either
+ condition is true, in which case you should abort your move
+ operation.
+
+ \sa endMoveColumns()
+
+ \since 4.6
+*/
+bool QAbstractItemModel::beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationChild)
+{
+ Q_ASSERT(sourceFirst >= 0);
+ Q_ASSERT(sourceLast >= sourceFirst);
+ Q_ASSERT(destinationChild >= 0);
+ Q_D(QAbstractItemModel);
+
+ if (!d->allowMove(sourceParent, sourceFirst, sourceLast, destinationParent, destinationChild, Qt::Horizontal)) {
+ return false;
+ }
+
+ d->changes.push(QAbstractItemModelPrivate::Change(sourceParent, sourceFirst, sourceLast));
+ int destinationLast = destinationChild + (sourceLast - sourceFirst);
+ d->changes.push(QAbstractItemModelPrivate::Change(destinationParent, destinationChild, destinationLast));
+
+ d->itemsAboutToBeMoved(sourceParent, sourceFirst, sourceLast, destinationParent, destinationChild, Qt::Horizontal);
+
+ emit columnsAboutToBeMoved(sourceParent, sourceFirst, sourceLast, destinationParent, destinationChild);
+ emit layoutAboutToBeChanged();
+ return true;
+}
+
+/*!
+ Ends a column move operation.
+
+ When implementing a subclass, you must call this
+ function \e after moving data within the model's underlying data
+ store.
+
+ layoutChanged is emitted by this method for compatibility reasons.
+
+ \sa beginMoveColumns()
+
+ \since 4.6
+*/
+void QAbstractItemModel::endMoveColumns()
+{
+ Q_D(QAbstractItemModel);
+
+ QAbstractItemModelPrivate::Change insertChange = d->changes.pop();
+ QAbstractItemModelPrivate::Change removeChange = d->changes.pop();
+
+ d->itemsMoved(removeChange.parent, removeChange.first, removeChange.last, insertChange.parent, insertChange.first, Qt::Horizontal);
+
+ emit columnsMoved(removeChange.parent, removeChange.first, removeChange.last, insertChange.parent, insertChange.first);
+ emit layoutChanged();
+}
+
+/*!
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.
+ \note Use beginResetModel() and endResetModel() instead whenever possible.
+ Use this method only if there is no way to call beginResetModel() before invalidating the model.
+ Otherwise it could lead to unexcpected behaviour, especially when used with proxy models.
+*/
+void QAbstractItemModel::reset()
+{
+ Q_D(QAbstractItemModel);
+ emit modelAboutToBeReset();
+ d->invalidatePersistentIndexes();
+ emit modelReset();
+}
+
+/*!
+ Begins a model reset operation.
+
+ A reset operation resets the model to its current state in any attached views.
+
+ \note Any views attached to this model 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.
+ model is now invalid and has to be queried for again. This also means that
+ the current item and any selected items will become invalid.
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()
+ You must call this function before resetting any internal data structures in your model
+ or proxy model.
+
+ \sa modelAboutToBeReset(), modelReset(), endResetModel()
+ \since 4.6
*/
-void QAbstractItemModel::reset()
+void QAbstractItemModel::beginResetModel()
{
- Q_D(QAbstractItemModel);
emit modelAboutToBeReset();
+}
+
+/*!
+ Completes a model reset operation.
+
+ You must call this function after resetting any internal data structure in your model
+ or proxy model.
+
+ \sa beginResetModel()
+ \since 4.6
+*/
+void QAbstractItemModel::endResetModel()
+{
+ Q_D(QAbstractItemModel);
d->invalidatePersistentIndexes();
emit modelReset();
}
/*!
- Changes the QPersistentModelIndex that is equal to the given \a from
- model index to the given \a to model index.
+ 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.
+ If no persistent model index equal to the given \a from model index was
+ found, nothing is changed.
- \sa persistentIndexList(), changePersistentIndexList()
+ \sa persistentIndexList(), changePersistentIndexList()
*/
void QAbstractItemModel::changePersistentIndex(const QModelIndex &from, const QModelIndex &to)
{
@@ -2291,15 +2865,15 @@ void QAbstractItemModel::changePersistentIndex(const QModelIndex &from, const QM
}
/*!
- \since 4.1
+ \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.
+ 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.
+ 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()
+ \sa persistentIndexList(), changePersistentIndex()
*/
void QAbstractItemModel::changePersistentIndexList(const QModelIndexList &from,
const QModelIndexList &to)
@@ -2332,9 +2906,9 @@ void QAbstractItemModel::changePersistentIndexList(const QModelIndexList &from,
}
/*!
- \since 4.2
+ \since 4.2
- Returns the list of indexes stored as persistent indexes in the model.
+ Returns the list of indexes stored as persistent indexes in the model.
*/
QModelIndexList QAbstractItemModel::persistentIndexList() const
{
@@ -2361,10 +2935,10 @@ QModelIndexList QAbstractItemModel::persistentIndexList() const
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.
+ 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
@@ -2372,9 +2946,6 @@ QModelIndexList QAbstractItemModel::persistentIndexList() const
\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.
@@ -2405,9 +2976,13 @@ QModelIndexList QAbstractItemModel::persistentIndexList() const
call endRemoveColumns() \e{immediately afterwards}.
\endlist
- \sa {Model Classes}, {Model Subclassing Reference}, QAbstractItemModel,
- QAbstractListModel,
- {Pixelator Example}
+ \note Some general guidelines for subclassing models are available in the
+ \l{Model Subclassing Reference}.
+
+ \note
+
+ \sa {Model Classes}, QAbstractItemModel, QAbstractListModel,
+ {Pixelator Example}
*/
/*!
@@ -2505,9 +3080,6 @@ bool QAbstractTableModel::hasChildren(const QModelIndex &parent) const
\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.
@@ -2534,6 +3106,9 @@ bool QAbstractTableModel::hasChildren(const QModelIndex &parent) const
call endRemoveRows() \e{immediately afterwards}.
\endlist
+ \note Some general guidelines for subclassing models are available in the
+ \l{Model Subclassing Reference}.
+
\sa {Model Classes}, {Model Subclassing Reference}, QAbstractItemView,
QAbstractTableModel, {Item Views Puzzle Example}
*/
@@ -2729,7 +3304,7 @@ bool QAbstractListModel::dropMimeData(const QMimeData *data, Qt::DropAction acti
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()
+ \sa beginResetModel(), modelReset()
*/
/*!
@@ -2739,7 +3314,7 @@ bool QAbstractListModel::dropMimeData(const QMimeData *data, Qt::DropAction acti
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()
+ \sa endResetModel(), modelAboutToBeReset()
*/
/*!
diff --git a/src/corelib/kernel/qabstractitemmodel.h b/src/corelib/kernel/qabstractitemmodel.h
index d8d98ac..1cb4e8b 100644
--- a/src/corelib/kernel/qabstractitemmodel.h
+++ b/src/corelib/kernel/qabstractitemmodel.h
@@ -220,6 +220,8 @@ public:
Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const;
virtual QSize span(const QModelIndex &index) const;
+ const QHash<int,QByteArray> &roleNames() const;
+
#ifdef Q_NO_USING_KEYWORD
inline QObject *parent() const { return QObject::parent(); }
#else
@@ -250,6 +252,13 @@ private: // can only be emitted by QAbstractItemModel
void modelAboutToBeReset();
void modelReset();
+ void rowsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow );
+ void rowsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row );
+
+ void columnsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn );
+ void columnsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column );
+
+
public Q_SLOTS:
virtual bool submit();
virtual void revert();
@@ -270,18 +279,29 @@ protected:
void beginRemoveRows(const QModelIndex &parent, int first, int last);
void endRemoveRows();
+ bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationRow);
+ void endMoveRows();
+
void beginInsertColumns(const QModelIndex &parent, int first, int last);
void endInsertColumns();
void beginRemoveColumns(const QModelIndex &parent, int first, int last);
void endRemoveColumns();
+ bool beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationColumn);
+ void endMoveColumns();
+
void reset();
+ void beginResetModel();
+ void endResetModel();
+
void changePersistentIndex(const QModelIndex &from, const QModelIndex &to);
void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to);
QModelIndexList persistentIndexList() const;
+ void setRoleNames(const QHash<int,QByteArray> &roleNames);
+
private:
Q_DECLARE_PRIVATE(QAbstractItemModel)
Q_DISABLE_COPY(QAbstractItemModel)
diff --git a/src/corelib/kernel/qabstractitemmodel_p.h b/src/corelib/kernel/qabstractitemmodel_p.h
index ebd9288..484147e 100644
--- a/src/corelib/kernel/qabstractitemmodel_p.h
+++ b/src/corelib/kernel/qabstractitemmodel_p.h
@@ -61,7 +61,7 @@
QT_BEGIN_NAMESPACE
-class Q_CORE_EXPORT QPersistentModelIndexData
+class QPersistentModelIndexData
{
public:
QPersistentModelIndexData() : model(0) {}
@@ -78,8 +78,9 @@ class Q_CORE_EXPORT QAbstractItemModelPrivate : public QObjectPrivate
Q_DECLARE_PUBLIC(QAbstractItemModel)
public:
- QAbstractItemModelPrivate() : QObjectPrivate(), supportedDragActions(-1) {}
+ QAbstractItemModelPrivate() : QObjectPrivate(), supportedDragActions(-1), roleNames(defaultRoleNames()) {}
void removePersistentIndexData(QPersistentModelIndexData *data);
+ void movePersistentIndexes(QVector<QPersistentModelIndexData *> indexes, int change, const QModelIndex &parent, Qt::Orientation orientation);
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);
@@ -89,7 +90,12 @@ public:
void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
void columnsRemoved(const QModelIndex &parent, int first, int last);
static QAbstractItemModel *staticEmptyModel();
+ static bool variantLessThan(const QVariant &v1, const QVariant &v2);
+ void itemsAboutToBeMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation);
+ void itemsMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation);
+ bool allowMove(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation);
+
inline QModelIndex createIndex(int row, int column, void *data = 0) const {
return q_func()->createIndex(row, column, data);
}
@@ -131,6 +137,8 @@ public:
Change(const QModelIndex &p, int f, int l) : parent(p), first(f), last(l) {}
QModelIndex parent;
int first, last;
+
+ bool isValid() { return first >= 0 && last >= 0; }
};
QStack<Change> changes;
@@ -143,6 +151,9 @@ public:
} persistent;
Qt::DropActions supportedDragActions;
+
+ QHash<int,QByteArray> roleNames;
+ static const QHash<int,QByteArray> &defaultRoleNames();
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qbasictimer.cpp b/src/corelib/kernel/qbasictimer.cpp
index 362177a..9c9cfcb 100644
--- a/src/corelib/kernel/qbasictimer.cpp
+++ b/src/corelib/kernel/qbasictimer.cpp
@@ -49,7 +49,6 @@ 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
diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp
new file mode 100644
index 0000000..a263cc4
--- /dev/null
+++ b/src/corelib/kernel/qcore_symbian_p.cpp
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <exception>
+#include <e32base.h>
+#include <e32uid.h>
+#include "qcore_symbian_p.h"
+#include <string>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Helper function for calling into Symbian classes that expect a TDes&.
+ This function converts a QString to a TDes by allocating memory that
+ must be deleted by the caller.
+*/
+
+Q_CORE_EXPORT HBufC* qt_QString2HBufC(const QString& aString)
+{
+ HBufC *buffer;
+#ifdef QT_NO_UNICODE
+ TPtrC8 ptr(reinterpret_cast<const TUint8*>(aString.toLocal8Bit().constData()));
+#else
+ TPtrC16 ptr(qt_QString2TPtrC(aString));
+#endif
+ buffer = q_check_ptr(HBufC::New(ptr.Length()));
+ buffer->Des().Copy(ptr);
+ return buffer;
+}
+
+Q_CORE_EXPORT QString qt_TDesC2QString(const TDesC& aDescriptor)
+{
+#ifdef QT_NO_UNICODE
+ return QString::fromLocal8Bit(aDescriptor.Ptr(), aDescriptor.Length());
+#else
+ return QString::fromUtf16(aDescriptor.Ptr(), aDescriptor.Length());
+#endif
+}
+
+QHBufC::QHBufC()
+ : m_hBufC(0)
+{
+}
+
+QHBufC::QHBufC(const QHBufC &src)
+ : m_hBufC(q_check_ptr(src.m_hBufC->Alloc()))
+{
+}
+
+/*!
+ \internal
+ Constructs a QHBufC from an HBufC. Note that the QHBufC instance takes
+ ownership of the HBufC.
+*/
+QHBufC::QHBufC(HBufC *src)
+ : m_hBufC(src)
+{
+}
+
+QHBufC::QHBufC(const QString &src)
+{
+ m_hBufC = qt_QString2HBufC(src);
+}
+
+QHBufC::~QHBufC()
+{
+ if (m_hBufC)
+ delete m_hBufC;
+}
+
+class QS60PluginResolver
+{
+public:
+ QS60PluginResolver()
+ : initTried(false) {}
+
+ ~QS60PluginResolver() {
+ lib.Close();
+ }
+
+ TLibraryFunction resolve(int ordinal) {
+ if (!initTried) {
+ init();
+ initTried = true;
+ }
+
+ if (lib.Handle())
+ return lib.Lookup(ordinal);
+ else
+ return reinterpret_cast<TLibraryFunction>(NULL);
+ }
+
+private:
+ void init()
+ {
+#ifdef Q_WS_S60
+ _LIT(KLibName_3_1, "qts60plugin_3_1.dll");
+ _LIT(KLibName_3_2, "qts60plugin_3_2.dll");
+ _LIT(KLibName_5_0, "qts60plugin_5_0.dll");
+ TPtrC libName;
+ TInt uidValue;
+ switch (QSysInfo::s60Version()) {
+ case QSysInfo::SV_S60_3_1:
+ libName.Set(KLibName_3_1);
+ uidValue = 0x2001E620;
+ break;
+ case QSysInfo::SV_S60_3_2:
+ libName.Set(KLibName_3_2);
+ uidValue = 0x2001E621;
+ break;
+ case QSysInfo::SV_S60_5_0: // Fall through to default
+ default:
+ // Default to 5.0 version, as any unknown platform is likely to be newer than that
+ libName.Set(KLibName_5_0);
+ uidValue = 0x2001E622;
+ break;
+ }
+
+ TUidType libUid(KDynamicLibraryUid, KSharedLibraryUid, TUid::Uid(uidValue));
+ lib.Load(libName, libUid);
+#endif
+ }
+
+ RLibrary lib;
+ bool initTried;
+};
+
+Q_GLOBAL_STATIC(QS60PluginResolver, qt_s60_plugin_resolver);
+
+/*!
+ \internal
+ Resolves a platform version specific function from S60 plugin.
+ If plugin is missing or resolving fails for another reason, NULL is returned.
+*/
+Q_CORE_EXPORT TLibraryFunction qt_resolveS60PluginFunc(int ordinal)
+{
+ return qt_s60_plugin_resolver()->resolve(ordinal);
+}
+
+class QS60RFsSession
+{
+public:
+ QS60RFsSession() {
+ qt_symbian_throwIfError(iFs.Connect());
+ qt_symbian_throwIfError(iFs.ShareProtected());
+ }
+
+ ~QS60RFsSession() {
+ iFs.Close();
+ }
+
+ RFs& GetRFs() {
+ return iFs;
+ }
+
+private:
+
+ RFs iFs;
+};
+
+Q_GLOBAL_STATIC(QS60RFsSession, qt_s60_RFsSession);
+
+Q_CORE_EXPORT RFs& qt_s60GetRFs()
+{
+ return qt_s60_RFsSession()->GetRFs();
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qcore_symbian_p.h b/src/corelib/kernel/qcore_symbian_p.h
new file mode 100644
index 0000000..a7f71a7
--- /dev/null
+++ b/src/corelib/kernel/qcore_symbian_p.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCORE_SYMBIAN_P_H
+#define QCORE_SYMBIAN_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 <e32std.h>
+#include <QtCore/qglobal.h>
+#include <qstring.h>
+#include <qrect.h>
+#include <qhash.h>
+#include <f32file.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+Q_CORE_EXPORT HBufC* qt_QString2HBufC(const QString& aString);
+
+Q_CORE_EXPORT QString qt_TDesC2QString(const TDesC& aDescriptor);
+inline QString qt_TDes2QString(const TDes& aDescriptor) { return qt_TDesC2QString(aDescriptor); }
+
+static inline QSize qt_TSize2QSize(const TSize& ts)
+{
+ return QSize(ts.iWidth, ts.iHeight);
+}
+
+static inline TSize qt_QSize2TSize(const QSize& qs)
+{
+ return TSize(qs.width(), qs.height());
+}
+
+static inline QRect qt_TRect2QRect(const TRect& tr)
+{
+ return QRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height());
+}
+
+static inline TRect qt_QRect2TRect(const QRect& qr)
+{
+ return TRect(TPoint(qr.left(), qr.top()), TSize(qr.width(), qr.height()));
+}
+
+// Returned TPtrC is valid as long as the given parameter is valid and unmodified
+static inline TPtrC qt_QString2TPtrC( const QString& string )
+{
+ return TPtrC16(static_cast<const TUint16*>(string.utf16()), string.length());
+}
+
+/*!
+ \internal
+ This class is a wrapper around the Symbian HBufC descriptor class.
+ It makes sure that the heap allocated HBufC class is freed when it is
+ destroyed.
+*/
+class Q_CORE_EXPORT QHBufC
+{
+public:
+ QHBufC();
+ QHBufC(const QHBufC &src);
+ QHBufC(HBufC *src);
+ QHBufC(const QString &src);
+ ~QHBufC();
+
+ inline operator HBufC *() { return m_hBufC; }
+ inline operator const HBufC *() const { return m_hBufC; }
+ inline HBufC *data() { return m_hBufC; }
+ inline const HBufC *data() const { return m_hBufC; }
+ inline HBufC & operator*() { return *m_hBufC; }
+ inline const HBufC & operator*() const { return *m_hBufC; }
+ inline HBufC * operator->() { return m_hBufC; }
+ inline const HBufC * operator->() const { return m_hBufC; }
+
+ inline bool operator==(const QHBufC &param) const { return data() == param.data(); }
+ inline bool operator!=(const QHBufC &param) const { return data() != param.data(); }
+
+private:
+ HBufC *m_hBufC;
+};
+
+inline uint qHash(TUid uid)
+{
+ return qHash(uid.iUid);
+}
+
+// S60 version specific function ordinals that can be resolved
+enum S60PluginFuncOrdinals
+{
+ S60Plugin_TimeFormatL = 1,
+ S60Plugin_GetTimeFormatSpec = 2,
+ S60Plugin_GetLongDateFormatSpec = 3,
+ S60Plugin_GetShortDateFormatSpec = 4,
+ S60Plugin_LocalizedDirectoryName = 5
+};
+
+Q_CORE_EXPORT TLibraryFunction qt_resolveS60PluginFunc(int ordinal);
+
+Q_CORE_EXPORT RFs& qt_s60GetRFs();
+
+// Defined in qlocale_symbian.cpp.
+Q_CORE_EXPORT QByteArray qt_symbianLocaleName(int code);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QCORE_SYMBIAN_P_H
diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp
new file mode 100644
index 0000000..0d2d1de
--- /dev/null
+++ b/src/corelib/kernel/qcore_unix.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcore_unix_p.h"
+
+#ifndef Q_OS_VXWORKS
+# include <sys/select.h>
+# include <sys/time.h>
+#else
+# include <selectLib.h>
+#endif
+
+#include <stdlib.h>
+
+#ifdef Q_OS_MAC
+#include <mach/mach_time.h>
+#endif
+
+#if !defined(QT_NO_CLOCK_MONOTONIC)
+# if defined(QT_BOOTSTRAPPED)
+# define QT_NO_CLOCK_MONOTONIC
+# endif
+#endif
+
+QT_BEGIN_NAMESPACE
+
+bool qt_gettime_is_monotonic()
+{
+#if (_POSIX_MONOTONIC_CLOCK-0 > 0) || defined(Q_OS_MAC)
+ return true;
+#else
+ static int returnValue = 0;
+
+ if (returnValue == 0) {
+# if (_POSIX_MONOTONIC_CLOCK-0 < 0)
+ returnValue = -1;
+# elif (_POSIX_MONOTONIC_CLOCK == 0)
+ // detect if the system support monotonic timers
+ long x = sysconf(_SC_MONOTONIC_CLOCK);
+ returnValue = (x >= 200112L) ? 1 : -1;
+# endif
+ }
+
+ return returnValue != -1;
+#endif
+}
+
+timeval qt_gettime()
+{
+ timeval tv;
+#if defined(Q_OS_MAC)
+ static mach_timebase_info_data_t info = {0,0};
+ if (info.denom == 0)
+ mach_timebase_info(&info);
+
+ uint64_t cpu_time = mach_absolute_time();
+ uint64_t nsecs = cpu_time * (info.numer / info.denom);
+ tv.tv_sec = nsecs / 1000000000ull;
+ tv.tv_usec = (nsecs / 1000) - (tv.tv_sec * 1000000);
+ return tv;
+#elif (_POSIX_MONOTONIC_CLOCK-0 > 0)
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
+ return tv;
+#else
+# if !defined(QT_NO_CLOCK_MONOTONIC) && !defined(QT_BOOTSTRAPPED)
+ if (qt_gettime_is_monotonic()) {
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
+ return tv;
+ }
+# endif
+ // use gettimeofday
+ ::gettimeofday(&tv, 0);
+ return tv;
+#endif
+}
+
+static inline bool time_update(struct timeval *tv, const struct timeval &start,
+ const struct timeval &timeout)
+{
+ if (!qt_gettime_is_monotonic()) {
+ // we cannot recalculate the timeout without a monotonic clock as the time may have changed
+ return false;
+ }
+
+ // clock source is monotonic, so we can recalculate how much timeout is left
+ struct timeval now = qt_gettime();
+ *tv = timeout + start - now;
+ return true;
+}
+
+int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
+ const struct timeval *orig_timeout)
+{
+ if (!orig_timeout) {
+ // no timeout -> block forever
+ register int ret;
+ EINTR_LOOP(ret, select(nfds, fdread, fdwrite, fdexcept, 0));
+ return ret;
+ }
+
+ timeval start = qt_gettime();
+ timeval timeout = *orig_timeout;
+
+ // loop and recalculate the timeout as needed
+ int ret;
+ forever {
+ ret = ::select(nfds, fdread, fdwrite, fdexcept, &timeout);
+ if (ret != -1 || errno != EINTR)
+ return ret;
+
+ // recalculate the timeout
+ if (!time_update(&timeout, start, *orig_timeout)) {
+ // clock reset, fake timeout error
+ return 0;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h
new file mode 100644
index 0000000..698b05b
--- /dev/null
+++ b/src/corelib/kernel/qcore_unix_p.h
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCORE_UNIX_P_H
+#define QCORE_UNIX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of Qt code on Unix. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qplatformdefs.h"
+
+#ifndef Q_OS_UNIX
+# error "qcore_unix_p.h included on a non-Unix system"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#if defined(Q_OS_VXWORKS)
+# include <ioLib.h>
+#endif
+
+struct sockaddr;
+
+#if defined(Q_OS_LINUX) && defined(O_CLOEXEC)
+# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1
+QT_BEGIN_NAMESPACE
+namespace QtLibcSupplement {
+ inline int accept4(int, sockaddr *, QT_SOCKLEN_T *, int)
+ { errno = ENOSYS; return -1; }
+ inline int dup3(int, int, int)
+ { errno = ENOSYS; return -1; }
+ inline int pipe2(int [], int )
+ { errno = ENOSYS; return -1; }
+}
+QT_END_NAMESPACE
+using namespace QT_PREPEND_NAMESPACE(QtLibcSupplement);
+
+#else
+# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 0
+#endif
+
+#define EINTR_LOOP(var, cmd) \
+ do { \
+ var = cmd; \
+ } while (var == -1 && errno == EINTR)
+
+QT_BEGIN_NAMESPACE
+
+// Internal operator functions for timevals
+inline timeval &normalizedTimeval(timeval &t)
+{
+ while (t.tv_usec > 1000000l) {
+ ++t.tv_sec;
+ t.tv_usec -= 1000000l;
+ }
+ while (t.tv_usec < 0l) {
+ --t.tv_sec;
+ t.tv_usec += 1000000l;
+ }
+ return t;
+}
+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;
+ t1.tv_usec += t2.tv_usec;
+ return normalizedTimeval(t1);
+}
+inline timeval operator+(const timeval &t1, const timeval &t2)
+{
+ timeval tmp;
+ tmp.tv_sec = t1.tv_sec + t2.tv_sec;
+ tmp.tv_usec = t1.tv_usec + t2.tv_usec;
+ return normalizedTimeval(tmp);
+}
+inline timeval operator-(const timeval &t1, const timeval &t2)
+{
+ timeval tmp;
+ tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1);
+ tmp.tv_usec = t1.tv_usec - (t2.tv_usec + 1000000);
+ return normalizedTimeval(tmp);
+}
+inline timeval operator*(const timeval &t1, int mul)
+{
+ timeval tmp;
+ tmp.tv_sec = t1.tv_sec * mul;
+ tmp.tv_usec = t1.tv_usec * mul;
+ return normalizedTimeval(tmp);
+}
+
+// don't call QT_OPEN or ::open
+// call qt_safe_open
+static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 0777)
+{
+#ifdef O_CLOEXEC
+ flags |= O_CLOEXEC;
+#endif
+ register int fd;
+ EINTR_LOOP(fd, QT_OPEN(pathname, flags, mode));
+
+ // unknown flags are ignored, so we have no way of verifying if
+ // O_CLOEXEC was accepted
+ if (fd != -1)
+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+ return fd;
+}
+#undef QT_OPEN
+#define QT_OPEN qt_safe_open
+
+#ifndef Q_OS_VXWORKS // no POSIX pipes in VxWorks
+// don't call ::pipe
+// call qt_safe_pipe
+static inline int qt_safe_pipe(int pipefd[2], int flags = 0)
+{
+#ifdef O_CLOEXEC
+ Q_ASSERT((flags & ~(O_CLOEXEC | O_NONBLOCK)) == 0);
+#else
+ Q_ASSERT((flags & ~O_NONBLOCK) == 0);
+#endif
+
+ register int ret;
+#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
+ // use pipe2
+ flags |= O_CLOEXEC;
+ ret = ::pipe2(pipefd, flags); // pipe2 is Linux-specific and is documented not to return EINTR
+ if (ret == 0 || errno != ENOSYS)
+ return ret;
+#endif
+
+ ret = ::pipe(pipefd);
+ if (ret == -1)
+ return -1;
+
+ ::fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);
+ ::fcntl(pipefd[1], F_SETFD, FD_CLOEXEC);
+
+ // set non-block too?
+ if (flags & O_NONBLOCK) {
+ ::fcntl(pipefd[0], F_SETFL, ::fcntl(pipefd[0], F_GETFL) | O_NONBLOCK);
+ ::fcntl(pipefd[1], F_SETFL, ::fcntl(pipefd[1], F_GETFL) | O_NONBLOCK);
+ }
+
+ return 0;
+}
+
+#endif // Q_OS_VXWORKS
+
+// don't call dup or fcntl(F_DUPFD)
+static inline int qt_safe_dup(int oldfd, int atleast = 0, int flags = FD_CLOEXEC)
+{
+ Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
+
+ register int ret;
+#ifdef F_DUPFD_CLOEXEC
+ // use this fcntl
+ if (flags & FD_CLOEXEC) {
+ ret = ::fcntl(oldfd, F_DUPFD_CLOEXEC, atleast);
+ if (ret != -1 || errno != EINVAL)
+ return ret;
+ }
+#endif
+
+ // use F_DUPFD
+ ret = ::fcntl(oldfd, F_DUPFD, atleast);
+
+ if (flags && ret != -1)
+ ::fcntl(ret, F_SETFD, flags);
+ return ret;
+}
+
+// don't call dup2
+// call qt_safe_dup2
+static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC)
+{
+ Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
+
+ register int ret;
+#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
+ // use dup3
+ if (flags & FD_CLOEXEC) {
+ EINTR_LOOP(ret, ::dup3(oldfd, newfd, O_CLOEXEC));
+ if (ret == 0 || errno != ENOSYS)
+ return ret;
+ }
+#endif
+ EINTR_LOOP(ret, ::dup2(oldfd, newfd));
+ if (ret == -1)
+ return -1;
+
+ if (flags)
+ ::fcntl(newfd, F_SETFD, flags);
+ return 0;
+}
+
+static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen)
+{
+ qint64 ret = 0;
+ EINTR_LOOP(ret, QT_READ(fd, data, maxlen));
+ return ret;
+}
+#undef QT_READ
+#define QT_READ qt_safe_read
+
+static inline qint64 qt_safe_write(int fd, const void *data, qint64 len)
+{
+ qint64 ret = 0;
+ EINTR_LOOP(ret, QT_WRITE(fd, data, len));
+ return ret;
+}
+#undef QT_WRITE
+#define QT_WRITE qt_safe_write
+
+static inline int qt_safe_close(int fd)
+{
+ register int ret;
+ EINTR_LOOP(ret, QT_CLOSE(fd));
+ return ret;
+}
+#undef QT_CLOSE
+#define QT_CLOSE qt_safe_close
+
+// - Open C does not (yet?) implement these on Symbian OS
+// - VxWorks doesn't have processes
+#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_VXWORKS)
+static inline int qt_safe_execve(const char *filename, char *const argv[],
+ char *const envp[])
+{
+ register int ret;
+ EINTR_LOOP(ret, ::execve(filename, argv, envp));
+ return ret;
+}
+
+static inline int qt_safe_execv(const char *path, char *const argv[])
+{
+ register int ret;
+ EINTR_LOOP(ret, ::execv(path, argv));
+ return ret;
+}
+
+static inline int qt_safe_execvp(const char *file, char *const argv[])
+{
+ register int ret;
+ EINTR_LOOP(ret, ::execvp(file, argv));
+ return ret;
+}
+#endif
+
+#ifndef Q_OS_VXWORKS // no processes on VxWorks
+static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
+{
+ register int ret;
+ EINTR_LOOP(ret, ::waitpid(pid, status, options));
+ return ret;
+}
+
+#endif // Q_OS_VXWORKS
+
+#if !defined(_POSIX_MONOTONIC_CLOCK)
+# define _POSIX_MONOTONIC_CLOCK -1
+#endif
+
+bool qt_gettime_is_monotonic();
+timeval qt_gettime();
+Q_CORE_EXPORT int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
+ const struct timeval *tv);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index cc0708d..423bdf8 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -60,9 +60,16 @@
#include <qthreadstorage.h>
#include <private/qthread_p.h>
#include <qlibraryinfo.h>
+#include <qvarlengtharray.h>
#include <private/qfactoryloader_p.h>
-
-#ifdef Q_OS_UNIX
+#include <private/qfunctions_p.h>
+
+#ifdef Q_OS_SYMBIAN
+# include <exception>
+# include <f32file.h>
+# include "qeventdispatcher_symbian_p.h"
+# include "private/qcore_symbian_p.h"
+#elif defined(Q_OS_UNIX)
# if !defined(QT_NO_GLIB)
# include "qeventdispatcher_glib_p.h"
# endif
@@ -83,8 +90,27 @@
# include <locale.h>
#endif
+#ifdef Q_OS_VXWORKS
+# include <taskLib.h>
+#endif
+
QT_BEGIN_NAMESPACE
+class QMutexUnlocker
+{
+public:
+ inline explicit QMutexUnlocker(QMutex *m)
+ : mtx(m)
+ { }
+ inline ~QMutexUnlocker() { unlock(); }
+ inline void unlock() { if (mtx) mtx->unlock(); mtx = 0; }
+
+private:
+ Q_DISABLE_COPY(QMutexUnlocker)
+
+ QMutex *mtx;
+};
+
#if defined(Q_WS_WIN) || defined(Q_WS_MAC)
extern QString qAppFileName();
#endif
@@ -156,7 +182,14 @@ void qRemovePostRoutine(QtCleanUpFunction p)
void Q_CORE_EXPORT qt_call_post_routines()
{
- QVFuncList *list = postRList();
+ QVFuncList *list = 0;
+ QT_TRY {
+ list = postRList();
+ } QT_CATCH(const std::bad_alloc &) {
+ // ignore - if we can't allocate a post routine list,
+ // there's a high probability that there's no post
+ // routine to be executed :)
+ }
if (!list)
return;
while (!list->isEmpty())
@@ -245,30 +278,34 @@ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv)
QCoreApplicationPrivate::~QCoreApplicationPrivate()
{
+ if (threadData) {
#ifndef QT_NO_THREAD
- void *data = &threadData->tls;
- QThreadStorageData::finish((void **)data);
+ 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;
+ // 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;
}
- threadData->postEventList.clear();
- threadData->postEventList.recursion = 0;
- threadData->quitNow = false;
}
void QCoreApplicationPrivate::createEventDispatcher()
{
Q_Q(QCoreApplication);
-#if defined(Q_OS_UNIX)
+#if defined(Q_OS_SYMBIAN)
+ eventDispatcher = new QEventDispatcherSymbian(q);
+#elif defined(Q_OS_UNIX)
# if !defined(QT_NO_GLIB)
if (qgetenv("QT_NO_GLIB").isEmpty() && QEventDispatcherGlib::versionSupported())
eventDispatcher = new QEventDispatcherGlib(q);
@@ -306,6 +343,11 @@ void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver)
Q_UNUSED(currentThread);
Q_UNUSED(thr);
}
+#elif defined(Q_OS_SYMBIAN) && defined (QT_NO_DEBUG)
+// no implementation in release builds, but keep the symbol present
+void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver)
+{
+}
#endif
void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths()
@@ -313,10 +355,17 @@ void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths()
#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
QStringList *app_libpaths = coreappdata()->app_libpaths;
Q_ASSERT(app_libpaths);
+# if defined(Q_OS_SYMBIAN)
+ QString app_location( QCoreApplication::applicationDirPath() );
+ // File existence check for application's private dir requires additional '\' or
+ // platform security will not allow it.
+ if (app_location != QLibraryInfo::location(QLibraryInfo::PluginsPath) && QFile::exists(app_location + QLatin1Char('\\')) && !app_libpaths->contains(app_location))
+# else
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))
+# endif
app_libpaths->append(app_location);
#endif
}
@@ -333,9 +382,6 @@ QString qAppName()
\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
@@ -347,43 +393,61 @@ QString qAppName()
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
+ \section1 The Event Loop and Event Handling
+
+ 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.
+ main() function as early as possible. exit() will not return
+ until the event loop exits; e.g., when quit() is called.
+
+ 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().
+
+ The class provides a quit() slot and an aboutToQuit() signal.
+
+ \section1 Application and Library Paths
An application has an applicationDirPath() and an
- applicationFilePath(). Translation files can be added or removed
+ applicationFilePath(). Library paths (see QLibrary) can be retrieved
+ with libraryPaths() and manipulated by setLibraryPaths(), addLibraryPath(),
+ and removeLibraryPath().
+
+ \section1 Internationalization and Translations
+
+ 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.
+ \section1 Accessing Command Line Arguments
- 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().
-
- On Unix/Linux Qt is configured to use the system local settings by
- default. This can cause a conflict when using POSIX functions, for
- instance, when converting between data types such as floats and
- strings, since the notation may differ between locales. To get
- around this problem call the POSIX function setlocale(LC_NUMERIC,"C")
- right after initializing QApplication or QCoreApplication to reset
- the locale that is used for number formatting to "C"-locale.
+ The command line arguments which are passed to QCoreApplication's
+ constructor should be accessed using the arguments() function.
+ Note that some arguments supplied by the user may have been
+ processed and removed by QCoreApplication.
+
+ In cases where command line arguments need to be obtained using the
+ argv() function, you must convert them from the local string encoding
+ using QString::fromLocal8Bit().
+
+ \section1 Locale Settings
+
+ On Unix/Linux Qt is configured to use the system locale settings by
+ default. This can cause a conflict when using POSIX functions, for
+ instance, when converting between data types such as floats and
+ strings, since the notation may differ between locales. To get
+ around this problem, call the POSIX function \c{setlocale(LC_NUMERIC,"C")}
+ right after initializing QApplication or QCoreApplication to reset
+ the locale that is used for number formatting to "C"-locale.
\sa QApplication, QAbstractEventDispatcher, QEventLoop,
{Semaphores Example}, {Wait Conditions Example}
@@ -444,6 +508,13 @@ QCoreApplication::QCoreApplication(int &argc, char **argv)
{
init();
QCoreApplicationPrivate::eventDispatcher->startingUp();
+#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+ // Refresh factoryloader, as text codecs are requested during lib path
+ // resolving process and won't be therefore properly loaded.
+ // Unknown if this is symbian specific issue.
+ QFactoryLoader::refreshAll();
+#endif
+
}
extern void set_winapp_name();
@@ -520,7 +591,14 @@ QCoreApplication::~QCoreApplication()
#if !defined(QT_NO_THREAD)
#if !defined(QT_NO_CONCURRENT)
// Synchronize and stop the global thread pool threads.
- QThreadPool::globalInstance()->waitForDone();
+ QThreadPool *globalThreadPool = 0;
+ QT_TRY {
+ globalThreadPool = QThreadPool::globalInstance();
+ } QT_CATCH (...) {
+ // swallow the exception, since destructors shouldn't throw
+ }
+ if (globalThreadPool)
+ globalThreadPool->waitForDone();
#endif
QThread::cleanup();
#endif
@@ -556,6 +634,20 @@ void QCoreApplication::setAttribute(Qt::ApplicationAttribute attribute, bool on)
QCoreApplicationPrivate::attribs |= 1 << attribute;
else
QCoreApplicationPrivate::attribs &= ~(1 << attribute);
+#ifdef Q_OS_MAC
+ // Turn on the no native menubar here, since we used to
+ // do this implicitly. We DO NOT flip it off if someone sets
+ // it to false.
+ // Ideally, we'd have magic that would be something along the lines of
+ // "follow MacPluginApplication" unless explicitly set.
+ // Considering this attribute isn't only at the beginning
+ // it's unlikely it will ever be a problem, but I want
+ // to have the behavior documented here.
+ if (attribute == Qt::AA_MacPluginApplication && on
+ && !testAttribute(Qt::AA_DontUseNativeMenuBar)) {
+ setAttribute(Qt::AA_DontUseNativeMenuBar, true);
+ }
+#endif
}
/*!
@@ -602,17 +694,13 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
d->inEventHandler = true;
#endif
-#if defined(QT_NO_EXCEPTIONS)
- bool returnValue = notify(receiver, event);
-#else
bool returnValue;
- try {
+ QT_TRY {
returnValue = notify(receiver, event);
- } catch(...) {
+ } QT_CATCH (...) {
--threadData->loopLevel;
- throw;
+ QT_RETHROW;
}
-#endif
#ifdef QT_JAMBI_BUILD
// Restore the previous state if the object was not deleted..
@@ -629,8 +717,8 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
/*!
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.
+ handler. Note that this function is called for all events sent to
+ any object in any thread.
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
@@ -1033,21 +1121,23 @@ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
data->postEventList.mutex.lock();
}
+ QMutexUnlocker locker(&data->postEventList.mutex);
+
// 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));
}
+ // delete the event on exceptions to protect against memory leaks till the event is
+ // properly owned in the postEventList
+ QScopedPointer<QEvent> eventDeleter(event);
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
@@ -1062,8 +1152,11 @@ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
QPostEventList::iterator at = qUpperBound(begin, end, priority);
data->postEventList.insert(at, QPostEvent(receiver, event, priority));
}
+ eventDeleter.take();
+ event->posted = true;
+ ++receiver->d_func()->postedEvents;
data->canWait = false;
- data->postEventList.mutex.unlock();
+ locker.unlock();
if (data->eventDispatcher)
data->eventDispatcher->wakeUp();
@@ -1334,13 +1427,10 @@ void QCoreApplication::removePostedEvents(QObject *receiver, int eventType)
// 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)
-{
+ //we will collect all the posted events for the QObject
+ //and we'll delete after the mutex was unlocked
+ QVarLengthArray<QEvent*> events;
int n = data->postEventList.size();
int j = 0;
@@ -1355,7 +1445,7 @@ void QCoreApplicationPrivate::removePostedEvents_unlocked(QObject *receiver,
pe.receiver->d_func()->removePendingChildInsertedEvents(0);
#endif
pe.event->posted = false;
- delete pe.event;
+ events.append(pe.event);
const_cast<QPostEvent &>(pe).event = 0;
} else if (!data->postEventList.recursion) {
if (i != j)
@@ -1374,8 +1464,12 @@ void QCoreApplicationPrivate::removePostedEvents_unlocked(QObject *receiver,
// truncate list
data->postEventList.erase(data->postEventList.begin() + j, data->postEventList.end());
}
-}
+ locker.unlock();
+ for (int i = 0; i < events.count(); ++i) {
+ delete events[i];
+ }
+}
/*!
Removes \a event from the queue of posted events, and emits a
@@ -1661,6 +1755,12 @@ QString QCoreApplication::translate(const char *context, const char *sourceText,
return result;
}
+// Declared in qglobal.h
+QString qtTrId(const char *id, int n)
+{
+ return QCoreApplication::translate(0, id, 0, QCoreApplication::UnicodeUTF8, n);
+}
+
bool QCoreApplicationPrivate::isTranslatorInstalled(QTranslator *translator)
{
return QCoreApplication::self
@@ -1686,6 +1786,9 @@ bool QCoreApplicationPrivate::isTranslatorInstalled(QTranslator *translator)
function also assumes that the current directory has not been
changed by the application.
+ In Symbian this function will return the application private directory,
+ not the path to executable itself, as those are always in \c {/sys/bin}.
+
\sa applicationFilePath()
*/
QString QCoreApplication::applicationDirPath()
@@ -1697,7 +1800,32 @@ QString QCoreApplication::applicationDirPath()
QCoreApplicationPrivate *d = self->d_func();
if (d->cachedApplicationDirPath.isNull())
+#if defined(Q_OS_SYMBIAN)
+ {
+ QString appPath;
+ RProcess proc;
+ TInt err = proc.Open(proc.Id());
+ if (err == KErrNone) {
+#if defined(Q_CC_NOKIAX86)
+ // In emulator, always resolve the private dir on C-drive
+ appPath.append(QChar('C'));
+#else
+ appPath.append(QChar((proc.FileName())[0]));
+#endif
+ appPath.append(QLatin1String(":\\private\\"));
+ QString sid;
+ sid.setNum(proc.SecureId().iId, 16);
+ appPath.append(sid);
+ appPath.append(QLatin1Char('\\'));
+ proc.Close();
+ }
+
+ QFileInfo fi(appPath);
+ d->cachedApplicationDirPath = fi.exists() ? fi.canonicalFilePath() : QString();
+ }
+#else
d->cachedApplicationDirPath = QFileInfo(applicationFilePath()).path();
+#endif
return d->cachedApplicationDirPath;
}
@@ -1727,21 +1855,8 @@ QString QCoreApplication::applicationFilePath()
if (!d->cachedApplicationFilePath.isNull())
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();
+#if defined(Q_WS_WIN)
+ d->cachedApplicationFilePath = QFileInfo(qAppFileName()).filePath();
return d->cachedApplicationFilePath;
#elif defined(Q_WS_MAC)
QString qAppFileName_str = qAppFileName();
@@ -1751,7 +1866,20 @@ QString QCoreApplication::applicationFilePath()
return d->cachedApplicationFilePath;
}
#endif
-#if defined( Q_OS_UNIX )
+#if defined(Q_OS_SYMBIAN)
+ QString appPath;
+ RProcess proc;
+ TInt err = proc.Open(proc.Id());
+ if (err == KErrNone) {
+ TFileName procName = proc.FileName();
+ appPath.append(QString(reinterpret_cast<const QChar*>(procName.Ptr()), procName.Length()));
+ proc.Close();
+ }
+
+ d->cachedApplicationFilePath = appPath;
+ return d->cachedApplicationFilePath;
+
+#elif 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
@@ -1784,7 +1912,7 @@ QString QCoreApplication::applicationFilePath()
*/
QByteArray pEnv = qgetenv("PATH");
QDir currentDir = QDir::current();
- QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1String(":"));
+ QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1Char(':'));
for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
if ((*p).isEmpty())
continue;
@@ -1814,8 +1942,9 @@ qint64 QCoreApplication::applicationPid()
{
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
return GetCurrentProcessId();
+#elif defined(Q_OS_VXWORKS)
+ return (pid_t) taskIdCurrent;
#else
- // UNIX
return getpid();
#endif
}
@@ -1864,9 +1993,9 @@ char **QCoreApplication::argv()
\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.
+ pass, for example, 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
@@ -1888,13 +2017,13 @@ QStringList QCoreApplication::arguments()
return list;
}
#ifdef Q_OS_WIN
- QString cmdline = QT_WA_INLINE(QString::fromUtf16((unsigned short *)GetCommandLineW()), QString::fromLocal8Bit(GetCommandLineA()));
+ QString cmdline = QString::fromWCharArray(GetCommandLine());
#if defined(Q_OS_WINCE)
wchar_t tempFilename[MAX_PATH+1];
- if (GetModuleFileNameW(0, tempFilename, MAX_PATH)) {
+ if (GetModuleFileName(0, tempFilename, MAX_PATH)) {
tempFilename[MAX_PATH] = 0;
- cmdline.prepend(QString(QLatin1String("\"")) + QString::fromUtf16((unsigned short *)tempFilename) + QString(QLatin1String("\" ")));
+ cmdline.prepend(QLatin1Char('\"') + QString::fromWCharArray(tempFilename) + QLatin1String("\" "));
}
#endif // Q_OS_WINCE
@@ -1908,8 +2037,7 @@ QStringList QCoreApplication::arguments()
l1arg == "-qdebug" ||
l1arg == "-reverse" ||
l1arg == "-stylesheet" ||
- l1arg == "-widgetcount" ||
- l1arg == "-direct3d")
+ l1arg == "-widgetcount")
;
else if (l1arg.startsWith("-style="))
;
@@ -2054,12 +2182,33 @@ QStringList QCoreApplication::libraryPaths()
if (!coreappdata()->app_libpaths) {
QStringList *app_libpaths = coreappdata()->app_libpaths = new QStringList;
QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
+#if defined(Q_OS_SYMBIAN)
+ // Add existing path on all drives for relative PluginsPath in Symbian
+ if (installPathPlugins.at(1) != QChar(':')) {
+ QString tempPath = installPathPlugins;
+ if (tempPath.at(tempPath.length() - 1) != QChar('\\')) {
+ tempPath += QChar('\\');
+ }
+ RFs& fs = qt_s60GetRFs();
+ TPtrC tempPathPtr(reinterpret_cast<const TText*> (tempPath.constData()));
+ TFindFile finder(fs);
+ TInt err = finder.FindByDir(tempPathPtr, tempPathPtr);
+ while (err == KErrNone) {
+ QString foundDir = QString::fromUtf16(finder.File().Ptr(), finder.File().Length());
+ foundDir = QDir(foundDir).canonicalPath();
+ if (!app_libpaths->contains(foundDir))
+ app_libpaths->append(foundDir);
+ err = finder.Find();
+ }
+ }
+#else
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);
}
+#endif
// If QCoreApplication is not yet instantiated,
// make sure we add the application path when we construct the QCoreApplication
@@ -2067,7 +2216,7 @@ QStringList QCoreApplication::libraryPaths()
const QByteArray libPathEnv = qgetenv("QT_PLUGIN_PATH");
if (!libPathEnv.isEmpty()) {
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
QLatin1Char pathSep(';');
#else
QLatin1Char pathSep(':');
@@ -2177,21 +2326,37 @@ void QCoreApplication::removeLibraryPath(const QString &path)
/*!
\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
+ Replaces the event filter function for the QCoreApplication with
+ \a filter and returns the pointer to the replaced event filter
+ function. Only the current event filter function is called. If you
+ want to use both filter functions, save the replaced EventFilter
+ in a place where yours can call it.
+
+ The event filter function set here is called for all messages
+ received by all threads meant for all Qt objects. It is \e not
+ called for messages that are not meant for Qt objects.
+
+ The event filter function should return true if the message should
+ be filtered, (i.e. stopped). It should return false to allow
+ processing the message to continue.
+
+ By default, no event filter function is set (i.e., this function
+ returns a null EventFilter the first time it is called).
+
+ \note The filter function set here receives native messages,
+ i.e. MSG or XEvent structs, that are going to Qt objects. It is
+ called by QCoreApplication::filterEvent(). If the filter function
+ returns false to indicate the message should be processed further,
+ the native message can then be translated into a QEvent and
+ handled by the standard Qt \l{QEvent} {event} filering, e.g.
+ QObject::installEventFilter().
+
+ \note The filter function set here is different form the filter
+ function set via QAbstractEventDispatcher::setEventFilter(), which
+ gets all messages received by its thread, even messages meant for
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()
+ \sa QObject::installEventFilter(), QAbstractEventDispatcher::setEventFilter()
*/
QCoreApplication::EventFilter
QCoreApplication::setEventFilter(QCoreApplication::EventFilter filter)
@@ -2342,7 +2507,7 @@ int QCoreApplication::loopLevel()
}
#endif
-/*!
+/*
\fn void QCoreApplication::watchUnixSignal(int signal, bool watch)
\internal
*/
diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h
index 5b9a62c..e98d719 100644
--- a/src/corelib/kernel/qcoreapplication.h
+++ b/src/corelib/kernel/qcoreapplication.h
@@ -165,7 +165,7 @@ public:
virtual bool winEventFilter(MSG *message, long *result);
#endif
-#ifdef Q_OS_UNIX
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
static void watchUnixSignal(int signal, bool watch);
#endif
@@ -195,6 +195,8 @@ private:
void init();
static QCoreApplication *self;
+
+ Q_DISABLE_COPY(QCoreApplication)
friend class QEventDispatcherUNIXPrivate;
friend class QApplication;
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index 7f937eb..c4ee43f 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -57,6 +57,10 @@
#include "QtCore/qtranslator.h"
#include "private/qobject_p.h"
+#ifdef Q_OS_SYMBIAN
+#include <f32file.h>
+#endif
+
QT_BEGIN_NAMESPACE
typedef QList<QTranslator*> QTranslatorList;
@@ -90,9 +94,8 @@ public:
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)
+#if !defined (QT_NO_DEBUG) || defined (QT_MAC_FRAMEWORK_BUILD) || defined (Q_OS_SYMBIAN)
void checkReceiverThread(QObject *receiver);
#endif
int &argc;
diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp
index afd4902..a6cb7ab 100644
--- a/src/corelib/kernel/qcoreapplication_win.cpp
+++ b/src/corelib/kernel/qcoreapplication_win.cpp
@@ -45,18 +45,18 @@
#include "qt_windows.h"
#include "qvector.h"
#include "qmutex.h"
+#include "qfileinfo.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;
+char appFileName[MAX_PATH]; // application file name
+char theAppName[MAX_PATH]; // application name
+HINSTANCE appInst = 0; // handle to app instance
+HINSTANCE appPrevInst = 0; // handle to prev app instance
+int appCmdShow = 0;
bool usingWinMain = false; // whether the qWinMain() is used or not
Q_CORE_EXPORT HINSTANCE qWinAppInst() // get Windows app handle
@@ -69,39 +69,74 @@ Q_CORE_EXPORT HINSTANCE qWinAppPrevInst() // get Windows prev app
return appPrevInst;
}
+Q_CORE_EXPORT int qWinAppCmdShow() // get main window show command
+{
+ return appCmdShow;
+}
+
+Q_CORE_EXPORT QString qAppFileName() // get application file name
+{
+ // We do MAX_PATH + 2 here, and request with MAX_PATH + 1, so we can handle all paths
+ // up to, and including MAX_PATH size perfectly fine with string termination, as well
+ // as easily detect if the file path is indeed larger than MAX_PATH, in which case we
+ // need to use the heap instead. This is a work-around, since contrary to what the
+ // MSDN documentation states, GetModuleFileName sometimes doesn't set the
+ // ERROR_INSUFFICIENT_BUFFER error number, and we thus cannot rely on this value if
+ // GetModuleFileName(0, buffer, MAX_PATH) == MAX_PATH.
+ // GetModuleFileName(0, buffer, MAX_PATH + 1) == MAX_PATH just means we hit the normal
+ // file path limit, and we handle it normally, if the result is MAX_PATH + 1, we use
+ // heap (even if the result _might_ be exactly MAX_PATH + 1, but that's ok).
+ wchar_t buffer[MAX_PATH + 2];
+ DWORD v = GetModuleFileName(0, buffer, MAX_PATH + 1);
+ buffer[MAX_PATH + 1] = 0;
+
+ if (v == 0)
+ return QString();
+ else if (v <= MAX_PATH)
+ return QString::fromWCharArray(buffer);
+
+ // MAX_PATH sized buffer wasn't large enough to contain the full path, use heap
+ wchar_t *b = 0;
+ int i = 1;
+ size_t size;
+ do {
+ ++i;
+ size = MAX_PATH * i;
+ b = reinterpret_cast<wchar_t *>(realloc(b, (size + 1) * sizeof(wchar_t)));
+ if (b)
+ v = GetModuleFileName(NULL, b, size);
+ } while (b && v == size);
+
+ if (b)
+ *(b + size) = 0;
+ QString res = QString::fromWCharArray(b);
+ free(b);
+
+ return res;
+}
+
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 moduleName = qAppFileName();
+
+ QByteArray filePath = moduleName.toLocal8Bit();
+ QByteArray fileName = QFileInfo(moduleName).baseName().toLocal8Bit();
+
+ memcpy(appFileName, filePath.constData(), filePath.length());
+ memcpy(theAppName, fileName.constData(), fileName.length());
+
+ if (appInst == 0)
+ appInst = GetModuleHandle(0);
+ }
}
QString QCoreApplicationPrivate::appName() const
{
- if (!theAppName[0])
- set_winapp_name();
- return QString::fromLatin1(theAppName);
+ return QFileInfo(qAppFileName()).baseName();
}
class QWinMsgHandlerCriticalSection
@@ -132,15 +167,11 @@ Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char* 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());
- })
+
+ QString s(QString::fromLocal8Bit(str));
+ s += QLatin1Char('\n');
+ OutputDebugString((wchar_t*)s.utf16());
+
staticCriticalSection.unlock();
}
@@ -173,14 +204,14 @@ void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam,
// Create command line
- set_winapp_name();
-
argv = qWinCmdLine<char>(cmdParam, int(strlen(cmdParam)), argc);
// Get Windows parameters
appInst = instance;
appPrevInst = prevInstance;
appCmdShow = cmdShow;
+
+ set_winapp_name();
}
/*!
@@ -249,7 +280,7 @@ QT_END_INCLUDE_NAMESPACE
// 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 {
+struct KnownWM {
uint WM;
const char* str;
} knownWM[] =
@@ -396,6 +427,7 @@ struct {
{ 0x020B, "WM_XBUTTONDOWN" },
{ 0x020C, "WM_XBUTTONUP" },
{ 0x020D, "WM_XBUTTONDBLCLK" },
+ { 0x020E, "WM_MOUSEHWHEEL" },
{ 0x0210, "WM_PARENTNOTIFY" },
{ 0x0211, "WM_ENTERMENULOOP" },
{ 0x0212, "WM_EXITMENULOOP" },
@@ -550,7 +582,7 @@ struct {
{ 0,0 }}; // End of known messages
// Looks up the WM_ message in the table above
-const char* findWMstr(uint msg)
+static const char* findWMstr(uint msg)
{
uint i = 0;
const char* result = 0;
@@ -618,7 +650,7 @@ QString valueCheck(uint actual, ...)
#ifdef Q_CC_BOR
-Q_CORE_EXPORT QString decodeMSG(const MSG& msg)
+QString decodeMSG(const MSG& msg)
{
return QString::fromLatin1("THis is not supported on Borland");
}
@@ -827,7 +859,7 @@ QString decodeMSG(const MSG& msg)
FLGSTR(ISC_SHOWUICANDIDATEWINDOW << 2),
FLGSTR(ISC_SHOWUICANDIDATEWINDOW << 3),
FLAG_STRING());
- parameters.sprintf("Input context(%s) Show flags(%s)", (fSet?"Active":"Inactive"), showFlgs.toLatin1().data());
+ parameters.sprintf("Input context(%s) Show flags(%s)", (fSet? "Active" : "Inactive"), showFlgs.toLatin1().data());
}
break;
#endif
@@ -885,6 +917,9 @@ QString decodeMSG(const MSG& msg)
#ifdef WM_MOUSEWHEEL
case WM_MOUSEWHEEL:
#endif
+#ifdef WM_MOUSEHWHEEL
+ case WM_MOUSEHWHEEL:
+#endif
#ifdef WM_LBUTTONDBLCLK
case WM_LBUTTONDBLCLK:
#endif
diff --git a/src/corelib/kernel/qcorecmdlineargs_p.h b/src/corelib/kernel/qcorecmdlineargs_p.h
index 566ca5f..34c00b0 100644
--- a/src/corelib/kernel/qcorecmdlineargs_p.h
+++ b/src/corelib/kernel/qcorecmdlineargs_p.h
@@ -135,9 +135,9 @@ static inline QStringList qWinCmdArgs(QString cmdLine) // not const-ref: this mi
QStringList args;
int argc = 0;
- QVector<ushort*> argv = qWinCmdLine<ushort>((ushort*)cmdLine.utf16(), cmdLine.length(), argc);
+ QVector<wchar_t*> argv = qWinCmdLine<wchar_t>((wchar_t *)cmdLine.utf16(), cmdLine.length(), argc);
for (int a = 0; a < argc; ++a) {
- args << QString::fromUtf16(argv[a]);
+ args << QString::fromWCharArray(argv[a]);
}
return args;
@@ -147,10 +147,7 @@ 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())
- );
+ QString cmdLine = QString::fromWCharArray(GetCommandLine());
return qWinCmdArgs(cmdLine);
}
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index e18931d..6ef8b6e 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -54,7 +54,6 @@ QT_BEGIN_NAMESPACE
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
@@ -108,6 +107,7 @@ QT_BEGIN_NAMESPACE
\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 CloseSoftwareInputPanel A widget wants to close the software input panel (SIP).
\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).
@@ -186,6 +186,7 @@ QT_BEGIN_NAMESPACE
\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 RequestSoftwareInputPanel A widget wants to open a software input panel (SIP).
\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).
@@ -219,9 +220,13 @@ QT_BEGIN_NAMESPACE
\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 Wrapped The event is a wrapper for, i.e., contains, another event (QWrappedEvent).
\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.
+ \value TouchBegin Beginning of a sequence of touch-screen and/or track-pad events (QTouchEvent)
+ \value TouchUpdate Touch-screen event (QTouchEvent)
+ \value TouchEnd End of touch-event sequence (QTouchEvent)
User events should have values between \c User and \c{MaxUser}:
@@ -264,6 +269,9 @@ QT_BEGIN_NAMESPACE
\omitvalue NetworkReplyUpdated
\omitvalue FutureCallOut
\omitvalue CocoaRequestModal
+ \omitvalue Signal
+ \omitvalue SymbianDeferredFocusChanged
+ \omitvalue NativeGesture
*/
/*!
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index 56b8abb..47acd04 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -44,6 +44,7 @@
#include <QtCore/qnamespace.h>
#include <QtCore/qbytearray.h>
+#include <QtCore/qobjectdefs.h>
QT_BEGIN_HEADER
@@ -54,7 +55,9 @@ 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 {
/*
@@ -266,6 +269,20 @@ public:
CocoaRequestModal = 190, // Internal for requesting an application modal Cocoa Window
MacGLClearDrawable = 191, // Internal Cocoa, the window has changed, so we must clear
+ Signal = 192,
+ Wrapped = 193,
+
+ TouchBegin = 194,
+ TouchUpdate = 195,
+ TouchEnd = 196,
+
+ NativeGesture = 197, // Internal for platform gesture support
+
+ RequestSoftwareInputPanel = 199,
+ CloseSoftwareInputPanel = 200,
+
+ SymbianDeferredFocusChanged = 201, // Internal for generating asynchronous focus events on Symbian
+
// 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event
@@ -304,6 +321,10 @@ private:
friend class Q3AccelManager;
friend class QShortcutMap;
friend class QETWidget;
+ friend class QGraphicsView;
+ friend class QGraphicsViewPrivate;
+ friend class QGraphicsScenePrivate;
+ friend class QGraphicsWidget;
};
class Q_CORE_EXPORT QTimerEvent : public QEvent
diff --git a/src/corelib/kernel/qcoreglobaldata.cpp b/src/corelib/kernel/qcoreglobaldata.cpp
index 473f410..96ffce8 100644
--- a/src/corelib/kernel/qcoreglobaldata.cpp
+++ b/src/corelib/kernel/qcoreglobaldata.cpp
@@ -41,8 +41,6 @@
#include "qcoreglobaldata_p.h"
-#include <QtDebug>
-
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QCoreGlobalData, globalInstance)
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp
new file mode 100644
index 0000000..daeb0e1
--- /dev/null
+++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp
@@ -0,0 +1,1000 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeventdispatcher_symbian_p.h"
+#include <private/qthread_p.h>
+#include <qcoreapplication.h>
+#include <private/qcoreapplication_p.h>
+#include <qdatetime.h>
+
+#include <unistd.h>
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+#define WAKE_UP_PRIORITY CActive::EPriorityStandard
+#define TIMER_PRIORITY CActive::EPriorityHigh
+#define NULLTIMER_PRIORITY CActive::EPriorityLow
+#define COMPLETE_DEFERRED_ACTIVE_OBJECTS_PRIORITY CActive::EPriorityIdle
+
+static inline int qt_pipe_write(int socket, const char *data, qint64 len)
+{
+ return ::write(socket, data, len);
+}
+#if defined(write)
+# undef write
+#endif
+
+static inline int qt_pipe_close(int socket)
+{
+ return ::close(socket);
+}
+#if defined(close)
+# undef close
+#endif
+
+static inline int qt_pipe_fcntl(int socket, int command)
+{
+ return ::fcntl(socket, command);
+}
+static inline int qt_pipe2_fcntl(int socket, int command, int option)
+{
+ return ::fcntl(socket, command, option);
+}
+#if defined(fcntl)
+# undef fcntl
+#endif
+
+static inline int qt_socket_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+{
+ return ::select(nfds, readfds, writefds, exceptfds, timeout);
+}
+
+// This simply interrupts the select and locks the mutex until destroyed.
+class QSelectMutexGrabber
+{
+public:
+ QSelectMutexGrabber(int fd, QMutex *mutex)
+ : m_mutex(mutex)
+ {
+ if (m_mutex->tryLock())
+ return;
+
+ char dummy = 0;
+ qt_pipe_write(fd, &dummy, 1);
+
+ m_mutex->lock();
+ }
+
+ ~QSelectMutexGrabber()
+ {
+ m_mutex->unlock();
+ }
+
+private:
+ QMutex *m_mutex;
+};
+
+/*
+ * This class is designed to aid in implementing event handling in a more round robin fashion. We
+ * cannot change active objects that we do not own, but the active objects that Qt owns will use
+ * this as a base class with convenience functions.
+ *
+ * Here is how it works: On every RunL, the deriving class should call okToRun(). This will allow
+ * exactly one run of the active object, and mark it as such. If it is called again, it will return
+ * false, and add the object to a queue so it can be run later.
+ *
+ * The QCompleteDeferredAOs class is a special object that runs after all others, which will
+ * reactivate the objects that were previously not run.
+ */
+inline QActiveObject::QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher)
+ : CActive(priority),
+ m_dispatcher(dispatcher),
+ m_hasAlreadyRun(false),
+ m_hasRunAgain(false),
+ m_iterationCount(1)
+{
+}
+
+QActiveObject::~QActiveObject()
+{
+ if (m_hasRunAgain)
+ m_dispatcher->removeDeferredActiveObject(this);
+}
+
+bool QActiveObject::okToRun()
+{
+ Q_ASSERT(!m_hasRunAgain);
+
+ if (!m_hasAlreadyRun || m_dispatcher->iterationCount() != m_iterationCount) {
+ // First occurrence of this event in this iteration.
+ m_hasAlreadyRun = true;
+ m_iterationCount = m_dispatcher->iterationCount();
+ return true;
+ } else {
+ // The event has already occurred.
+ m_dispatcher->addDeferredActiveObject(this);
+ m_hasRunAgain = true;
+ return false;
+ }
+}
+
+void QActiveObject::reactivateAndComplete()
+{
+ iStatus = KRequestPending;
+ SetActive();
+ TRequestStatus *status = &iStatus;
+ QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+
+ m_hasRunAgain = false;
+ m_hasAlreadyRun = false;
+}
+
+QWakeUpActiveObject::QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher)
+ : CActive(WAKE_UP_PRIORITY),
+ m_dispatcher(dispatcher)
+{
+ CActiveScheduler::Add(this);
+ iStatus = KRequestPending;
+ SetActive();
+}
+
+QWakeUpActiveObject::~QWakeUpActiveObject()
+{
+ Cancel();
+}
+
+void QWakeUpActiveObject::DoCancel()
+{
+ if (iStatus.Int() == KRequestPending) {
+ TRequestStatus *status = &iStatus;
+ QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+ }
+}
+
+void QWakeUpActiveObject::RunL()
+{
+ iStatus = KRequestPending;
+ SetActive();
+ QT_TRYCATCH_LEAVING(m_dispatcher->wakeUpWasCalled());
+}
+
+QTimerActiveObject::QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo)
+ : QActiveObject((timerInfo->interval) ? TIMER_PRIORITY : NULLTIMER_PRIORITY , dispatcher),
+ m_timerInfo(timerInfo)
+{
+}
+
+QTimerActiveObject::~QTimerActiveObject()
+{
+ Cancel();
+}
+
+void QTimerActiveObject::DoCancel()
+{
+ if (m_timerInfo->interval > 0) {
+ m_rTimer.Cancel();
+ m_rTimer.Close();
+ } else {
+ if (iStatus.Int() == KRequestPending) {
+ TRequestStatus *status = &iStatus;
+ QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+ }
+ }
+}
+
+void QTimerActiveObject::RunL()
+{
+ int error;
+ QT_TRYCATCH_ERROR(error, Run());
+ // All Symbian error codes are negative.
+ if (error < 0) {
+ CActiveScheduler::Current()->Error(error); // stop and report here, as this timer will be deleted on scope exit
+ }
+}
+
+void QTimerActiveObject::Run()
+{
+ if (!okToRun())
+ return;
+
+ if (m_timerInfo->interval > 0) {
+ // Start a new timer immediately so that we don't lose time.
+ SetActive();
+ m_rTimer.After(iStatus, m_timerInfo->interval*1000);
+
+ m_timerInfo->dispatcher->timerFired(m_timerInfo->timerId);
+ } else {
+ // However, we only complete zero timers after the event has finished,
+ // in order to prevent busy looping when doing nested loops.
+
+ // Keep the refpointer around in order to avoid deletion until the end of this function.
+ SymbianTimerInfoPtr timerInfoPtr(m_timerInfo);
+
+ m_timerInfo->dispatcher->timerFired(m_timerInfo->timerId);
+
+ iStatus = KRequestPending;
+ SetActive();
+ TRequestStatus *status = &iStatus;
+ QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+ }
+}
+
+void QTimerActiveObject::Start()
+{
+ CActiveScheduler::Add(this);
+ if (m_timerInfo->interval > 0) {
+ m_rTimer.CreateLocal();
+ iStatus = KRequestPending;
+ SetActive();
+ m_rTimer.After(iStatus, m_timerInfo->interval*1000);
+ } else {
+ iStatus = KRequestPending;
+ SetActive();
+ TRequestStatus *status = &iStatus;
+ QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+ }
+}
+
+SymbianTimerInfo::SymbianTimerInfo()
+ : timerAO(0)
+{
+}
+
+SymbianTimerInfo::~SymbianTimerInfo()
+{
+ delete timerAO;
+}
+
+QCompleteDeferredAOs::QCompleteDeferredAOs(QEventDispatcherSymbian *dispatcher)
+ : CActive(COMPLETE_DEFERRED_ACTIVE_OBJECTS_PRIORITY),
+ m_dispatcher(dispatcher)
+{
+ CActiveScheduler::Add(this);
+ iStatus = KRequestPending;
+ SetActive();
+}
+
+QCompleteDeferredAOs::~QCompleteDeferredAOs()
+{
+ Cancel();
+}
+
+void QCompleteDeferredAOs::complete()
+{
+ if (iStatus.Int() == KRequestPending) {
+ TRequestStatus *status = &iStatus;
+ QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+ }
+}
+
+void QCompleteDeferredAOs::DoCancel()
+{
+ if (iStatus.Int() == KRequestPending) {
+ TRequestStatus *status = &iStatus;
+ QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+ }
+}
+
+void QCompleteDeferredAOs::RunL()
+{
+ iStatus = KRequestPending;
+ SetActive();
+
+ QT_TRYCATCH_LEAVING(m_dispatcher->reactivateDeferredActiveObjects());
+}
+
+QSelectThread::QSelectThread()
+ : m_quit(false)
+{
+ if (::pipe(m_pipeEnds) != 0) {
+ qWarning("Select thread was unable to open a pipe, errno: %i", errno);
+ } else {
+ int flags0 = qt_pipe_fcntl(m_pipeEnds[0], F_GETFL);
+ int flags1 = qt_pipe_fcntl(m_pipeEnds[1], F_GETFL);
+ // We should check the error code here, but Open C has a bug that returns
+ // failure even though the operation was successful.
+ qt_pipe2_fcntl(m_pipeEnds[0], F_SETFL, flags0 | O_NONBLOCK);
+ qt_pipe2_fcntl(m_pipeEnds[1], F_SETFL, flags1 | O_NONBLOCK);
+ }
+}
+
+QSelectThread::~QSelectThread()
+{
+ qt_pipe_close(m_pipeEnds[1]);
+ qt_pipe_close(m_pipeEnds[0]);
+}
+
+void QSelectThread::run()
+{
+ Q_D(QThread);
+
+ m_mutex.lock();
+
+ while (!m_quit) {
+ fd_set readfds;
+ fd_set writefds;
+ fd_set exceptionfds;
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&exceptionfds);
+
+ int maxfd = 0;
+ maxfd = qMax(maxfd, updateSocketSet(QSocketNotifier::Read, &readfds));
+ maxfd = qMax(maxfd, updateSocketSet(QSocketNotifier::Write, &writefds));
+ maxfd = qMax(maxfd, updateSocketSet(QSocketNotifier::Exception, &exceptionfds));
+ maxfd = qMax(maxfd, m_pipeEnds[0]);
+ maxfd++;
+
+ FD_SET(m_pipeEnds[0], &readfds);
+
+ int ret;
+ int savedSelectErrno;
+ ret = qt_socket_select(maxfd, &readfds, &writefds, &exceptionfds, 0);
+ savedSelectErrno = errno;
+
+ char buffer;
+
+ while (::read(m_pipeEnds[0], &buffer, 1) > 0) {}
+
+ if(ret == 0) {
+ // do nothing
+ } else if (ret < 0) {
+ switch (savedSelectErrno) {
+ case EBADF:
+ case EINVAL:
+ case ENOMEM:
+ case EFAULT:
+ qWarning("::select() returned an error: %i", savedSelectErrno);
+ break;
+ case ECONNREFUSED:
+ case EPIPE:
+ qWarning("::select() returned an error: %i (go through sockets)", savedSelectErrno);
+ // prepare to go through all sockets
+ // mark in fd sets both:
+ // good ones
+ // ones that return -1 in select
+ // after loop update notifiers for all of them
+
+ // as we dont have "exception" notifier type
+ // we should force monitoring fd_set of this
+ // type as well
+
+ // clean @ start
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&exceptionfds);
+ for (QHash<QSocketNotifier *, TRequestStatus *>::const_iterator i = m_AOStatuses.begin();
+ i != m_AOStatuses.end(); ++i) {
+
+ fd_set onefds;
+ FD_ZERO(&onefds);
+ FD_SET(i.key()->socket(), &onefds);
+
+ fd_set excfds;
+ FD_ZERO(&excfds);
+ FD_SET(i.key()->socket(), &excfds);
+
+ maxfd = i.key()->socket() + 1;
+
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ ret = 0;
+
+ if(i.key()->type() == QSocketNotifier::Read) {
+ ret = ::select(maxfd, &onefds, 0, &excfds, &timeout);
+ if(ret != 0) FD_SET(i.key()->socket(), &readfds);
+ } else if(i.key()->type() == QSocketNotifier::Write) {
+ ret = ::select(maxfd, 0, &onefds, &excfds, &timeout);
+ if(ret != 0) FD_SET(i.key()->socket(), &writefds);
+ }
+
+ } // end for
+
+ // traversed all, so update
+ updateActivatedNotifiers(QSocketNotifier::Read, &readfds);
+ updateActivatedNotifiers(QSocketNotifier::Write, &writefds);
+ updateActivatedNotifiers(QSocketNotifier::Exception, &exceptionfds);
+
+ break;
+ case EINTR: // Should never occur on Symbian, but this is future proof!
+ default:
+ qWarning("::select() returned an unknown error: %i", savedSelectErrno);
+
+ break;
+ }
+ } else {
+ updateActivatedNotifiers(QSocketNotifier::Read, &readfds);
+ updateActivatedNotifiers(QSocketNotifier::Write, &writefds);
+ updateActivatedNotifiers(QSocketNotifier::Exception, &exceptionfds);
+ }
+
+ m_waitCond.wait(&m_mutex);
+ }
+
+ m_mutex.unlock();
+}
+
+void QSelectThread::requestSocketEvents ( QSocketNotifier *notifier, TRequestStatus *status )
+{
+ Q_D(QThread);
+
+ if (!isRunning()) {
+ start();
+ }
+
+ QSelectMutexGrabber lock(m_pipeEnds[1], &m_mutex);
+
+ Q_ASSERT(!m_AOStatuses.contains(notifier));
+
+ m_AOStatuses.insert(notifier, status);
+
+ m_waitCond.wakeAll();
+}
+
+void QSelectThread::cancelSocketEvents ( QSocketNotifier *notifier )
+{
+ QSelectMutexGrabber lock(m_pipeEnds[1], &m_mutex);
+
+ m_AOStatuses.remove(notifier);
+
+ m_waitCond.wakeAll();
+}
+
+void QSelectThread::restart()
+{
+ QSelectMutexGrabber lock(m_pipeEnds[1], &m_mutex);
+
+ m_waitCond.wakeAll();
+}
+
+int QSelectThread::updateSocketSet(QSocketNotifier::Type type, fd_set *fds)
+{
+ int maxfd = 0;
+ if(m_AOStatuses.isEmpty()) {
+ /*
+ * Wonder if should return -1
+ * to signal that no descriptors
+ * added to fds
+ */
+ return maxfd;
+ }
+ for ( QHash<QSocketNotifier *, TRequestStatus *>::const_iterator i = m_AOStatuses.begin();
+ i != m_AOStatuses.end(); ++i) {
+ if (i.key()->type() == type) {
+ FD_SET(i.key()->socket(), fds);
+ maxfd = qMax(maxfd, i.key()->socket());
+ } else if(type == QSocketNotifier::Exception) {
+ /*
+ * We are registering existing sockets
+ * always to exception set
+ *
+ * Doing double FD_SET shouldn't
+ * matter
+ */
+ FD_SET(i.key()->socket(), fds);
+ maxfd = qMax(maxfd, i.key()->socket());
+ }
+ }
+
+ return maxfd;
+}
+
+void QSelectThread::updateActivatedNotifiers(QSocketNotifier::Type type, fd_set *fds)
+{
+ Q_D(QThread);
+ if(m_AOStatuses.isEmpty()) {
+ return;
+ }
+ QList<QSocketNotifier *> toRemove;
+ for (QHash<QSocketNotifier *, TRequestStatus *>::const_iterator i = m_AOStatuses.begin();
+ i != m_AOStatuses.end(); ++i) {
+ if (i.key()->type() == type && FD_ISSET(i.key()->socket(), fds)) {
+ toRemove.append(i.key());
+ TRequestStatus *status = i.value();
+ // Thread data is still owned by the main thread.
+ QEventDispatcherSymbian::RequestComplete(d->threadData->symbian_thread_handle, status, KErrNone);
+ } else if(type == QSocketNotifier::Exception && FD_ISSET(i.key()->socket(), fds)) {
+ /*
+ * check if socket is in exception set
+ * then signal RequestComplete for it
+ */
+ qWarning("exception on %d", i.key()->socket());
+ toRemove.append(i.key());
+ TRequestStatus *status = i.value();
+ QEventDispatcherSymbian::RequestComplete(d->threadData->symbian_thread_handle, status, KErrNone);
+ }
+ }
+
+ for (int c = 0; c < toRemove.size(); ++c) {
+ m_AOStatuses.remove(toRemove[c]);
+ }
+}
+
+void QSelectThread::stop()
+{
+ m_quit = true;
+ restart();
+ wait();
+}
+
+QSocketActiveObject::QSocketActiveObject(QEventDispatcherSymbian *dispatcher, QSocketNotifier *notifier)
+ : QActiveObject(CActive::EPriorityStandard, dispatcher),
+ m_notifier(notifier),
+ m_inSocketEvent(false),
+ m_deleteLater(false)
+{
+ CActiveScheduler::Add(this);
+ iStatus = KRequestPending;
+ SetActive();
+}
+
+QSocketActiveObject::~QSocketActiveObject()
+{
+ Cancel();
+}
+
+void QSocketActiveObject::DoCancel()
+{
+ if (iStatus.Int() == KRequestPending) {
+ TRequestStatus *status = &iStatus;
+ QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+ }
+}
+
+void QSocketActiveObject::RunL()
+{
+ if (!okToRun())
+ return;
+
+ QT_TRYCATCH_LEAVING(m_dispatcher->socketFired(this));
+}
+
+void QSocketActiveObject::deleteLater()
+{
+ if (m_inSocketEvent) {
+ m_deleteLater = true;
+ } else {
+ delete this;
+ }
+}
+
+QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent)
+ : QAbstractEventDispatcher(parent),
+ m_activeScheduler(0),
+ m_wakeUpAO(0),
+ m_completeDeferredAOs(0),
+ m_interrupt(false),
+ m_wakeUpDone(0),
+ m_iterationCount(0),
+ m_noSocketEvents(false)
+{
+}
+
+QEventDispatcherSymbian::~QEventDispatcherSymbian()
+{
+ m_processHandle.Close();
+}
+
+void QEventDispatcherSymbian::startingUp()
+{
+ if( !CActiveScheduler::Current() ) {
+ m_activeScheduler = q_check_ptr(new CQtActiveScheduler()); // CBase derived class needs to be checked on new
+ CActiveScheduler::Install(m_activeScheduler);
+ }
+ m_wakeUpAO = q_check_ptr(new QWakeUpActiveObject(this));
+ m_completeDeferredAOs = q_check_ptr(new QCompleteDeferredAOs(this));
+ // We already might have posted events, wakeup once to process them
+ wakeUp();
+}
+
+void QEventDispatcherSymbian::closingDown()
+{
+ if (m_selectThread.isRunning()) {
+ m_selectThread.stop();
+ }
+
+ delete m_completeDeferredAOs;
+ delete m_wakeUpAO;
+ if (m_activeScheduler) {
+ delete m_activeScheduler;
+ }
+}
+
+bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags flags )
+{
+ bool handledAnyEvent = false;
+
+ QT_TRY {
+ Q_D(QAbstractEventDispatcher);
+
+ // It is safe if this counter overflows. The main importance is that each
+ // iteration count is different from the last.
+ m_iterationCount++;
+
+ RThread &thread = d->threadData->symbian_thread_handle;
+
+ bool block;
+ if (flags & QEventLoop::WaitForMoreEvents) {
+ block = true;
+ emit aboutToBlock();
+ } else {
+ block = false;
+ }
+
+ bool oldNoSocketEventsValue = m_noSocketEvents;
+ if (flags & QEventLoop::ExcludeSocketNotifiers) {
+ m_noSocketEvents = true;
+ } else {
+ m_noSocketEvents = false;
+ handledAnyEvent = sendDeferredSocketEvents();
+ }
+
+ bool handledSymbianEvent = false;
+ m_interrupt = false;
+
+ /*
+ * This QTime variable is used to measure the time it takes to finish
+ * the event loop. If we take too long in the loop, other processes
+ * may be starved and killed. After the first event has completed, we
+ * take the current time, and if the remaining events take longer than
+ * a preset time, we temporarily lower the priority to force a context
+ * switch. For applications that do not take unecessarily long in the
+ * event loop, the priority will not be altered.
+ */
+ QTime time;
+ enum {
+ FirstRun,
+ SubsequentRun,
+ TimeStarted
+ } timeState = FirstRun;
+
+ TProcessPriority priority;
+
+ while (1) {
+ if (block) {
+ // This is where Qt will spend most of its time.
+ CActiveScheduler::Current()->WaitForAnyRequest();
+ } else {
+ if (thread.RequestCount() == 0) {
+ break;
+ }
+ // This one should return without delay.
+ CActiveScheduler::Current()->WaitForAnyRequest();
+ }
+
+ if (timeState == SubsequentRun) {
+ time.start();
+ timeState = TimeStarted;
+ }
+
+ TInt error;
+ handledSymbianEvent = CActiveScheduler::RunIfReady(error, CActive::EPriorityIdle);
+ if (error) {
+ qWarning("CActiveScheduler::RunIfReady() returned error: %i\n", error);
+ CActiveScheduler::Current()->Error(error);
+ }
+
+ if (!handledSymbianEvent) {
+ qFatal("QEventDispatcherSymbian::processEvents(): Caught Symbian stray signal");
+ }
+ handledAnyEvent = true;
+ if (m_interrupt) {
+ break;
+ }
+ block = false;
+ if (timeState == TimeStarted && time.elapsed() > 100) {
+ priority = m_processHandle.Priority();
+ m_processHandle.SetPriority(EPriorityLow);
+ time.start();
+ // Slight chance of race condition in the next lines, but nothing fatal
+ // will happen, just wrong priority.
+ if (m_processHandle.Priority() == EPriorityLow) {
+ m_processHandle.SetPriority(priority);
+ }
+ }
+ if (timeState == FirstRun)
+ timeState = SubsequentRun;
+ };
+
+ emit awake();
+
+ m_noSocketEvents = oldNoSocketEventsValue;
+ } QT_CATCH (const std::exception& ex) {
+#ifndef QT_NO_EXCEPTIONS
+ CActiveScheduler::Current()->Error(qt_symbian_exception2Error(ex));
+#endif
+ }
+
+ return handledAnyEvent;
+}
+
+void QEventDispatcherSymbian::timerFired(int timerId)
+{
+ QHash<int, SymbianTimerInfoPtr>::iterator i = m_timerList.find(timerId);
+ if (i == m_timerList.end()) {
+ // The timer has been deleted. Ignore this event.
+ return;
+ }
+
+ SymbianTimerInfoPtr timerInfo = *i;
+
+ // Prevent infinite timer recursion.
+ if (timerInfo->inTimerEvent) {
+ return;
+ }
+
+ timerInfo->inTimerEvent = true;
+
+ QTimerEvent event(timerInfo->timerId);
+ QCoreApplication::sendEvent(timerInfo->receiver, &event);
+
+ timerInfo->inTimerEvent = false;
+
+ return;
+}
+
+void QEventDispatcherSymbian::socketFired(QSocketActiveObject *socketAO)
+{
+ if (m_noSocketEvents) {
+ m_deferredSocketEvents.append(socketAO);
+ return;
+ }
+
+ QEvent e(QEvent::SockAct);
+ socketAO->m_inSocketEvent = true;
+ QCoreApplication::sendEvent(socketAO->m_notifier, &e);
+ socketAO->m_inSocketEvent = false;
+
+ if (socketAO->m_deleteLater) {
+ delete socketAO;
+ } else {
+ socketAO->iStatus = KRequestPending;
+ socketAO->SetActive();
+ reactivateSocketNotifier(socketAO->m_notifier);
+ }
+}
+
+void QEventDispatcherSymbian::wakeUpWasCalled()
+{
+ // The reactivation should happen in RunL, right before the call to this function.
+ // This is because m_wakeUpDone is the "signal" that the object can be completed
+ // once more.
+ // Also, by dispatching the posted events after resetting m_wakeUpDone, we guarantee
+ // that no posted event notification will be lost. If we did it the other way
+ // around, it would be possible for another thread to post an event right after
+ // the sendPostedEvents was done, but before the object was ready to be completed
+ // again. This could deadlock the application if there are no other posted events.
+ m_wakeUpDone.fetchAndStoreOrdered(0);
+ sendPostedEvents();
+}
+
+void QEventDispatcherSymbian::interrupt()
+{
+ m_interrupt = true;
+ wakeUp();
+}
+
+void QEventDispatcherSymbian::wakeUp()
+{
+ Q_D(QAbstractEventDispatcher);
+
+ if (m_wakeUpAO && m_wakeUpDone.testAndSetAcquire(0, 1)) {
+ TRequestStatus *status = &m_wakeUpAO->iStatus;
+ QEventDispatcherSymbian::RequestComplete(d->threadData->symbian_thread_handle, status, KErrNone);
+ }
+}
+
+bool QEventDispatcherSymbian::sendPostedEvents()
+{
+ Q_D(QAbstractEventDispatcher);
+
+ // moveToThread calls this and canWait == true -> Events will never get processed
+ // if we check for d->threadData->canWait
+ //
+ // QCoreApplication::postEvent sets canWait = false, but after the object and events
+ // are moved to a new thread, the canWait in new thread is true i.e. not changed to reflect
+ // the flag on old thread. That's why events in a new thread will not get processed.
+ // This migth be actually bug in moveToThread functionality, but because other platforms
+ // do not check canWait in wakeUp (where we essentially are now) - decided to remove it from
+ // here as well.
+
+ //if (!d->threadData->canWait) {
+ QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
+ return true;
+ //}
+ //return false;
+}
+
+inline void QEventDispatcherSymbian::addDeferredActiveObject(QActiveObject *object)
+{
+ if (m_deferredActiveObjects.isEmpty()) {
+ m_completeDeferredAOs->complete();
+ }
+ m_deferredActiveObjects.append(object);
+}
+
+inline void QEventDispatcherSymbian::removeDeferredActiveObject(QActiveObject *object)
+{
+ m_deferredActiveObjects.removeAll(object);
+}
+
+void QEventDispatcherSymbian::reactivateDeferredActiveObjects()
+{
+ while (!m_deferredActiveObjects.isEmpty()) {
+ QActiveObject *object = m_deferredActiveObjects.takeFirst();
+ object->reactivateAndComplete();
+ }
+
+ // We do this because we want to return from processEvents. This is because
+ // each invocation of processEvents should only run each active object once.
+ // The active scheduler should run them continously, however.
+ m_interrupt = true;
+}
+
+bool QEventDispatcherSymbian::sendDeferredSocketEvents()
+{
+ bool sentAnyEvents = false;
+ while (!m_deferredSocketEvents.isEmpty()) {
+ sentAnyEvents = true;
+ socketFired(m_deferredSocketEvents.takeFirst());
+ }
+
+ return sentAnyEvents;
+}
+
+void QEventDispatcherSymbian::flush()
+{
+}
+
+bool QEventDispatcherSymbian::hasPendingEvents()
+{
+ Q_D(QAbstractEventDispatcher);
+ return (d->threadData->symbian_thread_handle.RequestCount() != 0
+ || !d->threadData->canWait || !m_deferredSocketEvents.isEmpty());
+}
+
+void QEventDispatcherSymbian::registerSocketNotifier ( QSocketNotifier * notifier )
+{
+ QSocketActiveObject *socketAO = q_check_ptr(new QSocketActiveObject(this, notifier));
+ m_notifiers.insert(notifier, socketAO);
+ m_selectThread.requestSocketEvents(notifier, &socketAO->iStatus);
+}
+
+void QEventDispatcherSymbian::unregisterSocketNotifier ( QSocketNotifier * notifier )
+{
+ m_selectThread.cancelSocketEvents(notifier);
+ if (m_notifiers.contains(notifier)) {
+ QSocketActiveObject *sockObj = *m_notifiers.find(notifier);
+ m_deferredSocketEvents.removeAll(sockObj);
+ sockObj->deleteLater();
+ m_notifiers.remove(notifier);
+ }
+}
+
+void QEventDispatcherSymbian::reactivateSocketNotifier(QSocketNotifier *notifier)
+{
+ m_selectThread.requestSocketEvents(notifier, &m_notifiers[notifier]->iStatus);
+}
+
+void QEventDispatcherSymbian::registerTimer ( int timerId, int interval, QObject * object )
+{
+ if (interval < 0) {
+ qWarning("Timer interval < 0");
+ interval = 0;
+ }
+
+ SymbianTimerInfoPtr timer(new SymbianTimerInfo);
+ timer->timerId = timerId;
+ timer->interval = interval;
+ timer->inTimerEvent = false;
+ timer->receiver = object;
+ timer->dispatcher = this;
+ timer->timerAO = q_check_ptr(new QTimerActiveObject(this, timer.data()));
+ m_timerList.insert(timerId, timer);
+
+ timer->timerAO->Start();
+}
+
+bool QEventDispatcherSymbian::unregisterTimer ( int timerId )
+{
+ if (!m_timerList.contains(timerId)) {
+ return false;
+ }
+
+ SymbianTimerInfoPtr timerInfo = m_timerList.take(timerId);
+
+ if (!QObjectPrivate::get(timerInfo->receiver)->inThreadChangeEvent)
+ QAbstractEventDispatcherPrivate::releaseTimerId(timerId);
+
+ return true;
+}
+
+bool QEventDispatcherSymbian::unregisterTimers ( QObject * object )
+{
+ if (m_timerList.isEmpty())
+ return false;
+
+ bool unregistered = false;
+ for (QHash<int, SymbianTimerInfoPtr>::iterator i = m_timerList.begin(); i != m_timerList.end(); ) {
+ if ((*i)->receiver == object) {
+ i = m_timerList.erase(i);
+ unregistered = true;
+ } else {
+ ++i;
+ }
+ }
+
+ return unregistered;
+}
+
+QList<QEventDispatcherSymbian::TimerInfo> QEventDispatcherSymbian::registeredTimers ( QObject * object ) const
+{
+ QList<TimerInfo> list;
+ for (QHash<int, SymbianTimerInfoPtr>::const_iterator i = m_timerList.begin(); i != m_timerList.end(); ++i) {
+ if ((*i)->receiver == object) {
+ list.push_back(TimerInfo((*i)->timerId, (*i)->interval));
+ }
+ }
+
+ return list;
+}
+
+/*
+ * This active scheduler class implements a simple report and continue policy, for Symbian OS leaves
+ * or exceptions from Qt that fall back to the scheduler.
+ * It will be used in cases where there is no existing active scheduler installed.
+ * Apps which link to qts60main.lib will have the UI active scheduler installed in the main thread
+ * instead of this one. But this would be used in other threads in the UI.
+ * An app could replace this behaviour by installing an alternative active scheduler.
+ */
+void CQtActiveScheduler::Error(TInt aError) const
+{
+ QT_TRY {
+ qWarning("Error from active scheduler %d", aError);
+ }
+ QT_CATCH (const std::bad_alloc&) {} // ignore alloc fails, nothing more can be done
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h
new file mode 100644
index 0000000..021de13
--- /dev/null
+++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h
@@ -0,0 +1,307 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEVENTDISPATCHER_SYMBIAN_P_H
+#define QEVENTDISPATCHER_SYMBIAN_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 <qhash.h>
+#include <qset.h>
+#include <qshareddata.h>
+#include <qabstracteventdispatcher.h>
+#include <private/qabstracteventdispatcher_p.h>
+#include <qthread.h>
+#include <qmutex.h>
+#include <qwaitcondition.h>
+#include <qsocketnotifier.h>
+
+#include <e32base.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QEventDispatcherSymbian;
+class QTimerActiveObject;
+
+class QActiveObject : public CActive
+{
+public:
+ QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher);
+ ~QActiveObject();
+
+ bool okToRun();
+
+ void reactivateAndComplete();
+
+protected:
+ QEventDispatcherSymbian *m_dispatcher;
+
+private:
+ bool m_hasAlreadyRun : 1;
+ bool m_hasRunAgain : 1;
+ int m_iterationCount;
+};
+
+class QWakeUpActiveObject : public CActive
+{
+public:
+ QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher);
+ ~QWakeUpActiveObject();
+
+ void Complete();
+
+protected:
+ void DoCancel();
+ void RunL();
+
+private:
+ QEventDispatcherSymbian *m_dispatcher;
+};
+
+struct SymbianTimerInfo : public QSharedData
+{
+ SymbianTimerInfo();
+ ~SymbianTimerInfo();
+
+ int timerId;
+ int interval;
+ bool inTimerEvent;
+ QObject *receiver;
+ QTimerActiveObject *timerAO;
+ QEventDispatcherSymbian *dispatcher;
+};
+
+typedef QExplicitlySharedDataPointer<SymbianTimerInfo> SymbianTimerInfoPtr;
+
+// This is a bit of a proxy class. See comments in SetActive and Start for details.
+class QTimerActiveObject : public QActiveObject
+{
+public:
+ QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo);
+ ~QTimerActiveObject();
+
+ void Start();
+
+protected:
+ void DoCancel();
+ void RunL();
+
+private:
+ void Run();
+
+private:
+ SymbianTimerInfo *m_timerInfo;
+ RTimer m_rTimer;
+};
+
+class QCompleteDeferredAOs : public CActive
+{
+public:
+ QCompleteDeferredAOs(QEventDispatcherSymbian *dispatcher);
+ ~QCompleteDeferredAOs();
+
+ void complete();
+
+protected:
+ void DoCancel();
+ void RunL();
+
+private:
+ QEventDispatcherSymbian *m_dispatcher;
+};
+
+class QSocketActiveObject : public QActiveObject
+{
+public:
+ QSocketActiveObject(QEventDispatcherSymbian *dispatcher, QSocketNotifier *notifier);
+ ~QSocketActiveObject();
+
+ void deleteLater();
+
+protected:
+ void DoCancel();
+ void RunL();
+
+private:
+ QSocketNotifier *m_notifier;
+ bool m_inSocketEvent;
+ bool m_deleteLater;
+
+ friend class QEventDispatcherSymbian;
+};
+
+class QSelectThread : public QThread
+{
+ Q_DECLARE_PRIVATE(QThread)
+
+public:
+ QSelectThread();
+ ~QSelectThread();
+
+ void requestSocketEvents ( QSocketNotifier *notifier, TRequestStatus *status );
+ void cancelSocketEvents ( QSocketNotifier *notifier );
+ void restart();
+ void stop();
+
+protected:
+ void run();
+
+private:
+ int updateSocketSet(QSocketNotifier::Type type, fd_set *fds);
+ void updateActivatedNotifiers(QSocketNotifier::Type type, fd_set *fds);
+
+private:
+ int m_pipeEnds[2];
+ QHash<QSocketNotifier *, TRequestStatus *> m_AOStatuses;
+ QMutex m_mutex;
+ QWaitCondition m_waitCond;
+ bool m_quit;
+};
+
+class Q_CORE_EXPORT CQtActiveScheduler : public CActiveScheduler
+{
+public: // from CActiveScheduler
+ virtual void Error(TInt aError) const;
+};
+
+class Q_CORE_EXPORT QEventDispatcherSymbian : public QAbstractEventDispatcher
+{
+ Q_DECLARE_PRIVATE(QAbstractEventDispatcher)
+
+public:
+ QEventDispatcherSymbian(QObject *parent = 0);
+ ~QEventDispatcherSymbian();
+
+ void flush();
+ bool hasPendingEvents();
+ void interrupt();
+ bool processEvents ( QEventLoop::ProcessEventsFlags flags );
+ void registerSocketNotifier ( QSocketNotifier * notifier );
+ void registerTimer ( int timerId, int interval, QObject * object );
+ QList<TimerInfo> registeredTimers ( QObject * object ) const;
+ void unregisterSocketNotifier ( QSocketNotifier * notifier );
+ bool unregisterTimer ( int timerId );
+ bool unregisterTimers ( QObject * object );
+ void wakeUp();
+
+ void startingUp();
+ void closingDown();
+
+ void timerFired(int timerId);
+ void socketFired(QSocketActiveObject *socketAO);
+ void wakeUpWasCalled();
+ void reactivateSocketNotifier(QSocketNotifier *notifier);
+
+ void addDeferredActiveObject(QActiveObject *object);
+ void removeDeferredActiveObject(QActiveObject *object);
+ void reactivateDeferredActiveObjects();
+
+ inline int iterationCount() const { return m_iterationCount; }
+
+ static void RequestComplete(TRequestStatus *&status, TInt reason);
+ static void RequestComplete(RThread &threadHandle, TRequestStatus *&status, TInt reason);
+
+private:
+ bool sendPostedEvents();
+ bool sendDeferredSocketEvents();
+
+private:
+ QSelectThread m_selectThread;
+
+ CQtActiveScheduler *m_activeScheduler;
+
+ QHash<int, SymbianTimerInfoPtr> m_timerList;
+ QHash<QSocketNotifier *, QSocketActiveObject *> m_notifiers;
+
+ QWakeUpActiveObject *m_wakeUpAO;
+ QCompleteDeferredAOs *m_completeDeferredAOs;
+
+ volatile bool m_interrupt;
+ QAtomicInt m_wakeUpDone;
+
+ unsigned char m_iterationCount;
+ bool m_noSocketEvents;
+ QList<QSocketActiveObject *> m_deferredSocketEvents;
+
+ QList<QActiveObject *> m_deferredActiveObjects;
+
+ RProcess m_processHandle;
+};
+
+#ifdef QT_DEBUG
+# define VERIFY_PENDING_REQUEST_STATUS \
+ Q_ASSERT(status->Int() == KRequestPending);
+#else
+# define VERIFY_PENDING_REQUEST_STATUS
+#endif
+
+// Convenience functions for doing some sanity checking on our own complete code.
+// Unless QT_DEBUG is defined, it is exactly equivalent to the Symbian version.
+inline void QEventDispatcherSymbian::RequestComplete(TRequestStatus *&status, TInt reason)
+{
+ VERIFY_PENDING_REQUEST_STATUS
+ User::RequestComplete(status, reason);
+}
+inline void QEventDispatcherSymbian::RequestComplete(RThread &threadHandle, TRequestStatus *&status, TInt reason)
+{
+ VERIFY_PENDING_REQUEST_STATUS
+ threadHandle.RequestComplete(status, reason);
+}
+
+#undef VERIFY_PENDING_REQUEST_STATUS
+
+QT_END_NAMESPACE
+
+#endif // QEVENTDISPATCHER_SYMBIAN_P_H
diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp
index 513543e..fced57d 100644
--- a/src/corelib/kernel/qeventdispatcher_unix.cpp
+++ b/src/corelib/kernel/qeventdispatcher_unix.cpp
@@ -49,11 +49,22 @@
#include "qeventdispatcher_unix_p.h"
#include <private/qthread_p.h>
#include <private/qcoreapplication_p.h>
+#include <private/qcore_unix_p.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+// VxWorks doesn't correctly set the _POSIX_... options
+#if defined(Q_OS_VXWORKS)
+# if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK <= 0)
+# undef _POSIX_MONOTONIC_CLOCK
+# define _POSIX_MONOTONIC_CLOCK 1
+# endif
+# include <pipeDrv.h>
+# include <selectLib.h>
+#endif
+
#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED)
# include <sys/times.h>
#endif
@@ -76,6 +87,7 @@ static void signalHandler(int sig)
}
+#if defined(Q_OS_INTEGRITY) || defined(Q_OS_VXWORKS)
static void initThreadPipeFD(int fd)
{
int ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
@@ -90,25 +102,52 @@ static void initThreadPipeFD(int fd)
if (ret == -1)
perror("QEventDispatcherUNIXPrivate: Unable to set flags on thread pipe");
}
-
+#endif
QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate()
{
extern Qt::HANDLE qt_application_thread_id;
mainThread = (QThread::currentThreadId() == qt_application_thread_id);
+ bool pipefail = false;
// initialize the common parts of the event loop
-#ifdef Q_OS_INTEGRITY
+#if defined(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)
+ if (socketpair(AF_INET, SOCK_STREAM, PF_INET, thread_pipe) == -1) {
perror("QEventDispatcherUNIXPrivate(): Unable to create socket pair");
+ pipefail = true;
+ } else {
+ initThreadPipeFD(thread_pipe[0]);
+ initThreadPipeFD(thread_pipe[1]);
+ }
+#elif defined(Q_OS_VXWORKS)
+ char name[20];
+ qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdCurrent));
+
+ // make sure there is no pipe with this name
+ pipeDevDelete(name, true);
+ // create the pipe
+ if (pipeDevCreate(name, 128 /*maxMsg*/, 1 /*maxLength*/) != OK) {
+ perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe device");
+ pipefail = true;
+ } else {
+ if ((thread_pipe[0] = open(name, O_RDWR, 0)) < 0) {
+ perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe");
+ pipefail = true;
+ } else {
+ initThreadPipeFD(thread_pipe[0]);
+ thread_pipe[1] = thread_pipe[0];
+ }
+ }
#else
- if (pipe(thread_pipe) == -1)
+ if (qt_safe_pipe(thread_pipe, O_NONBLOCK) == -1) {
perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe");
+ pipefail = true;
+ }
#endif
- initThreadPipeFD(thread_pipe[0]);
- initThreadPipeFD(thread_pipe[1]);
+ if (pipefail)
+ qFatal("QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe");
sn_highest = -1;
@@ -117,9 +156,18 @@ QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate()
QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate()
{
+#if defined(Q_OS_VXWORKS)
+ close(thread_pipe[0]);
+
+ char name[20];
+ qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdCurrent));
+
+ pipeDevDelete(name, true);
+#else
// cleanup the common parts of the event loop
close(thread_pipe[0]);
close(thread_pipe[1]);
+#endif
// cleanup timers
qDeleteAll(timerList);
@@ -184,7 +232,7 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags,
continue;
for (int i = 0; i < list.size(); ++i) {
- QSockNot *sn = list.at(i);
+ QSockNot *sn = list[i];
FD_ZERO(&fdset);
FD_SET(sn->fd, &fdset);
@@ -224,9 +272,15 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags,
// select doesn't immediately return next time
int nevents = 0;
if (nsel > 0 && FD_ISSET(thread_pipe[0], &sn_vec[0].select_fds)) {
+#if defined(Q_OS_VXWORKS)
+ char c[16];
+ ::read(thread_pipe[0], c, sizeof(c));
+ ::ioctl(thread_pipe[0], FIOFLUSH, 0);
+#else
char c[16];
while (::read(thread_pipe[0], c, sizeof(c)) > 0)
;
+#endif
if (!wakeUps.testAndSetRelease(1, 0)) {
// hopefully, this is dead code
qWarning("QEventDispatcherUNIX: internal error, wakeUps.testAndSetRelease(1, 0) failed!");
@@ -241,7 +295,7 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags,
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);
+ QSockNot *sn = list[j];
if (FD_ISSET(sn->fd, &sn_vec[i].select_fds))
q->setSocketNotifierPending(sn->obj);
}
@@ -257,18 +311,10 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags,
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);
+ currentTime = qt_gettime();
- if (!useMonotonicTimers) {
+#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)
+ if (!qt_gettime_is_monotonic()) {
// not using monotonic timers, initialize the timeChanged() machinery
previousTime = currentTime;
@@ -284,9 +330,6 @@ QTimerInfoList::QTimerInfoList()
ticksPerSecond = 0;
msPerTick = 0;
}
-#else
- // using monotonic timers unconditionally
- getTime(currentTime);
#endif
firstTimerInfo = currentTimerInfo = 0;
@@ -294,11 +337,24 @@ QTimerInfoList::QTimerInfoList()
timeval QTimerInfoList::updateCurrentTime()
{
- getTime(currentTime);
- return currentTime;
+ return (currentTime = qt_gettime());
}
-#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED)
+#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)) || defined(QT_BOOTSTRAPPED)
+
+template <>
+timeval qAbs(const timeval &t)
+{
+ timeval tmp = t;
+ if (tmp.tv_sec < 0) {
+ tmp.tv_sec = -tmp.tv_sec - 1;
+ tmp.tv_usec -= 1000000;
+ }
+ if (tmp.tv_sec == 0 && tmp.tv_usec < 0) {
+ tmp.tv_usec = -tmp.tv_usec;
+ }
+ return normalizedTimeval(tmp);
+}
/*
Returns true if the real time clock has changed by more than 10%
@@ -309,60 +365,35 @@ timeval QTimerInfoList::updateCurrentTime()
*/
bool QTimerInfoList::timeChanged(timeval *delta)
{
- tms unused;
+ struct tms unused;
clock_t currentTicks = times(&unused);
- int elapsedTicks = currentTicks - previousTicks;
+ clock_t 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;
- }
+ timeval elapsedTimeTicks;
+ elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond;
+ elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000;
+
+ timeval dummy;
+ if (!delta)
+ delta = &dummy;
+ *delta = elapsedTime - elapsedTimeTicks;
+
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;
- }
- }
+ timeval tickGranularity;
+ tickGranularity.tv_sec = 0;
+ tickGranularity.tv_usec = msPerTick * 1000;
+ return elapsedTimeTicks < ((qAbs(*delta) - tickGranularity) * 10);
}
void QTimerInfoList::repairTimersIfNeeded()
{
- if (useMonotonicTimers)
+ if (qt_gettime_is_monotonic())
return;
timeval delta;
if (timeChanged(&delta))
@@ -371,14 +402,6 @@ void QTimerInfoList::repairTimersIfNeeded()
#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()
{
}
@@ -407,7 +430,7 @@ 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;
+ t->timeout = t->timeout + diff;
}
}
@@ -599,30 +622,15 @@ QEventDispatcherUNIX::QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObj
{ }
QEventDispatcherUNIX::~QEventDispatcherUNIX()
-{ }
+{
+ Q_D(QEventDispatcherUNIX);
+ d->threadData->eventDispatcher = 0;
+}
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);
+ return qt_safe_select(nfds, readfds, writefds, exceptfds, timeout);
}
/*!
@@ -706,8 +714,8 @@ QSockNotType::QSockNotType()
QSockNotType::~QSockNotType()
{
- while (!list.isEmpty())
- delete list.takeFirst();
+ for (int i = 0; i < list.size(); ++i)
+ delete list[i];
}
/*****************************************************************************
@@ -743,7 +751,7 @@ void QEventDispatcherUNIX::registerSocketNotifier(QSocketNotifier *notifier)
int i;
for (i = 0; i < list.size(); ++i) {
- QSockNot *p = list.at(i);
+ QSockNot *p = list[i];
if (p->fd < sockfd)
break;
if (p->fd == sockfd) {
@@ -781,7 +789,7 @@ void QEventDispatcherUNIX::unregisterSocketNotifier(QSocketNotifier *notifier)
QSockNot *sn = 0;
int i;
for (i = 0; i < list.size(); ++i) {
- sn = list.at(i);
+ sn = list[i];
if(sn->obj == notifier && sn->fd == sockfd)
break;
}
@@ -799,7 +807,7 @@ void QEventDispatcherUNIX::unregisterSocketNotifier(QSocketNotifier *notifier)
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);
+ d->sn_vec[i].list[0]->fd);
}
}
}
@@ -823,7 +831,7 @@ void QEventDispatcherUNIX::setSocketNotifierPending(QSocketNotifier *notifier)
QSockNot *sn = 0;
int i;
for (i = 0; i < list.size(); ++i) {
- sn = list.at(i);
+ sn = list[i];
if(sn->obj == notifier && sn->fd == sockfd)
break;
}
diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h
index 9559cbc..010a0d5 100644
--- a/src/corelib/kernel/qeventdispatcher_unix_p.h
+++ b/src/corelib/kernel/qeventdispatcher_unix_p.h
@@ -56,54 +56,20 @@
#include "QtCore/qabstracteventdispatcher.h"
#include "QtCore/qlist.h"
#include "private/qabstracteventdispatcher_p.h"
+#include "private/qcore_unix_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>
+#include "QtCore/qvarlengtharray.h"
+
+#if defined(Q_OS_VXWORKS)
+# include <sys/times.h>
+#else
+# include <sys/time.h>
+# if !defined(Q_OS_HPUX) || defined(__ia64)
+# include <sys/select.h>
+# endif
#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 {
@@ -116,9 +82,7 @@ struct QTimerInfo {
class QTimerInfoList : public QList<QTimerInfo*>
{
-#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED)
- bool useMonotonicTimers;
-
+#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)) || defined(QT_BOOTSTRAPPED)
timeval previousTime;
clock_t previousTicks;
int ticksPerSecond;
@@ -133,8 +97,6 @@ class QTimerInfoList : public QList<QTimerInfo*>
public:
QTimerInfoList();
- void getTime(timeval &t);
-
timeval currentTime;
timeval updateCurrentTime();
@@ -153,14 +115,14 @@ public:
int activateTimers();
};
-struct Q_CORE_EXPORT QSockNot
+struct QSockNot
{
QSocketNotifier *obj;
int fd;
fd_set *queue;
};
-class Q_CORE_EXPORT QSockNotType
+class QSockNotType
{
public:
QSockNotType();
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index 4310182..b7934db 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -355,8 +355,7 @@ QEventDispatcherWin32Private::QEventDispatcherWin32Private()
{
resolveTimerAPI();
- wakeUpNotifier.setHandle(QT_WA_INLINE(CreateEventW(0, FALSE, FALSE, 0),
- CreateEventA(0, FALSE, FALSE, 0)));
+ wakeUpNotifier.setHandle(CreateEvent(0, FALSE, FALSE, 0));
if (!wakeUpNotifier.handle())
qWarning("QEventDispatcher: Creating QEventDispatcherWin32Private wakeup event failed");
}
@@ -367,13 +366,8 @@ QEventDispatcherWin32Private::~QEventDispatcherWin32Private()
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
+ QString className = QLatin1String("QEventDispatcherWin32_Internal_Widget") + QString::number(quintptr(qt_internal_proc));
+ UnregisterClass((wchar_t*)className.utf16(), qWinAppInst());
}
void QEventDispatcherWin32Private::activateEventNotifier(QWinEventNotifier * wen)
@@ -382,25 +376,24 @@ void QEventDispatcherWin32Private::activateEventNotifier(QWinEventNotifier * wen
QCoreApplication::sendEvent(wen, &event);
}
-
+// ### Qt 5: remove
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); });
+ return PeekMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
}
+// ### Qt 5: remove
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); });
+ return PostMessage(hWnd, msg, wParam, lParam);
}
+// ### Qt 5: remove
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); });
+ return GetMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax);
}
// This function is called by a workerthread
@@ -450,10 +443,10 @@ LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
#ifdef GWLP_USERDATA
QEventDispatcherWin32 *eventDispatcher =
- (QEventDispatcherWin32 *) GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+ (QEventDispatcherWin32 *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
#else
QEventDispatcherWin32 *eventDispatcher =
- (QEventDispatcherWin32 *) GetWindowLongA(hwnd, GWL_USERDATA);
+ (QEventDispatcherWin32 *) GetWindowLong(hwnd, GWL_USERDATA);
#endif
if (eventDispatcher) {
QEventDispatcherWin32Private *d = eventDispatcher->d_func();
@@ -501,54 +494,35 @@ LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher)
{
- HINSTANCE hi = qWinAppInst();
-#if defined(Q_OS_WINCE)
+ // make sure that multiple Qt's can coexist in the same process
+ QString className = QLatin1String("QEventDispatcherWin32_Internal_Widget") + QString::number(quintptr(qt_internal_proc));
+
WNDCLASS wc;
-#else
- WNDCLASSA wc;
-#endif
wc.style = 0;
wc.lpfnWndProc = qt_internal_proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
- wc.hInstance = hi;
+ wc.hInstance = qWinAppInst();
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = 0;
wc.lpszMenuName = NULL;
+ wc.lpszClassName = reinterpret_cast<const wchar_t *> (className.utf16());
- // 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
-
+ wc.lpszClassName, // window name
+ 0, // style
+ 0, 0, 0, 0, // geometry
+ 0, // parent
+ 0, // menu handle
+ qWinAppInst(), // application
+ 0); // windows creation data.
#ifdef GWLP_USERDATA
- SetWindowLongPtrA(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher);
+ SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher);
#else
- SetWindowLongA(wnd, GWL_USERDATA, (LONG)eventDispatcher);
+ SetWindowLong(wnd, GWL_USERDATA, (LONG)eventDispatcher);
#endif
if (!wnd) {
@@ -697,13 +671,14 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
haveMessage = true;
msg = d->queuedSocketEvents.takeFirst();
} else {
- haveMessage = winPeekMessage(&msg, 0, 0, 0, PM_REMOVE);
+ haveMessage = PeekMessage(&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)) {
+ || msg.message == WM_MOUSEWHEEL
+ || msg.message == WM_MOUSEHWHEEL)) {
// queue user input events for later processing
haveMessage = false;
d->queuedUserInputEvents.append(msg);
@@ -744,11 +719,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
if (!filterEvent(&msg)) {
TranslateMessage(&msg);
- QT_WA({
- DispatchMessage(&msg);
- } , {
- DispatchMessageA(&msg);
- });
+ DispatchMessage(&msg);
}
} else if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) {
d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
@@ -787,7 +758,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
bool QEventDispatcherWin32::hasPendingEvents()
{
MSG msg;
- return qGlobalPostedEventsCount() || winPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
+ return qGlobalPostedEventsCount() || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
}
void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
diff --git a/src/corelib/kernel/qfunctions_p.h b/src/corelib/kernel/qfunctions_p.h
index 37af736..c019286 100644
--- a/src/corelib/kernel/qfunctions_p.h
+++ b/src/corelib/kernel/qfunctions_p.h
@@ -57,6 +57,8 @@
#if defined(Q_OS_WINCE)
# include "QtCore/qfunctions_wince.h"
+#elif defined(Q_OS_VXWORKS)
+# include "QtCore/qfunctions_vxworks.h"
#endif
#ifdef Q_CC_RVCT
diff --git a/src/corelib/kernel/qfunctions_vxworks.cpp b/src/corelib/kernel/qfunctions_vxworks.cpp
new file mode 100644
index 0000000..48cd8dd
--- /dev/null
+++ b/src/corelib/kernel/qfunctions_vxworks.cpp
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+
+#ifdef Q_OS_VXWORKS
+
+#include "qplatformdefs.h"
+#include "qfunctions_vxworks.h"
+
+#include <vmLib.h>
+#include <selectLib.h>
+#include <ioLib.h>
+
+QT_USE_NAMESPACE
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// no lfind() - used by the TIF image format
+void *lfind(const void* key, const void* base, size_t* elements, size_t size,
+ int (*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;
+}
+
+
+// no rand_r(), but rand()
+// NOTE: this implementation is wrong for multi threaded applications,
+// but there is no way to get it right on VxWorks (in kernel mode)
+int rand_r(unsigned int * /*seedp*/)
+{
+ return rand();
+}
+
+// no usleep() support
+int usleep(unsigned int usec)
+{
+ div_t dt = div(usec, 1000000);
+ struct timespec ts = { dt.quot, dt.rem * 1000 };
+
+ return nanosleep(&ts, 0);
+}
+
+
+// gettimeofday() is declared, but is missing from the library
+// It IS however defined in the Curtis-Wright X11 libraries, so
+// we have to make the symbol 'weak'
+#if defined(Q_CC_DIAB)
+# pragma weak gettimeofday
+#endif
+int gettimeofday(struct timeval *tv, void /*struct timezone*/ *)
+{
+ // the compiler will optimize this and will only use one code path
+ if (sizeof(struct timeval) == sizeof(struct timespec)) {
+ int res = clock_gettime(CLOCK_REALTIME, (struct timespec *) tv);
+ if (!res)
+ tv->tv_usec /= 1000;
+ return res;
+ } else {
+ struct timespec ts;
+
+ int res = clock_gettime(CLOCK_REALTIME, &ts);
+ if (!res) {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+ return res;
+ }
+}
+
+// neither getpagesize() or sysconf(_SC_PAGESIZE) are available
+int getpagesize()
+{
+ return vmPageSizeGet();
+}
+
+// symlinks are not supported (lstat is now just a call to stat - see qplatformdefs.h)
+int symlink(const char *, const char *)
+{
+ errno = EIO;
+ return -1;
+}
+
+ssize_t readlink(const char *, char *, size_t)
+{
+ errno = EIO;
+ return -1;
+}
+
+// there's no truncate(), but ftruncate() support...
+int truncate(const char *path, off_t length)
+{
+ int fd = open(path, O_WRONLY, 00777);
+ if (fd >= 0) {
+ int res = ftruncate(fd, length);
+ int en = errno;
+ close(fd);
+ errno = en;
+ return res;
+ }
+ // errno is already set by open
+ return -1;
+}
+
+
+
+// VxWorks doesn't know about passwd & friends.
+// in order to avoid patching the unix fs path everywhere
+// we introduce some dummy functions that simulate a single
+// 'root' user on the system.
+
+uid_t getuid()
+{
+ return 0;
+}
+
+gid_t getgid()
+{
+ return 0;
+}
+
+uid_t geteuid()
+{
+ return 0;
+}
+
+struct passwd *getpwuid(uid_t uid)
+{
+ static struct passwd pwbuf = { "root", 0, 0, 0, 0, 0, 0 };
+
+ if (uid == 0) {
+ return &pwbuf;
+ } else {
+ errno = ENOENT;
+ return 0;
+ }
+}
+
+struct group *getgrgid(gid_t gid)
+{
+ static struct group grbuf = { "root", 0, 0, 0 };
+
+ if (gid == 0) {
+ return &grbuf;
+ } else {
+ errno = ENOENT;
+ return 0;
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // Q_OS_VXWORKS
diff --git a/src/corelib/kernel/qfunctions_vxworks.h b/src/corelib/kernel/qfunctions_vxworks.h
new file mode 100644
index 0000000..6100200
--- /dev/null
+++ b/src/corelib/kernel/qfunctions_vxworks.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFUNCTIONS_VXWORKS_H
+#define QFUNCTIONS_VXWORKS_H
+#ifdef Q_OS_VXWORKS
+
+#include <unistd.h>
+#include <pthread.h>
+#include <dirent.h>
+#include <signal.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/times.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#ifndef QT_NO_IPV6IFNAME
+#include <net/if.h>
+#endif
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifdef QT_BUILD_CORE_LIB
+QT_MODULE(Core)
+#endif
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+
+#ifndef RTLD_LOCAL
+#define RTLD_LOCAL 0
+#endif
+
+#ifndef NSIG
+#define NSIG _NSIGS
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// isascii is missing (sometimes!!)
+#ifndef isascii
+inline int isascii(int c) { return (c & 0x7f); }
+#endif
+
+// no lfind() - used by the TIF image format
+void *lfind(const void* key, const void* base, size_t* elements, size_t size,
+ int (*compare)(const void*, const void*));
+
+// no rand_r(), but rand()
+// NOTE: this implementation is wrong for multi threaded applications,
+// but there is no way to get it right on VxWorks (in kernel mode)
+int rand_r(unsigned int * /*seedp*/);
+
+// no usleep() support
+int usleep(unsigned int);
+
+// gettimeofday() is declared, but is missing from the library.
+// It IS however defined in the Curtis-Wright X11 libraries, so
+// we have to make the symbol 'weak'
+int gettimeofday(struct timeval *tv, void /*struct timezone*/ *) __attribute__((weak));
+
+// neither getpagesize() or sysconf(_SC_PAGESIZE) are available
+int getpagesize();
+
+// symlinks are not supported (lstat is now just a call to stat - see qplatformdefs.h)
+int symlink(const char *, const char *);
+ssize_t readlink(const char *, char *, size_t);
+
+// there's no truncate(), but ftruncate() support...
+int truncate(const char *path, off_t length);
+
+// VxWorks doesn't know about passwd & friends.
+// in order to avoid patching the unix fs path everywhere
+// we introduce some dummy functions that simulate a single
+// 'root' user on the system.
+
+uid_t getuid();
+gid_t getgid();
+uid_t geteuid();
+
+struct passwd {
+ char *pw_name; /* user name */
+ char *pw_passwd; /* user password */
+ uid_t pw_uid; /* user ID */
+ gid_t pw_gid; /* group ID */
+ char *pw_gecos; /* real name */
+ char *pw_dir; /* home directory */
+ char *pw_shell; /* shell program */
+};
+
+struct group {
+ char *gr_name; /* group name */
+ char *gr_passwd; /* group password */
+ gid_t gr_gid; /* group ID */
+ char **gr_mem; /* group members */
+};
+
+struct passwd *getpwuid(uid_t uid);
+struct group *getgrgid(gid_t gid);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // Q_OS_VXWORKS
+#endif // QFUNCTIONS_VXWORKS_H
diff --git a/src/corelib/kernel/qfunctions_wince.cpp b/src/corelib/kernel/qfunctions_wince.cpp
index 68bec6f..834c386 100644
--- a/src/corelib/kernel/qfunctions_wince.cpp
+++ b/src/corelib/kernel/qfunctions_wince.cpp
@@ -108,7 +108,7 @@ int qt_wince__getdrive( void )
return 1;
}
-int qt_wince__waccess( const WCHAR *path, int pmode )
+int qt_wince__waccess( const wchar_t *path, int pmode )
{
DWORD res = GetFileAttributes( path );
if ( 0xFFFFFFFF == res )
@@ -118,7 +118,7 @@ int qt_wince__waccess( const WCHAR *path, int pmode )
return -1;
if ( (pmode & X_OK) && !(res & FILE_ATTRIBUTE_DIRECTORY) ) {
- QString file = QString::fromUtf16(reinterpret_cast<const ushort *> (path));
+ QString file = QString::fromWCharArray(path);
if ( !(file.endsWith(QString::fromLatin1(".exe")) ||
file.endsWith(QString::fromLatin1(".com"))) )
return -1;
@@ -130,12 +130,12 @@ int qt_wince__waccess( const WCHAR *path, int pmode )
int qt_wince_open( const char *filename, int oflag, int pmode )
{
QString fn( QString::fromLatin1(filename) );
- return _wopen( (WCHAR*)fn.utf16(), oflag, pmode );
+ return _wopen( (wchar_t*)fn.utf16(), oflag, pmode );
}
-int qt_wince__wopen( const WCHAR *filename, int oflag, int /*pmode*/ )
+int qt_wince__wopen( const wchar_t *filename, int oflag, int /*pmode*/ )
{
- WCHAR *flag;
+ wchar_t *flag;
if ( oflag & _O_APPEND ) {
if ( oflag & _O_WRONLY ) {
@@ -285,25 +285,21 @@ int qt_wince_SetErrorMode(int 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)
+bool qt_wince__wchmod(const wchar_t *file, int mode)
{
+ BOOL success = FALSE;
// ### Does not work properly, what about just adding one property?
if(mode&_S_IWRITE) {
- return SetFileAttributes(file, FILE_ATTRIBUTE_NORMAL);
+ success = SetFileAttributes(file, FILE_ATTRIBUTE_NORMAL);
} else if((mode&_S_IREAD) && !(mode&_S_IWRITE)) {
- return SetFileAttributes(file, FILE_ATTRIBUTE_READONLY);
+ success = SetFileAttributes(file, FILE_ATTRIBUTE_READONLY);
}
- return false;
+ return success ? 0 : -1;
}
HANDLE qt_wince_CreateFileA(LPCSTR filename, DWORD access, DWORD share, LPSECURITY_ATTRIBUTES attr, DWORD dispo, DWORD flags, HANDLE tempFile)
diff --git a/src/corelib/kernel/qfunctions_wince.h b/src/corelib/kernel/qfunctions_wince.h
index 3e67fe0..10620c7 100644
--- a/src/corelib/kernel/qfunctions_wince.h
+++ b/src/corelib/kernel/qfunctions_wince.h
@@ -175,8 +175,8 @@ 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 );
+int qt_wince__waccess( const wchar_t *path, int pmode );
+int qt_wince__wopen( const wchar_t *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 );
@@ -199,10 +199,12 @@ 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);
+#ifndef CoInitialize
+#define CoInitialize(x) CoInitializeEx(x, COINIT_MULTITHREADED)
+#endif
bool qt_wince__chmod(const char *file, int mode);
-bool qt_wince__wchmod(const WCHAR *file, int mode);
+bool qt_wince__wchmod(const wchar_t *file, int mode);
#pragma warning(disable: 4273)
HANDLE qt_wince_CreateFileA(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
@@ -376,7 +378,6 @@ typedef DWORD OLE_COLOR;
#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)
diff --git a/src/corelib/kernel/qguard_p.h b/src/corelib/kernel/qguard_p.h
new file mode 100644
index 0000000..314e3d1
--- /dev/null
+++ b/src/corelib/kernel/qguard_p.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGUARD_P_H
+#define QGUARD_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/qglobal.h"
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+template<class T>
+class QGuard
+{
+ QObject *o;
+ QGuard<QObject> *next;
+ QGuard<QObject> **prev;
+ friend void q_guard_addGuard(QGuard<QObject> *);
+ friend void q_guard_removeGuard(QGuard<QObject> *);
+ friend class QObjectPrivate;
+public:
+ inline QGuard();
+ inline QGuard(T *);
+ inline QGuard(const QGuard<T> &);
+ inline virtual ~QGuard();
+
+ inline QGuard<T> &operator=(const QGuard<T> &o);
+ inline QGuard<T> &operator=(T *);
+
+ 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)); }
+
+protected:
+ virtual void objectDestroyed(T *) {}
+};
+
+QT_END_NAMESPACE
+
+#include "private/qobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+inline void q_guard_addGuard(QGuard<QObject> *);
+inline void q_guard_removeGuard(QGuard<QObject> *);
+
+template<class T>
+QGuard<T>::QGuard()
+: o(0), next(0), prev(0)
+{
+}
+
+template<class T>
+QGuard<T>::QGuard(T *g)
+: o(g), next(0), prev(0)
+{
+ if (o) q_guard_addGuard(reinterpret_cast<QGuard<QObject> *>(this));
+}
+
+template<class T>
+QGuard<T>::QGuard(const QGuard<T> &g)
+: o(g.o), next(0), prev(0)
+{
+ if (o) q_guard_addGuard(reinterpret_cast<QGuard<QObject> *>(this));
+}
+
+template<class T>
+QGuard<T>::~QGuard()
+{
+ if (prev) q_guard_removeGuard(reinterpret_cast<QGuard<QObject> *>(this));
+ o = 0;
+}
+
+template<class T>
+QGuard<T> &QGuard<T>::operator=(const QGuard<T> &g)
+{
+ if (g.o != o) {
+ if (prev)
+ q_guard_removeGuard(reinterpret_cast<QGuard<QObject> *>(this));
+ o = g.o;
+ if (o) q_guard_addGuard(reinterpret_cast<QGuard<QObject> *>(this));
+ }
+ return *this;
+}
+
+template<class T>
+inline QGuard<T> &QGuard<T>::operator=(T *g)
+{
+ if (g != o) {
+ if (prev)
+ q_guard_removeGuard(reinterpret_cast<QGuard<QObject> *>(this));
+ o = g;
+ if (o) q_guard_addGuard(reinterpret_cast<QGuard<QObject> *>(this));
+ }
+ return *this;
+}
+
+QT_END_NAMESPACE
+
+#endif // QGUARD_P_H
diff --git a/src/corelib/kernel/qmath.h b/src/corelib/kernel/qmath.h
index c9aafda..62c2566 100644
--- a/src/corelib/kernel/qmath.h
+++ b/src/corelib/kernel/qmath.h
@@ -132,6 +132,10 @@ inline qreal qPow(qreal x, qreal y)
return pow(x, y);
}
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 434df0c..30f1cc8 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -140,56 +140,6 @@ QT_BEGIN_NAMESPACE
\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); }
@@ -277,6 +227,17 @@ int QMetaObject::static_metacall(Call cl, int idx, void **argv) const
}
/*!
+ \internal
+*/
+int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
+{
+ if (QMetaObject *mo = object->d_ptr->metaObject)
+ return static_cast<QAbstractDynamicMetaObject*>(mo)->metaCall(cl, idx, argv);
+ else
+ return object->qt_metacall(cl, idx, argv);
+}
+
+/*!
\fn const char *QMetaObject::className() const
Returns the class name.
@@ -581,29 +542,46 @@ int QMetaObject::indexOfMethod(const char *method) const
*/
int QMetaObject::indexOfSignal(const char *signal) const
{
- int i = -1;
const QMetaObject *m = this;
- while (m && i < 0) {
+ int i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal);
+ if (i >= 0)
+ i += m->methodOffset();
+ return i;
+}
+
+/*! \internal
+ Same as QMetaObject::indexOfSignal, but the result is the local offset to the base object.
+
+ \a baseObject will be adjusted to the enclosing QMetaObject, or 0 if the signal is not found
+*/
+int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject, const char *signal)
+{
+ int i = -1;
+ while (*baseObject) {
+ const QMetaObject *const m = *baseObject;
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();
+ + m->d.data[priv(m->d.data)->methodData + 5*i]) == 0) {
break;
}
- m = m->d.superdata;
+ if (i >= 0)
+ break;
+ *baseObject = m->d.superdata;
}
#ifndef QT_NO_DEBUG
+ const QMetaObject *m = *baseObject;
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);
+ m->d.stringdata, m->d.superdata->d.stringdata, signal);
}
#endif
return i;
}
+
/*!
Finds \a slot and returns its index; otherwise returns -1.
@@ -635,16 +613,26 @@ static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, co
if (strcmp(self->d.stringdata, name) == 0)
return self;
if (self->d.extradata) {
+#ifdef Q_NO_DATA_RELOCATION
+ const QMetaObjectAccessor *e;
+ Q_ASSERT(priv(self->d.data)->revision >= 2);
+#else
const QMetaObject **e;
if (priv(self->d.data)->revision < 2) {
e = (const QMetaObject**)(self->d.extradata);
- } else {
+ } else
+#endif
+ {
const QMetaObjectExtraData *extra = (const QMetaObjectExtraData*)(self->d.extradata);
e = extra->objects;
}
if (e) {
while (*e) {
+#ifdef Q_NO_DATA_RELOCATION
+ if (const QMetaObject *m =QMetaObject_findMetaObject(&((*e)()), name))
+#else
if (const QMetaObject *m =QMetaObject_findMetaObject((*e), name))
+#endif
return m;
++e;
}
@@ -696,6 +684,14 @@ int QMetaObject::indexOfProperty(const char *name) const
}
m = m->d.superdata;
}
+
+ if (i == -1 && priv(this->d.data)->revision >= 3 && (priv(this->d.data)->flags & DynamicMetaObject)){
+ QAbstractDynamicMetaObject *me =
+ const_cast<QAbstractDynamicMetaObject *>(static_cast<const QAbstractDynamicMetaObject *>(this));
+
+ i = me->createProperty(name, 0);
+ }
+
return i;
}
@@ -1326,6 +1322,18 @@ int QMetaMethod::attributes() const
}
/*!
+ \since 4.6
+
+ Returns this method's index.
+*/
+int QMetaMethod::methodIndex() const
+{
+ if (!mobj)
+ return -1;
+ return ((handle - priv(mobj->d.data)->methodData) / 5) + mobj->methodOffset();
+}
+
+/*!
Returns the access specification of this method (private,
protected, or public).
@@ -1525,7 +1533,7 @@ bool QMetaMethod::invoke(QObject *object,
// 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;
+ return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, methodIndex, param) < 0;
} else {
if (returnValue.data()) {
qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
@@ -1535,7 +1543,9 @@ bool QMetaMethod::invoke(QObject *object,
int nargs = 1; // include return type
void **args = (void **) qMalloc(paramCount * sizeof(void *));
+ Q_CHECK_PTR(args);
int *types = (int *) qMalloc(paramCount * sizeof(int));
+ Q_CHECK_PTR(types);
types[0] = 0; // return type
args[0] = 0;
@@ -2009,6 +2019,11 @@ QVariant::Type QMetaProperty::type() const
if (enumMetaTypeId == 0)
return QVariant::Int;
}
+#ifdef QT_COORD_TYPE
+ // qreal metatype must be resolved at runtime.
+ if (strcmp(typeName(), "qreal") == 0)
+ return QVariant::Type(qMetaTypeId<qreal>());
+#endif
return QVariant::UserType;
}
@@ -2035,6 +2050,18 @@ int QMetaProperty::userType() const
}
/*!
+ \since 4.6
+
+ Returns this property's index.
+*/
+int QMetaProperty::propertyIndex() const
+{
+ if (!mobj)
+ return -1;
+ return idx + mobj->propertyOffset();
+}
+
+/*!
Returns true if the property's type is an enumeration value that
is used as a flag; otherwise returns false.
@@ -2131,19 +2158,25 @@ QVariant QMetaProperty::read(const QObject *object) const
return QVariant();
}
}
+
+ // the status variable is changed by qt_metacall to indicate what it did
+ // this feature is currently only used by QtDBus and should not be depended
+ // upon. Don't change it without looking into QDBusAbstractInterface first
+ // -1 (unchanged): normal qt_metacall, result stored in argv[0]
+ // changed: result stored directly in value
+ int status = -1;
QVariant value;
- void *argv[2] = { 0, &value };
+ void *argv[] = { 0, &value, &status };
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
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::ReadProperty,
+ idx + mobj->propertyOffset(), argv);
+
+ if (status != -1)
return value;
if (t != QVariant::LastType && argv[0] != value.data())
// pointer or reference
@@ -2201,13 +2234,19 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
return false;
}
- void *argv[2] = { 0, &v };
+ // the status variable is changed by qt_metacall to indicate what it did
+ // this feature is currently only used by QtDBus and should not be depended
+ // upon. Don't change it without looking into QDBusAbstractInterface first
+ // -1 (unchanged): normal qt_metacall, result stored in argv[0]
+ // changed: result stored directly in value, return the value of status
+ int status = -1;
+ void *argv[] = { 0, &v, &status };
if (t == QVariant::LastType)
argv[0] = &v;
else
argv[0] = v.data();
- object->qt_metacall(QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv);
- return true;
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv);
+ return status;
}
/*!
@@ -2223,7 +2262,7 @@ bool QMetaProperty::reset(QObject *object) const
if (!object || !mobj || !isResettable())
return false;
void *argv[] = { 0 };
- object->qt_metacall(QMetaObject::ResetProperty, idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(object, QMetaObject::ResetProperty, idx + mobj->propertyOffset(), argv);
return true;
}
@@ -2286,6 +2325,8 @@ QMetaMethod QMetaProperty::notifySignal() const
}
/*!
+ \since 4.6
+
Returns the index of the property change notifying signal if one was
specified, otherwise returns -1.
@@ -2335,8 +2376,8 @@ bool QMetaProperty::isDesignable(const QObject *object) const
bool b = flags & Designable;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyDesignable,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyDesignable,
+ idx + mobj->propertyOffset(), argv);
}
return b;
@@ -2361,8 +2402,8 @@ bool QMetaProperty::isScriptable(const QObject *object) const
bool b = flags & Scriptable;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyScriptable,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyScriptable,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
@@ -2385,8 +2426,8 @@ bool QMetaProperty::isStored(const QObject *object) const
bool b = flags & Stored;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyStored,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyStored,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
@@ -2412,13 +2453,43 @@ bool QMetaProperty::isUser(const QObject *object) const
bool b = flags & User;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyUser,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyUser,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
/*!
+ \since 4.6
+ Returns true if the property is constant; otherwise returns false.
+
+ A property is constant if the \c{Q_PROPERTY()}'s \c CONSTANT attribute
+ is set.
+*/
+bool QMetaProperty::isConstant() const
+{
+ if (!mobj)
+ return false;
+ int flags = mobj->d.data[handle + 2];
+ return flags & Constant;
+}
+
+/*!
+ \since 4.6
+ Returns true if the property is final; otherwise returns false.
+
+ A property is final if the \c{Q_PROPERTY()}'s \c FINAL attribute
+ is set.
+*/
+bool QMetaProperty::isFinal() const
+{
+ if (!mobj)
+ return false;
+ int flags = mobj->d.data[handle + 2];
+ return flags & Final;
+}
+
+/*!
\obsolete
Returns true if the property is editable for the given \a object;
@@ -2438,8 +2509,8 @@ bool QMetaProperty::isEditable(const QObject *object) const
bool b = flags & Editable;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyEditable,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyEditable,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
@@ -2570,4 +2641,20 @@ const char* QMetaClassInfo::value() const
and \a data.
*/
+/*! \internal
+ If the local_method_index is a cloned method, return the index of the original.
+
+ Example: if the index of "destroyed()" is passed, the index of "destroyed(QObject*)" is returned
+ */
+int QMetaObjectPrivate::originalClone(const QMetaObject *mobj, int local_method_index)
+{
+ int handle = get(mobj)->methodData + 5 * local_method_index;
+ while (mobj->d.data[handle + 4] & MethodCloned) {
+ Q_ASSERT(local_method_index > 0);
+ handle -= 5;
+ local_method_index--;
+ }
+ return local_method_index;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index e2a9441..7b35d4a 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -69,6 +69,7 @@ public:
MethodType methodType() const;
enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 };
int attributes() const;
+ int methodIndex() const;
inline const QMetaObject *enclosingMetaObject() const { return mobj; }
@@ -178,6 +179,7 @@ public:
const char *typeName() const;
QVariant::Type type() const;
int userType() const;
+ int propertyIndex() const;
bool isReadable() const;
bool isWritable() const;
@@ -187,6 +189,8 @@ public:
bool isStored(const QObject *obj = 0) const;
bool isEditable(const QObject *obj = 0) const;
bool isUser(const QObject *obj = 0) const;
+ bool isConstant() const;
+ bool isFinal() const;
bool isFlagType() const;
bool isEnumType() const;
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index 7a714c1..6420bbb 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -54,9 +54,87 @@
//
#include <QtCore/qglobal.h>
+#include <QtCore/qobjectdefs.h>
QT_BEGIN_NAMESPACE
+enum PropertyFlags {
+ Invalid = 0x00000000,
+ Readable = 0x00000001,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ EnumOrFlag = 0x00000008,
+ StdCppSet = 0x00000100,
+// Override = 0x00000200,
+ Constant = 0x00000400,
+ Final = 0x00000800,
+ 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
+};
+
+enum MetaObjectFlags {
+ DynamicMetaObject = 0x01
+};
+
+class QMutex;
+
+struct QMetaObjectPrivate
+{
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+ int constructorCount, constructorData; //since revision 2
+ int flags; //since revision 3
+ int signalCount; //since revision 4
+
+ static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
+ { return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }
+
+ static int indexOfSignalRelative(const QMetaObject **baseObject, const char* name);
+ static int originalClone(const QMetaObject *obj, int local_method_index);
+
+#ifndef QT_NO_QOBJECT
+ //defined in qobject.cpp
+ static bool connect(const QObject *sender, int signal_index,
+ const QObject *receiver, int method_index,
+ int type = 0, int *types = 0);
+ static bool disconnect(const QObject *sender, int signal_index,
+ const QObject *receiver, int method_index);
+ static inline bool disconnectHelper(QObjectPrivate::Connection *c,
+ const QObject *receiver, int method_index,
+ QMutex *senderMutex);
+#endif
+};
+
#ifndef UTILS_H
// mirrored in moc's utils.h
static inline bool is_ident_char(char s)
@@ -202,6 +280,7 @@ static QByteArray normalizeTypeInternal(const char *t, const char *e, bool fixSc
return result;
}
+
QT_END_NAMESPACE
#endif
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 5d52bf2..892e557 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -171,6 +171,11 @@ QT_BEGIN_NAMESPACE
\value QBitmap QBitmap
\value QMatrix QMatrix
\value QTransform QTransform
+ \value QMatrix4x4 QMatrix4x4
+ \value QVector2D QVector2D
+ \value QVector3D QVector3D
+ \value QVector4D QVector4D
+ \value QQuaternion QQuaternion
\value User Base value for user types
@@ -179,6 +184,7 @@ QT_BEGIN_NAMESPACE
\omitvalue LastCoreExtType
\omitvalue LastCoreType
\omitvalue LastGuiType
+ \omitvalue QReal
Additional types can be registered using Q_DECLARE_METATYPE().
@@ -271,6 +277,11 @@ static const struct { const char * typeName; int type; } types[] = {
{"QTextFormat", QMetaType::QTextFormat},
{"QMatrix", QMetaType::QMatrix},
{"QTransform", QMetaType::QTransform},
+ {"QMatrix4x4", QMetaType::QMatrix4x4},
+ {"QVector2D", QMetaType::QVector2D},
+ {"QVector3D", QMetaType::QVector3D},
+ {"QVector4D", QMetaType::QVector4D},
+ {"QQuaternion", QMetaType::QQuaternion},
/* All Metatype builtins */
{"void*", QMetaType::VoidStar},
@@ -359,7 +370,7 @@ void QMetaType::registerStreamOperators(const char *typeName, SaveOperator saveO
inf.saveOp = saveOp;
inf.loadOp = loadOp;
}
-#endif
+#endif // QT_NO_DATASTREAM
/*!
Returns the type name associated with the given \a type, or 0 if no
@@ -429,16 +440,15 @@ int QMetaType::registerType(const char *typeName, Destructor destructor,
#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];
+ QCustomTypeInfo inf;
inf.typeName = normalizedTypeName;
inf.constr = constructor;
inf.destr = destructor;
+ idx = ct->size() + User;
+ ct->append(inf);
}
return idx;
}
@@ -670,6 +680,11 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data)
case QMetaType::QTextFormat:
case QMetaType::QMatrix:
case QMetaType::QTransform:
+ case QMetaType::QMatrix4x4:
+ case QMetaType::QVector2D:
+ case QMetaType::QVector3D:
+ case QMetaType::QVector4D:
+ case QMetaType::QQuaternion:
if (!qMetaTypeGuiHelper)
return false;
qMetaTypeGuiHelper[type - FirstGuiType].saveOp(stream, data);
@@ -862,6 +877,11 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
case QMetaType::QTextFormat:
case QMetaType::QMatrix:
case QMetaType::QTransform:
+ case QMetaType::QMatrix4x4:
+ case QMetaType::QVector2D:
+ case QMetaType::QVector3D:
+ case QMetaType::QVector4D:
+ case QMetaType::QQuaternion:
if (!qMetaTypeGuiHelper)
return false;
qMetaTypeGuiHelper[type - FirstGuiType].loadOp(stream, data);
@@ -884,7 +904,7 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
}
return true;
}
-#endif
+#endif // QT_NO_DATASTREAM
/*!
Returns a copy of \a copy, assuming it is of type \a type. If \a
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 601b0a5..50eae56 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -79,13 +79,24 @@ public:
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 */,
+ QMatrix4x4 = 82, QVector2D = 83, QVector3D = 84, QVector4D = 85,
+ QQuaternion = 86,
+ LastGuiType = 86 /* QQuaternion */,
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 */,
+// This logic must match the one in qglobal.h
+#if defined(QT_COORD_TYPE)
+ QReal = 0,
+#elif defined(QT_NO_FPU) || defined(QT_ARCH_ARM) || defined(QT_ARCH_WINDOWSCE) || defined(QT_ARCH_SYMBIAN)
+ QReal = Float,
+#else
+ QReal = Double,
+#endif
+
User = 256
};
@@ -174,7 +185,7 @@ void qRegisterMetaTypeStreamOperators(const char *typeName
QMetaType::registerStreamOperators(typeName, reinterpret_cast<QMetaType::SaveOperator>(sptr),
reinterpret_cast<QMetaType::LoadOperator>(lptr));
}
-#endif
+#endif // QT_NO_DATASTREAM
template <typename T>
struct QMetaTypeId
@@ -283,6 +294,11 @@ class QTextLength;
class QTextFormat;
class QMatrix;
class QTransform;
+class QMatrix4x4;
+class QVector2D;
+class QVector3D;
+class QVector4D;
+class QQuaternion;
QT_END_NAMESPACE
@@ -345,6 +361,11 @@ Q_DECLARE_BUILTIN_METATYPE(QTextLength, QTextLength)
Q_DECLARE_BUILTIN_METATYPE(QTextFormat, QTextFormat)
Q_DECLARE_BUILTIN_METATYPE(QMatrix, QMatrix)
Q_DECLARE_BUILTIN_METATYPE(QTransform, QTransform)
+Q_DECLARE_BUILTIN_METATYPE(QMatrix4x4, QMatrix4x4)
+Q_DECLARE_BUILTIN_METATYPE(QVector2D, QVector2D)
+Q_DECLARE_BUILTIN_METATYPE(QVector3D, QVector3D)
+Q_DECLARE_BUILTIN_METATYPE(QVector4D, QVector4D)
+Q_DECLARE_BUILTIN_METATYPE(QQuaternion, QQuaternion)
QT_END_HEADER
diff --git a/src/corelib/kernel/qmimedata.cpp b/src/corelib/kernel/qmimedata.cpp
index 498cb89..6b87320 100644
--- a/src/corelib/kernel/qmimedata.cpp
+++ b/src/corelib/kernel/qmimedata.cpp
@@ -105,7 +105,7 @@ QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QVariant::Ty
Q_Q(const QMimeData);
QVariant data = q->retrieveData(format, type);
- if (data.type() == type || data.type() == QVariant::Invalid)
+ if (data.type() == type || !data.isValid())
return data;
// provide more conversion possiblities than just what QVariant provides
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index f4a4174..4d9d3b2 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -41,6 +41,7 @@
#include "qobject.h"
#include "qobject_p.h"
+#include "qmetaobject_p.h"
#include "qabstracteventdispatcher.h"
#include "qcoreapplication.h"
@@ -56,8 +57,10 @@
#include <qvarlengtharray.h>
#include <qset.h>
#include <qsemaphore.h>
+#include <qsharedpointer.h>
#include <private/qorderedmutexlocker_p.h>
+#include <private/qmutexpool_p.h>
#include <new>
@@ -70,7 +73,8 @@ static int DIRECT_CONNECTION_ONLY = 0;
static int *queuedConnectionTypes(const QList<QByteArray> &typeNames)
{
- int *types = static_cast<int *>(qMalloc((typeNames.count() + 1) * sizeof(int)));
+ int *types = new int [typeNames.count() + 1];
+ Q_CHECK_PTR(types);
for (int i = 0; i < typeNames.count(); ++i) {
const QByteArray typeName = typeNames.at(i);
if (typeName.endsWith('*'))
@@ -82,7 +86,7 @@ static int *queuedConnectionTypes(const QList<QByteArray> &typeNames)
qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
"(Make sure '%s' is registered using qRegisterMetaType().)",
typeName.constData(), typeName.constData());
- qFree(types);
+ delete [] types;
return 0;
}
}
@@ -91,16 +95,41 @@ static int *queuedConnectionTypes(const QList<QByteArray> &typeNames)
return types;
}
+static QBasicAtomicPointer<QMutexPool> signalSlotMutexes = Q_BASIC_ATOMIC_INITIALIZER(0);
+static QBasicAtomicInt objectCount = Q_BASIC_ATOMIC_INITIALIZER(0);
+
+/** \internal
+ * mutex to be locked when accessing the connectionlists or the senders list
+ */
+static QMutex *signalSlotLock(const QObject *o)
+{
+ if (!signalSlotMutexes) {
+ QMutexPool *mp = new QMutexPool;
+ if (!signalSlotMutexes.testAndSetOrdered(0, mp)) {
+ delete mp;
+ }
+ }
+ return signalSlotMutexes->get(o);
+}
+
extern "C" Q_CORE_EXPORT void qt_addObject(QObject *)
{
+ objectCount.ref();
}
extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *)
{
+ if(!objectCount.deref()) {
+ QMutexPool *old = signalSlotMutexes.fetchAndStoreAcquire(0);
+ delete old;
+ }
}
+QObjectData::~QObjectData() {}
+QDeclarativeData::~QDeclarativeData() {}
+
QObjectPrivate::QObjectPrivate(int version)
- : threadData(0), currentSender(0), currentChildBeingDeleted(0), connectionLists(0)
+ : threadData(0), connectionLists(0), senders(0), currentSender(0), currentChildBeingDeleted(0), declarativeData(0), objectGuards(0)
{
if (version != QObjectPrivateVersion)
qFatal("Cannot mix incompatible Qt libraries");
@@ -116,14 +145,18 @@ QObjectPrivate::QObjectPrivate(int version)
receiveChildEvents = true;
postedEvents = 0;
extraData = 0;
- connectedSignals = 0;
+ for (uint i = 0; i < (sizeof connectedSignals / sizeof connectedSignals[0]); ++i)
+ connectedSignals[i] = 0;
inEventHandler = false;
inThreadChangeEvent = false;
deleteWatch = 0;
+ metaObject = 0;
+ hasGuards = false;
}
QObjectPrivate::~QObjectPrivate()
{
+ delete static_cast<QAbstractDynamicMetaObject*>(metaObject);
if (deleteWatch)
*deleteWatch = 1;
#ifndef QT_NO_USERDATA
@@ -190,12 +223,44 @@ void QObjectPrivate::removePendingChildInsertedEvents(QObject *child)
#endif
+/*!\internal
+ For a given metaobject, compute the signal offset, and the method offset (including signals)
+*/
+static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset)
+{
+ *signalOffset = *methodOffset = 0;
+ const QMetaObject *m = metaobject->d.superdata;
+ while (m) {
+ const QMetaObjectPrivate *d = QMetaObjectPrivate::get(m);
+ *methodOffset += d->methodCount;
+ *signalOffset += (d->revision >= 4) ? d->signalCount : d->methodCount;
+ /*Before Qt 4.6 (revision 4), the signalCount information was not generated by moc.
+ so for compatibility we consider all the method as slot for old moc output*/
+ m = m->d.superdata;
+ }
+}
+
+/*
+ This vector contains the all connections from an object.
+
+ Each object may have one vector containing the lists of
+ connections for a given signal. The index in the vector correspond
+ to the signal index. The signal index is the one returned by
+ QObjectPrivate::signalIndex (not QMetaObject::indexOfSignal).
+ Negative index means connections to all signals.
+
+ This vector is protected by the object mutex (signalSlotMutexes())
+
+ Each Connection is also part of a 'senders' linked list. The mutex
+ of the receiver must be locked when touching the pointers of this
+ linked list.
+*/
class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList>
{
public:
- bool orphaned;
- bool dirty;
- int inUse;
+ bool orphaned; //the QObject owner of this vector has been destroyed while the vector was inUse
+ bool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet
+ int inUse; //number of functions that are currently accessing this object or its connections
QObjectPrivate::ConnectionList allsignals;
QObjectConnectionListVector()
@@ -216,53 +281,59 @@ public:
}
};
+// Used by QAccessibleWidget
bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const
{
Q_Q(const QObject);
- int signal_index = q->metaObject()->indexOfSignal(signal);
+ int signal_index = signalIndex(signal);
if (signal_index < 0)
return false;
- QMutexLocker locker(&threadData->mutex);
+ QMutexLocker locker(signalSlotLock(q));
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)
+ const QObjectPrivate::Connection *c =
+ connectionLists->at(signal_index).first;
+
+ while (c) {
+ if (c->receiver == receiver)
return true;
+ c = c->nextConnectionList;
}
}
}
return false;
}
+// Used by QAccessibleWidget
QObjectList QObjectPrivate::receiverList(const char *signal) const
{
Q_Q(const QObject);
QObjectList returnValue;
- int signal_index = q->metaObject()->indexOfSignal(signal);
+ int signal_index = signalIndex(signal);
if (signal_index < 0)
return returnValue;
- QMutexLocker locker(&threadData->mutex);
+ QMutexLocker locker(signalSlotLock(q));
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;
+ const QObjectPrivate::Connection *c = connectionLists->at(signal_index).first;
+
+ while (c) {
+ if (c->receiver)
+ returnValue << c->receiver;
+ c = c->nextConnectionList;
}
}
}
return returnValue;
}
+// Used by QAccessibleWidget
QObjectList QObjectPrivate::senderList() const
{
QObjectList returnValue;
- QMutexLocker locker(&threadData->mutex);
- for (int i = 0; i < senders.count(); ++i)
- returnValue << senders.at(i).sender;
+ QMutexLocker locker(signalSlotLock(q_func()));
+ for (Connection *c = senders; c; c = c->next)
+ returnValue << c->sender;
return returnValue;
}
@@ -274,75 +345,50 @@ void QObjectPrivate::addConnection(int signal, Connection *c)
connectionLists->resize(signal + 1);
ConnectionList &connectionList = (*connectionLists)[signal];
- connectionList.append(*c);
+ if (connectionList.last) {
+ connectionList.last->nextConnectionList = c;
+ } else {
+ connectionList.first = c;
+ }
+ connectionList.last = 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--);
+ QObjectPrivate::ConnectionList &connectionList =
+ (*connectionLists)[signal];
+
+ // Set to the last entry in the connection list that was *not*
+ // deleted. This is needed to update the list's last pointer
+ // at the end of the cleanup.
+ QObjectPrivate::Connection *last = 0;
+
+ QObjectPrivate::Connection **prev = &connectionList.first;
+ QObjectPrivate::Connection *c = *prev;
+ while (c) {
+ if (c->receiver) {
+ last = c;
+ prev = &c->nextConnectionList;
+ c = *prev;
+ } else {
+ QObjectPrivate::Connection *next = c->nextConnectionList;
+ *prev = next;
+ delete c;
+ c = next;
+ }
}
- }
- 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;
- }
+ // Correct the connection list's last pointer.
+ // As conectionList.last could equal last, this could be a noop
+ connectionList.last = last;
}
+ connectionLists->dirty = false;
}
- // Q_ASSERT_X(false, "QObjectPrivate::derefSender", "sender not found");
}
QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver,
@@ -382,6 +428,7 @@ void QMetaObject::addGuard(QObject **ptr)
return;
}
QMutexLocker locker(guardHashLock());
+ QObjectPrivate::get(*ptr)->hasGuards = true;
hash->insert(*ptr, ptr);
}
@@ -392,17 +439,24 @@ void QMetaObject::removeGuard(QObject **ptr)
if (!*ptr)
return;
GuardHash *hash = guardHash();
- if (!hash)
+ /* check that the hash is empty - otherwise we might detach
+ the shared_null hash, which will alloc, which is not nice */
+ if (!hash || hash->isEmpty())
return;
QMutexLocker locker(guardHashLock());
GuardHash::iterator it = hash->find(*ptr);
const GuardHash::iterator end = hash->end();
+ bool more = false; //if the QObject has more pointer attached to it.
for (; it.key() == *ptr && it != end; ++it) {
if (it.value() == ptr) {
- (void) hash->erase(it);
+ it = hash->erase(it);
+ if (!more) more = (it != end && it.key() == *ptr);
break;
}
+ more = true;
}
+ if (!more)
+ QObjectPrivate::get(*ptr)->hasGuards = false;
}
/*!\internal
@@ -415,28 +469,63 @@ void QMetaObject::changeGuard(QObject **ptr, QObject *o)
return;
}
QMutexLocker locker(guardHashLock());
+ if (o) {
+ hash->insert(o, ptr);
+ QObjectPrivate::get(o)->hasGuards = true;
+ }
if (*ptr) {
+ bool more = false; //if the QObject has more pointer attached to it.
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);
+ it = hash->erase(it);
+ if (!more) more = (it != end && it.key() == *ptr);
break;
}
+ more = true;
}
+ if (!more)
+ QObjectPrivate::get(*ptr)->hasGuards = false;
}
*ptr = o;
- if (*ptr)
- hash->insert(*ptr, ptr);
}
/*! \internal
*/
void QObjectPrivate::clearGuards(QObject *object)
{
- GuardHash *hash = guardHash();
- if (hash) {
- QMutexLocker locker(guardHashLock());
+ QObjectPrivate *priv = QObjectPrivate::get(object);
+ QGuard<QObject> *guard = priv->objectGuards;
+ while (guard) {
+ guard->o = 0;
+ guard = guard->next;
+ }
+ while (priv->objectGuards) {
+ guard = priv->objectGuards;
+ guard->prev = 0;
+ if (guard->next) guard->next->prev = &priv->objectGuards;
+ priv->objectGuards = guard->next;
+ guard->next = 0;
+ guard->objectDestroyed(object);
+ }
+
+ if (!priv->hasGuards)
+ return;
+
+ GuardHash *hash = 0;
+ QMutex *mutex = 0;
+ QT_TRY {
+ hash = guardHash();
+ mutex = guardHashLock();
+ } QT_CATCH(const std::bad_alloc &) {
+ // do nothing in case of OOM - code below is safe
+ }
+
+ /* check that the hash is empty - otherwise we might detach
+ the shared_null hash, which will alloc, which is not nice */
+ if (hash && !hash->isEmpty()) {
+ QMutexLocker locker(mutex);
GuardHash::iterator it = hash->find(object);
const GuardHash::iterator end = hash->end();
while (it.key() == object && it != end) {
@@ -474,7 +563,7 @@ QMetaCallEvent::~QMetaCallEvent()
*/
int QMetaCallEvent::placeMetaCall(QObject *object)
{
- return object->qt_metacall(QMetaObject::InvokeMetaMethod, id_, args_);
+ return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, id_, args_);
}
/*!
@@ -482,7 +571,7 @@ int QMetaCallEvent::placeMetaCall(QObject *object)
\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
@@ -572,7 +661,7 @@ int QMetaCallEvent::placeMetaCall(QObject *object)
\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
+ given in the \l{Using a Designer UI File in Your Application} section of
the \QD manual.
\section2 Dynamic Properties
@@ -660,12 +749,18 @@ QObject::QObject(QObject *parent)
: d_ptr(new QObjectPrivate)
{
Q_D(QObject);
- qt_addObject(d_ptr->q_ptr = this);
+ 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);
+ QT_TRY {
+ if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData))
+ parent = 0;
+ setParent(parent);
+ } QT_CATCH(...) {
+ d->threadData->deref();
+ QT_RETHROW;
+ }
+ qt_addObject(this);
}
#ifdef QT3_SUPPORT
@@ -695,20 +790,26 @@ QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
Q_D(QObject);
- qt_addObject(d_ptr->q_ptr = this);
+ 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);
+ QT_TRY {
+ 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);
}
- // no events sent here, this is done at the end of the QWidget constructor
- } else {
- setParent(parent);
+ } QT_CATCH(...) {
+ d->threadData->deref();
+ QT_RETHROW;
}
+ qt_addObject(this);
}
/*!
@@ -754,10 +855,47 @@ QObject::~QObject()
QObjectPrivate::clearGuards(this);
}
- emit destroyed(this);
+ if (d->sharedRefcount) {
+ if (d->sharedRefcount->strongref > 0) {
+ qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash.");
+ // but continue deleting, it's too late to stop anyway
+ }
+
+ // indicate to all QWeakPointers that this QObject has now been deleted
+ d->sharedRefcount->strongref = 0;
+ if (!d->sharedRefcount->weakref.deref())
+ delete d->sharedRefcount;
+ }
+
+ QT_TRY {
+ emit destroyed(this);
+ } QT_CATCH(...) {
+ // all the signal/slots connections are still in place - if we don't
+ // quit now, we will crash pretty soon.
+ qWarning("Detected an unexpected exception in ~QObject while emitting destroyed().");
+#if defined(Q_AUTOTEST_EXPORT) && !defined(QT_NO_EXCEPTIONS)
+ struct AutotestException : public std::exception
+ {
+ const char *what() const throw() { return "autotest swallow"; }
+ } autotestException;
+ // throw autotestException;
+
+#else
+ QT_RETHROW;
+#endif
+ }
+
+ if (d->declarativeData)
+ d->declarativeData->destroyed(this);
{
- QMutexLocker locker(&d->threadData->mutex);
+ QMutex *signalSlotMutex = 0;
+ QT_TRY {
+ signalSlotMutex = signalSlotLock(this);
+ } QT_CATCH(const std::bad_alloc &) {
+ // out of memory - swallow to prevent a crash
+ }
+ QMutexLocker locker(signalSlotMutex);
// set ref to zero to indicate that this object has been deleted
if (d->currentSender != 0)
@@ -768,25 +906,28 @@ QObject::~QObject()
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)
+ QObjectPrivate::ConnectionList &connectionList =
+ (*d->connectionLists)[signal];
+
+ while (QObjectPrivate::Connection *c = connectionList.first) {
+ if (!c->receiver) {
+ connectionList.first = c->nextConnectionList;
+ delete c;
continue;
+ }
- QMutex *m = &c->receiver->d_func()->threadData->mutex;
+ QMutex *m = signalSlotLock(c->receiver);
bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m);
- c = &connectionList[i];
- if (c->receiver)
- c->receiver->d_func()->derefSender(this, signal);
+
+ if (c->receiver) {
+ *c->prev = c->next;
+ if (c->next) c->next->prev = c->prev;
+ }
if (needToUnlock)
m->unlock();
- if (c->argumentTypes && c->argumentTypes != &DIRECT_CONNECTION_ONLY) {
- qFree(c->argumentTypes);
- c->argumentTypes = 0;
- }
- c->receiver = 0;
+ connectionList.first = c->nextConnectionList;
+ delete c;
}
}
@@ -799,25 +940,25 @@ QObject::~QObject()
}
// disconnect all senders
- for (int i = 0; i < d->senders.count(); ) {
- QObjectPrivate::Sender *s = &d->senders[i];
-
- QMutex *m = &s->sender->d_func()->threadData->mutex;
+ QObjectPrivate::Connection *node = d->senders;
+ while (node) {
+ QMutex *m = signalSlotLock(node->sender);
+ node->prev = &node;
bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m);
- if (m < locker.mutex()) {
- if (i >= d->senders.count() || s != &d->senders[i]) {
- if (needToUnlock)
- m->unlock();
- continue;
- }
+ //the node has maybe been removed while the mutex was unlocked in relock?
+ if (!node || signalSlotLock(node->sender) != m) {
+ m->unlock();
+ continue;
}
- s->sender->d_func()->removeReceiver(s->signal, this);
+ node->receiver = 0;
+ QObjectConnectionListVector *senderLists = node->sender->d_func()->connectionLists;
+ if (senderLists)
+ senderLists->dirty = true;
+
+ node = node->next;
if (needToUnlock)
m->unlock();
- ++i;
}
-
- d->senders.clear();
}
if (d->pendTimer) {
@@ -837,10 +978,7 @@ QObject::~QObject()
qt_removeObject(this);
- QMutexLocker locker2(&d->threadData->postEventList.mutex);
- if (d->postedEvents > 0)
- QCoreApplicationPrivate::removePostedEvents_unlocked(this, 0, d->threadData);
- locker2.unlock();
+ QCoreApplication::removePostedEvents(this);
if (d->parent) // remove it from parent object
d->setParent_helper(0);
@@ -853,9 +991,12 @@ QObject::~QObject()
objectName().isNull() ? "unnamed" : qPrintable(objectName()));
}
#endif
+}
- delete d;
- d_ptr = 0;
+QObjectPrivate::Connection::~Connection()
+{
+ if (argumentTypes != &DIRECT_CONNECTION_ONLY)
+ delete [] static_cast<int *>(argumentTypes);
}
@@ -950,10 +1091,9 @@ QObject::~QObject()
\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.
+ If you need to determine whether an object is an instance of a particular
+ class for the purpose of casting it, consider using qobject_cast<Type *>(object)
+ instead.
\sa metaObject(), qobject_cast()
*/
@@ -1031,7 +1171,7 @@ static QObject *qChildHelper(const char *objName, const char *inheritsClass,
more than one, the first one found is returned.
*/
QObject* QObject::child(const char *objName, const char *inheritsClass,
- bool recursiveSearch) const
+ bool recursiveSearch) const
{
Q_D(const QObject);
return qChildHelper(objName, inheritsClass, recursiveSearch, d->children);
@@ -1098,11 +1238,11 @@ bool QObject::event(QEvent *e)
#if defined(QT_NO_EXCEPTIONS)
mce->placeMetaCall(this);
#else
- try {
+ QT_TRY {
mce->placeMetaCall(this);
- } catch (...) {
+ } QT_CATCH(...) {
QObjectPrivate::resetCurrentSender(this, &currentSender, previousSender);
- throw;
+ QT_RETHROW;
}
#endif
QObjectPrivate::resetCurrentSender(this, &currentSender, previousSender);
@@ -1250,7 +1390,7 @@ bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */)
/*!
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.
+ If \a block is false, no such blocking will occur.
The return value is the previous value of signalsBlocked().
@@ -1395,8 +1535,10 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData
++eventsMoved;
}
}
- if (eventsMoved > 0 && targetData->eventDispatcher)
+ if (eventsMoved > 0 && targetData->eventDispatcher) {
+ targetData->canWait = false;
targetData->eventDispatcher->wakeUp();
+ }
// the current emitting thread shouldn't restore currentSender after calling moveToThread()
if (currentSender)
@@ -1540,12 +1682,12 @@ void QObject::killTimer(int id)
#ifdef QT3_SUPPORT
static void objSearch(QObjectList &result,
- const QObjectList &list,
- const char *inheritsClass,
- bool onlyWidgets,
- const char *objName,
- QRegExp *rx,
- bool recurse)
+ 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);
@@ -1615,9 +1757,9 @@ static void objSearch(QObjectList &result,
*/
QObjectList QObject::queryList(const char *inheritsClass,
- const char *objName,
- bool regexpMatch,
- bool recursiveSearch) const
+ const char *objName,
+ bool regexpMatch,
+ bool recursiveSearch) const
{
Q_D(const QObject);
QObjectList list;
@@ -1769,7 +1911,7 @@ QObjectList QObject::queryList(const char *inheritsClass,
\internal
*/
void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QRegExp *re,
- const QMetaObject &mo, QList<void*> *list)
+ const QMetaObject &mo, QList<void*> *list)
{
if (!parent || !list)
return;
@@ -2087,6 +2229,34 @@ void QObject::deleteLater()
\snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 17
+ \section1 Meta Data
+
+ Additional data can be attached to each translatable message.
+ The syntax:
+
+ \tt{//= <id>}
+
+ can be used to give the message a unique identifier to support tools
+ which need it.
+ The syntax:
+
+ \tt{//~ <field name> <field contents>}
+
+ can be used to attach meta data to the message. The field name should consist
+ of a domain prefix (possibly the conventional file extension of the file format
+ the field is inspired by), a hyphen and the actual field name in
+ underscore-delimited notation. For storage in TS files, the field name together
+ with the prefix "extra-" will form an XML element name. The field contents will
+ be XML-escaped, but otherwise appear verbatim as the element's contents.
+ Any number of unique fields can be added to each message.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp meta data
+
+ Meta data appearing right in front of a magic TRANSLATOR comment applies to the
+ whole TS file.
+
\section1 Character Encodings
You can set the encoding for \a sourceText by calling QTextCodec::setCodecForTr().
@@ -2243,11 +2413,11 @@ static void err_method_notfound(const QObject *object,
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");
+ loc ? " in ": "", loc ? loc : "");
else
qWarning("Object::%s: No such %s %s::%s%s%s",
func, type, object->metaObject()->className(), method+1,
- loc ? " in ":"\0", loc ? loc : "\0");
+ loc ? " in ": "", loc ? loc : "");
}
@@ -2290,14 +2460,14 @@ QObject *QObject::sender() const
{
Q_D(const QObject);
- QMutexLocker(&d->threadData->mutex);
+ QMutexLocker locker(signalSlotLock(this));
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);
+ for (QObjectPrivate::Connection *c = d->senders; c && !found; c = c->next)
+ found = (c->sender == d->currentSender->sender);
if (!found)
return 0;
return d->currentSender->sender;
@@ -2327,6 +2497,7 @@ QObject *QObject::sender() const
int QObject::receivers(const char *signal) const
{
+ Q_D(const QObject);
int receivers = 0;
if (signal) {
QByteArray signal_name = QMetaObject::normalizedSignature(signal);
@@ -2336,8 +2507,7 @@ int QObject::receivers(const char *signal) const
return 0;
#endif
signal++; // skip code
- const QMetaObject *smeta = this->metaObject();
- int signal_index = smeta->indexOfSignal(signal);
+ int signal_index = d->signalIndex(signal);
if (signal_index < 0) {
#ifndef QT_NO_DEBUG
err_method_notfound(this, signal-1, "receivers");
@@ -2346,14 +2516,14 @@ int QObject::receivers(const char *signal) const
}
Q_D(const QObject);
- QMutexLocker locker(&d->threadData->mutex);
+ QMutexLocker locker(signalSlotLock(this));
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;
+ const QObjectPrivate::Connection *c =
+ d->connectionLists->at(signal_index).first;
+ while (c) {
+ receivers += c->receiver ? 1 : 0;
+ c = c->nextConnectionList;
}
}
}
@@ -2392,7 +2562,8 @@ int QObject::receivers(const char *signal) const
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.
+ in the same order as the order the connection was made, 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
@@ -2400,9 +2571,13 @@ int QObject::receivers(const char *signal) const
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.
+ By default, a signal is emitted for every connection you make;
+ two signals are emitted for duplicate connections. You can break
+ all of these connections with a single disconnect() call.
+ If you pass the Qt::UniqueConnection \a type, the connection will only
+ be made if it is not a duplicate. If there is already a duplicate
+ (exact same signal to the exact same slot on the same objects),
+ the connection will fail and connect will return false
The optional \a type parameter describes the type of connection
to establish. In particular, it determines whether a particular
@@ -2456,19 +2631,26 @@ bool QObject::connect(const QObject *sender, const char *signal,
const QMetaObject *smeta = sender->metaObject();
const char *signal_arg = signal;
++signal; //skip code
- int signal_index = smeta->indexOfSignal(signal);
+ int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, 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);
+ smeta = sender->metaObject();
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal);
+
if (signal_index < 0) {
err_method_notfound(sender, signal_arg, "connect");
err_info_about_objects("connect", sender, receiver);
return false;
}
}
+ signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
+ int signalOffset, methodOffset;
+ computeOffsets(smeta, &signalOffset, &methodOffset);
+ int signal_absolute_index = signal_index + methodOffset;
+ signal_index += signalOffset;
QByteArray tmp_method_name;
int membcode = extract_code(method);
@@ -2517,12 +2699,12 @@ bool QObject::connect(const QObject *sender, const char *signal,
int *types = 0;
if ((type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
- && !(types = queuedConnectionTypes(smeta->method(signal_index).parameterTypes())))
+ && !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes())))
return false;
#ifndef QT_NO_DEBUG
{
- QMetaMethod smethod = smeta->method(signal_index);
+ QMetaMethod smethod = smeta->method(signal_absolute_index);
QMetaMethod rmethod = rmeta->method(method_index);
if (warnCompat) {
if(smethod.attributes() & QMetaMethod::Compatibility) {
@@ -2535,7 +2717,8 @@ bool QObject::connect(const QObject *sender, const char *signal,
}
}
#endif
- QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
+ if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, type, types))
+ return false;
const_cast<QObject*>(sender)->connectNotify(signal - 1);
return true;
}
@@ -2635,8 +2818,14 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
QByteArray signal_name;
bool signal_found = false;
if (signal) {
- signal_name = QMetaObject::normalizedSignature(signal);
- signal = signal_name;
+ QT_TRY {
+ signal_name = QMetaObject::normalizedSignature(signal);
+ signal = signal_name.constData();
+ } QT_CATCH (const std::bad_alloc &) {
+ // if the signal is already normalized, we can continue.
+ if (sender->metaObject()->indexOfSignal(signal + 1) == -1)
+ QT_RETHROW;
+ }
if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
return false;
@@ -2648,8 +2837,15 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
int membcode = -1;
bool method_found = false;
if (method) {
- method_name = QMetaObject::normalizedSignature(method);
- method = method_name;
+ QT_TRY {
+ method_name = QMetaObject::normalizedSignature(method);
+ method = method_name.constData();
+ } QT_CATCH(const std::bad_alloc &) {
+ // if the method is already normalized, we can continue.
+ if (receiver->metaObject()->indexOfMethod(method + 1) == -1)
+ QT_RETHROW;
+ }
+
membcode = extract_code(method);
if (!check_method_code(membcode, receiver, method, "disconnect"))
return false;
@@ -2665,14 +2861,18 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
do {
int signal_index = -1;
if (signal) {
- signal_index = smeta->indexOfSignal(signal);
- if (signal_index < smeta->methodOffset())
- continue;
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal);
+ if (signal_index < 0)
+ break;
+ signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
+ int signalOffset, methodOffset;
+ computeOffsets(smeta, &signalOffset, &methodOffset);
+ signal_index += signalOffset;
signal_found = true;
}
if (!method) {
- res |= QMetaObject::disconnect(sender, signal_index, receiver, -1);
+ res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, -1);
} else {
const QMetaObject *rmeta = receiver->metaObject();
do {
@@ -2682,7 +2882,7 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
rmeta = rmeta->superClass();
if (method_index < 0)
break;
- res |= QMetaObject::disconnect(sender, signal_index, receiver, method_index);
+ res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index);
method_found = true;
} while ((rmeta = rmeta->superClass()));
}
@@ -2773,38 +2973,87 @@ void QObject::disconnectNotify(const char *)
}
/*!\internal
+ \a types is a 0-terminated vector of meta types for queued
+ connections.
- \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
-*/
+ 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)
{
+ if (signal_index > 0) {
+ const QMetaObject *mo = sender->metaObject();
+ while (mo && mo->methodOffset() > signal_index)
+ mo = mo->superClass();
+ if (mo) {
+ int signalOffset, methodOffset;
+ computeOffsets(mo, &signalOffset, &methodOffset);
+ signal_index = QMetaObjectPrivate::originalClone(mo, signal_index - methodOffset) + signalOffset;
+ }
+ }
+ return QMetaObjectPrivate::connect(sender, signal_index,
+ receiver, method_index, type, types);
+}
+
+/*! \internal
+ Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex
+ */
+bool QMetaObjectPrivate::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);
+ QOrderedMutexLocker locker(signalSlotLock(sender),
+ signalSlotLock(receiver));
-#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 (type & Qt::UniqueConnection) {
+ QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
+ if (connectionLists && connectionLists->count() > signal_index) {
+ const QObjectPrivate::Connection *c2 =
+ (*connectionLists)[signal_index].first;
- if (signal_index < 0)
- sender->d_func()->connectedSignals = ~0u;
- else if (signal_index < 32)
- sender->d_func()->connectedSignals |= (1 << signal_index);
+ while (c2) {
+ if (c2->receiver == receiver && c2->method == method_index)
+ return false;
+ c2 = c2->nextConnectionList;
+ }
+ }
+ type &= Qt::UniqueConnection - 1;
+ }
+
+ QObjectPrivate::Connection *c = new QObjectPrivate::Connection;
+ c->sender = s;
+ c->receiver = r;
+ c->method = method_index;
+ c->connectionType = type;
+ c->argumentTypes = types;
+ c->nextConnectionList = 0;
+
+ QT_TRY {
+ QObjectPrivate::get(s)->addConnection(signal_index, c);
+ } QT_CATCH(...) {
+ delete c;
+ QT_RETHROW;
+ }
+
+ c->prev = &(QObjectPrivate::get(r)->senders);
+ c->next = *c->prev;
+ *c->prev = c;
+ if (c->next)
+ c->next->prev = &c->next;
+
+ QObjectPrivate *const sender_d = QObjectPrivate::get(s);
+ if (signal_index < 0) {
+ for (uint i = 0; i < (sizeof sender_d->connectedSignals
+ / sizeof sender_d->connectedSignals[0] ); ++i)
+ sender_d->connectedSignals[i] = ~0u;
+ } else if (signal_index < (int)sizeof sender_d->connectedSignals * 8) {
+ uint n = (signal_index / (8 * sizeof sender_d->connectedSignals[0]));
+ sender_d->connectedSignals[n] |= (1 << (signal_index - n * 8
+ * sizeof sender_d->connectedSignals[0]));
+ }
return true;
}
@@ -2815,17 +3064,73 @@ bool QMetaObject::connect(const QObject *sender, int signal_index,
bool QMetaObject::disconnect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index)
{
+ if (signal_index > 0) {
+ const QMetaObject *mo = sender->metaObject();
+ while (mo && mo->methodOffset() > signal_index)
+ mo = mo->superClass();
+ if (mo) {
+ int signalOffset, methodOffset;
+ computeOffsets(mo, &signalOffset, &methodOffset);
+ signal_index = QMetaObjectPrivate::originalClone(mo, signal_index - methodOffset) + signalOffset;
+ }
+ }
+ return QMetaObjectPrivate::disconnect(sender, signal_index,
+ receiver, method_index);
+}
+
+/*! \internal
+ Helper function to remove the connection from the senders list and setting the receivers to 0
+ */
+bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c,
+ const QObject *receiver, int method_index,
+ QMutex *senderMutex)
+{
+ bool success = false;
+ while (c) {
+ if (c->receiver
+ && (receiver == 0 || (c->receiver == receiver
+ && (method_index < 0 || c->method == method_index)))) {
+ bool needToUnlock = false;
+ QMutex *receiverMutex = 0;
+ if (!receiver) {
+ receiverMutex = signalSlotLock(c->receiver);
+ // need to relock this receiver and sender in the correct order
+ needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex);
+ }
+ if (c->receiver) {
+ *c->prev = c->next;
+ if (c->next)
+ c->next->prev = c->prev;
+ }
+
+ if (needToUnlock)
+ receiverMutex->unlock();
+
+ c->receiver = 0;
+
+ success = true;
+ }
+ c = c->nextConnectionList;
+ }
+ return success;
+}
+
+/*! \internal
+ Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex
+ */
+bool QMetaObjectPrivate::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;
+ QMutex *senderMutex = signalSlotLock(sender);
+ QMutex *receiverMutex = receiver ? signalSlotLock(receiver) : 0;
QOrderedMutexLocker locker(senderMutex, receiverMutex);
- QObjectConnectionListVector *connectionLists = s->d_func()->connectionLists;
+ QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
if (!connectionLists)
return false;
@@ -2836,66 +3141,20 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index,
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;
-
+ QObjectPrivate::Connection *c =
+ (*connectionLists)[signal_index].first;
+ if (disconnectHelper(c, receiver, method_index, senderMutex)) {
success = true;
connectionLists->dirty = true;
}
}
+ } else if (signal_index < connectionLists->count()) {
+ QObjectPrivate::Connection *c =
+ (*connectionLists)[signal_index].first;
+ if (disconnectHelper(c, receiver, method_index, senderMutex)) {
+ success = true;
+ connectionLists->dirty = true;
+ }
}
--connectionLists->inUse;
@@ -2941,23 +3200,26 @@ void QMetaObject::connectSlotsByName(QObject *o)
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);
+ int sigIndex = co->d_func()->signalIndex(slot + len + 4);
if (sigIndex < 0) { // search for compatible signals
+ const QMetaObject *smo = co->metaObject();
int slotlen = qstrlen(slot + len + 4) - 1;
for (int k = 0; k < co->metaObject()->methodCount(); ++k) {
- if (smo->method(k).methodType() != QMetaMethod::Signal)
+ QMetaMethod method = smo->method(k);
+ if (method.methodType() != QMetaMethod::Signal)
continue;
- if (!qstrncmp(smo->method(k).signature(), slot + len + 4, slotlen)) {
- sigIndex = k;
+ if (!qstrncmp(method.signature(), slot + len + 4, slotlen)) {
+ int signalOffset, methodOffset;
+ computeOffsets(method.enclosingMetaObject(), &signalOffset, &methodOffset);
+ sigIndex = k + - methodOffset + signalOffset;
break;
}
}
}
if (sigIndex < 0)
continue;
- if (QMetaObject::connect(co, sigIndex, o, i)) {
+ if (QMetaObjectPrivate::connect(co, sigIndex, o, i)) {
foundIt = true;
break;
}
@@ -2972,32 +3234,33 @@ void QMetaObject::connectSlotsByName(QObject *o)
}
}
-static void queued_activate(QObject *sender, int signal, const QObjectPrivate::Connection &c,
+static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c,
void **argv, QSemaphore *semaphore = 0)
{
- if (!c.argumentTypes || c.argumentTypes != &DIRECT_CONNECTION_ONLY) {
+ 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 (!c->argumentTypes.testAndSetOrdered(0, tmp)) {
if (tmp != &DIRECT_CONNECTION_ONLY)
- qFree(tmp);
+ delete [] tmp;
}
}
- if (c.argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
+ if (c->argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
return;
int nargs = 1; // include return type
- while (c.argumentTypes[nargs-1])
+ while (c->argumentTypes[nargs-1])
++nargs;
int *types = (int *) qMalloc(nargs*sizeof(int));
+ Q_CHECK_PTR(types);
void **args = (void **) qMalloc(nargs*sizeof(void *));
+ Q_CHECK_PTR(args);
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,
+ args[n] = QMetaType::construct((types[n] = c->argumentTypes[n-1]), argv[n]);
+ QCoreApplication::postEvent(c->receiver, new QMetaCallEvent(c->method,
sender,
signal,
nargs,
@@ -3006,13 +3269,13 @@ static void queued_activate(QObject *sender, int signal, const QObjectPrivate::C
semaphore));
}
-static void blocking_activate(QObject *sender, int signal, const QObjectPrivate::Connection &c, void **argv)
+static void blocking_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
{
- if (QThread::currentThread() == c.receiver->thread()) {
+ 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);
+ c->receiver->metaObject()->className(), c->receiver);
}
#ifdef QT_NO_THREAD
@@ -3020,7 +3283,7 @@ static void blocking_activate(QObject *sender, int signal, const QObjectPrivate:
#else
QSemaphore semaphore;
queued_activate(sender, signal, c, argv, &semaphore);
- QMutex *mutex = &QThreadData::get2(sender->thread())->mutex;
+ QMutex *mutex = signalSlotLock(sender);
mutex->unlock();
semaphore.acquire();
mutex->lock();
@@ -3028,41 +3291,68 @@ static void blocking_activate(QObject *sender, int signal, const QObjectPrivate:
}
/*!\internal
+ \obsolete.
+ Used to be called from QMetaObject::activate(QObject *, QMetaObject *, int, int, void **) before Qt 4.6
*/
void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv)
{
+ Q_UNUSED(to_signal_index);
+ activate(sender, from_signal_index, argv);
+}
+
+/*!\internal
+ */
+void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
+ void **argv)
+{
+ int signalOffset;
+ int methodOffset;
+ computeOffsets(m, &signalOffset, &methodOffset);
+
+ int signal_index = signalOffset + local_signal_index;
+ if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8
+ && !qt_signal_spy_callback_set.signal_begin_callback
+ && !qt_signal_spy_callback_set.signal_end_callback) {
+ uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ if ((sender->d_func()->connectedSignals[n] & m) == 0)
+ // nothing connected to these signals, and no spy
+ return;
+ }
+
if (sender->d_func()->blockSig)
return;
+ int signal_absolute_index = methodOffset + local_signal_index;
+
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,
+ qt_signal_spy_callback_set.signal_begin_callback(sender, signal_absolute_index,
argv ? argv : empty_argv);
}
- QMutexLocker locker(&sender->d_func()->threadData->mutex);
+ QMutexLocker locker(signalSlotLock(sender));
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);
+ qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index);
return;
}
++connectionLists->inUse;
+ if (signal_index >= connectionLists->count()) {
+ signal_index = -2; //for "all signals";
+ }
- // 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];
+ do {
+ QObjectPrivate::Connection *c = connectionLists->at(signal_index).first;
+ if (!c) continue;
+ // We need to check against last here to ensure that signals added
+ // during the signal emission are not emitted in this emission.
+ QObjectPrivate::Connection *last = connectionLists->at(signal_index).last;
+
+ do {
if (!c->receiver)
continue;
@@ -3074,17 +3364,17 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal
&& (currentThreadData != sender->d_func()->threadData
|| receiver->d_func()->threadData != sender->d_func()->threadData))
|| (c->connectionType == Qt::QueuedConnection)) {
- queued_activate(sender, signal, *c, argv);
+ queued_activate(sender, signal_absolute_index, c, argv);
continue;
} else if (c->connectionType == Qt::BlockingQueuedConnection) {
- blocking_activate(sender, signal, *c, argv);
+ blocking_activate(sender, signal_absolute_index, c, argv);
continue;
}
const int method = c->method;
QObjectPrivate::Sender currentSender;
currentSender.sender = sender;
- currentSender.signal = signal < 0 ? from_signal_index : signal;
+ currentSender.signal = signal_absolute_index;
currentSender.ref = 1;
QObjectPrivate::Sender *previousSender = 0;
if (currentThreadData == receiver->d_func()->threadData)
@@ -3098,11 +3388,11 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal
}
#if defined(QT_NO_EXCEPTIONS)
- receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
+ metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
#else
- try {
- receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
- } catch (...) {
+ QT_TRY {
+ metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
+ } QT_CATCH(...) {
locker.relock();
QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
@@ -3111,7 +3401,7 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal
Q_ASSERT(connectionLists->inUse >= 0);
if (connectionLists->orphaned && !connectionLists->inUse)
delete connectionLists;
- throw;
+ QT_RETHROW;
}
#endif
@@ -3124,11 +3414,11 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal
if (connectionLists->orphaned)
break;
- }
+ } while (c != last && (c = c->nextConnectionList) != 0);
if (connectionLists->orphaned)
break;
- }
+ } while (signal_index >= 0 && (signal_index = -1)); //start over for -1 (all signal)
--connectionLists->inUse;
Q_ASSERT(connectionLists->inUse >= 0);
@@ -3142,63 +3432,74 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal
locker.unlock();
if (qt_signal_spy_callback_set.signal_end_callback != 0)
- qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);
-}
+ qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index);
+}
/*!\internal
- */
+ Obsolete. (signal_index comes from indexOfMethod())
+*/
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);
+ const QMetaObject *mo = sender->metaObject();
+ while (mo && mo->methodOffset() > signal_index)
+ mo = mo->superClass();
+ activate(sender, mo, signal_index - mo->methodOffset(), argv);
}
/*!\internal
+ Obsolete, called by moc generated code before Qt 4.6 for cloned signals
+ But since Qt 4.6, all clones are connected to their original
*/
-void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
- void **argv)
+void QMetaObject::activate(QObject *sender, const QMetaObject *m,
+ int from_local_signal_index, int to_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);
+ Q_UNUSED(to_local_signal_index);
+ Q_ASSERT(from_local_signal_index == QMetaObjectPrivate::originalClone(m, to_local_signal_index));
+ activate(sender, m, from_local_signal_index, argv);
}
-/*!\internal
- */
-void QMetaObject::activate(QObject *sender, const QMetaObject *m,
- int from_local_signal_index, int to_local_signal_index, void **argv)
+/*! \internal
+ Returns the signal index used in the internal connectionLists vector.
+
+ It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod
+ while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots.
+*/
+int QObjectPrivate::signalIndex(const char *signalName) const
+{
+ Q_Q(const QObject);
+ const QMetaObject *base = q->metaObject();
+ int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName);
+ if (relative_index < 0)
+ return relative_index;
+ relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
+ int signalOffset, methodOffset;
+ computeOffsets(base, &signalOffset, &methodOffset);
+ return relative_index + signalOffset;
+}
+
+/*! \internal
+
+ Returns true if the signal with index \a signal_index from object \a sender is connected.
+ Signals with indices above a certain range are always considered connected (see connectedSignals
+ in QObjectPrivate). If a signal spy is installed, all signals are considered connected.
+
+ \a signal_index must be the index returned by QObjectPrivate::signalIndex;
+*/
+bool QObjectPrivate::isSignalConnected(int signal_index) const
{
- 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
+ if (signal_index < (int)sizeof(connectedSignals) * 8
&& !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)
+ uint n = (signal_index / (8 * sizeof connectedSignals[0]));
+ uint m = 1 << (signal_index - n * 8 * sizeof connectedSignals[0]);
+ if ((connectedSignals[n] & m) == 0)
// nothing connected to these signals, and no spy
- return;
+ return false;
}
- activate(sender, from_signal_index, to_signal_index, argv);
+ return true;
}
-
/*****************************************************************************
Properties
*****************************************************************************/
@@ -3392,30 +3693,45 @@ void QObject::dumpObjectInfo()
objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
Q_D(QObject);
- QMutexLocker locker(&d->threadData->mutex);
+ QMutexLocker locker(signalSlotLock(this));
// first, look for connections where this object is the sender
qDebug(" SIGNALS OUT");
if (d->connectionLists) {
+ int offset = 0;
+ int offsetToNextMetaObject = 0;
for (int signal_index = 0; signal_index < d->connectionLists->count(); ++signal_index) {
- const QMetaMethod signal = metaObject()->method(signal_index);
+ if (signal_index >= offsetToNextMetaObject) {
+ const QMetaObject *mo = metaObject();
+ int signalOffset, methodOffset;
+ computeOffsets(mo, &signalOffset, &methodOffset);
+ while (mo && signalOffset > signal_index) {
+ mo = mo->superClass();
+ offsetToNextMetaObject = signalOffset;
+ computeOffsets(mo, &signalOffset, &methodOffset);
+ }
+ offset = offset - signalOffset + methodOffset;
+ }
+ const QMetaMethod signal = metaObject()->method(signal_index + offset);
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) {
+ const QObjectPrivate::Connection *c =
+ d->connectionLists->at(signal_index).first;
+ while (c) {
+ if (!c->receiver) {
qDebug(" <Disconnected receiver>");
+ c = c->nextConnectionList;
continue;
}
- const QMetaObject *receiverMetaObject = c.receiver->metaObject();
- const QMetaMethod method = receiverMetaObject->method(c.method);
+ 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()),
+ c->receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver->objectName()),
method.signature());
+ c = c->nextConnectionList;
}
}
} else {
@@ -3425,18 +3741,16 @@ void QObject::dumpObjectInfo()
// 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());
+ if (d->senders) {
+ for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) {
+ const QMetaMethod slot = metaObject()->method(s->method);
+ qDebug(" <-- %s::%s %s",
+ s->sender->metaObject()->className(),
+ s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
+ slot.signature());
}
} else {
- qDebug(" <None>");
+ qDebug(" <None>");
}
#endif
}
@@ -3489,7 +3803,7 @@ 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;
+ dbg.nospace() << o->metaObject()->className() << '(' << (void *)o;
if (!o->objectName().isEmpty())
dbg << ", name = " << o->objectName();
dbg << ')';
@@ -3789,23 +4103,17 @@ QDebug operator<<(QDebug dbg, const QObject *o) {
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;
+ QObjectPrivate::get(o)->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
index 81412a7..7c2004c 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -51,6 +51,7 @@
#ifdef QT_INCLUDE_COMPAT
#include <QtCore/qcoreevent.h>
#endif
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_HEADER
@@ -106,8 +107,10 @@ public:
uint receiveChildEvents : 1;
uint inEventHandler : 1;
uint inThreadChangeEvent : 1;
- uint unused : 23;
+ uint hasGuards : 1; //true iff there is one or more QPointer attached to this object
+ uint unused : 22;
int postedEvents;
+ QMetaObject *metaObject; // assert dynamic
};
@@ -286,7 +289,7 @@ protected:
QObject(QObjectPrivate &dd, QObject *parent = 0);
protected:
- QObjectData *d_ptr;
+ QScopedPointer<QObjectData> d_ptr;
static const QMetaObject staticQtMetaObject;
@@ -378,6 +381,9 @@ inline QList<T> qFindChildren(const QObject *o, const QRegExp &re)
#endif // Q_MOC_RUN
+template <class T> inline const char * qobject_interface_iid()
+{ return 0; }
+
template <class T> inline T qobject_cast_helper(QObject *object, T)
{ return static_cast<T>(((T)0)->staticMetaObject.cast(object)); }
@@ -394,6 +400,8 @@ inline T qobject_cast(const QObject *object)
#ifndef Q_MOC_RUN
# define Q_DECLARE_INTERFACE(IFace, IId) \
+ template <> inline const char *qobject_interface_iid<IFace *>() \
+ { return 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 *) \
@@ -457,8 +465,13 @@ inline T qobject_cast(const QObject *object)
}
+template <class T> inline const char * qobject_interface_iid()
+{ return 0; }
+
#ifndef Q_MOC_RUN
# define Q_DECLARE_INTERFACE(IFace, IId) \
+ template <> inline const char *qobject_interface_iid<IFace *>() \
+ { return 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) \
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 5df7186..30a8fe9 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -60,12 +60,14 @@
#include "QtCore/qvector.h"
#include "QtCore/qreadwritelock.h"
#include "QtCore/qvariant.h"
+#include "private/qguard_p.h"
QT_BEGIN_NAMESPACE
class QVariant;
class QThreadData;
class QObjectConnectionListVector;
+namespace QtSharedPointer { struct ExternalRefCountData; }
/* mirrored in QtTestLib, DON'T CHANGE without prior warning */
struct QSignalSpyCallbackSet
@@ -81,57 +83,20 @@ void Q_CORE_EXPORT qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet
extern QSignalSpyCallbackSet Q_CORE_EXPORT qt_signal_spy_callback_set;
-inline QObjectData::~QObjectData() {}
-
enum { QObjectPrivateVersion = QT_VERSION };
+class Q_CORE_EXPORT QDeclarativeData
+{
+public:
+ virtual ~QDeclarativeData();
+ virtual void destroyed(QObject *) = 0;
+};
+
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
@@ -140,29 +105,56 @@ public:
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 *sender;
QObject *receiver;
int method;
uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
QBasicAtomicPointer<int> argumentTypes;
+ // The next pointer for the singly-linked ConnectionList
+ Connection *nextConnectionList;
+ //senders linked list
+ Connection *next;
+ Connection **prev;
+ ~Connection();
+ };
+ // ConnectionList is a singly-linked list
+ struct ConnectionList {
+ ConnectionList() : first(0), last(0) {}
+ Connection *first;
+ Connection *last;
};
- typedef QList<Connection> ConnectionList;
- QObjectConnectionListVector *connectionLists;
+ struct Sender
+ {
+ QObject *sender;
+ int signal;
+ int ref;
+ };
+
+
+ QObjectPrivate(int version = QObjectPrivateVersion);
+ virtual ~QObjectPrivate();
+ void deleteChildren();
+
+ void setParent_helper(QObject *);
+ void moveToThread_helper();
+ void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
+ void _q_reregisterTimers(void *pointer);
+
+ bool isSender(const QObject *receiver, const char *signal) const;
+ QObjectList receiverList(const char *signal) const;
+ QObjectList senderList() const;
+
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);
+#ifdef QT3_SUPPORT
+ void sendPendingChildInsertedEvents();
+ void removePendingChildInsertedEvents(QObject *child);
+#endif
static Sender *setCurrentSender(QObject *receiver,
Sender *sender);
@@ -171,14 +163,69 @@ public:
Sender *previousSender);
static int *setDeleteWatch(QObjectPrivate *d, int *newWatch);
static void resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch);
-
- int *deleteWatch;
+ static void clearGuards(QObject *);
static QObjectPrivate *get(QObject *o) {
return o->d_func();
}
+
+ int signalIndex(const char *signalName) const;
+ bool isSignalConnected(int signalIdx) const;
+
+public:
+ QString objectName;
+ ExtraData *extraData; // extra data set by the user
+ QThreadData *threadData; // id of the thread that owns the object
+
+ QObjectConnectionListVector *connectionLists;
+
+ Connection *senders; // linked list of connections connected to this object
+ Sender *currentSender; // object currently activating the object
+ mutable quint32 connectedSignals[2]; // 64-bit, so doesn't cause padding on 64-bit platforms
+
+#ifdef QT3_SUPPORT
+ QList<QObject *> pendingChildInsertedEvents;
+#else
+ // preserve binary compatibility with code compiled without Qt 3 support
+ // ### why?
+ QList<QObject *> unused;
+#endif
+
+ QList<QPointer<QObject> > eventFilters;
+ QObject *currentChildBeingDeleted;
+
+ // these objects are all used to indicate that a QObject was deleted
+ // plus QPointer, which keeps a separate list
+ QDeclarativeData *declarativeData;
+ QGuard<QObject> *objectGuards;
+ QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
+ int *deleteWatch;
};
+inline void q_guard_addGuard(QGuard<QObject> *g)
+{
+ QObjectPrivate *p = QObjectPrivate::get(g->o);
+ if (p->wasDeleted) {
+ qWarning("QGuard: cannot add guard to deleted object");
+ g->o = 0;
+ return;
+ }
+
+ g->next = p->objectGuards;
+ p->objectGuards = g;
+ g->prev = &p->objectGuards;
+ if (g->next)
+ g->next->prev = &g->next;
+}
+
+inline void q_guard_removeGuard(QGuard<QObject> *g)
+{
+ if (g->next) g->next->prev = g->prev;
+ *g->prev = g->next;
+ g->next = 0;
+ g->prev = 0;
+}
+
Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE);
@@ -207,7 +254,7 @@ private:
QSemaphore *semaphore_;
};
-class Q_CORE_EXPORT QBoolBlocker
+class QBoolBlocker
{
public:
inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;}
@@ -219,6 +266,14 @@ private:
void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
+
+struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QMetaObject
+{
+ virtual ~QAbstractDynamicMetaObject() {}
+ virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; }
+ virtual int createProperty(const char *, const char *) { return -1; }
+};
+
QT_END_NAMESPACE
#endif // QOBJECT_P_H
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 27ef5b3..baeb42e 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -55,7 +55,7 @@ class QByteArray;
class QString;
#ifndef Q_MOC_OUTPUT_REVISION
-#define Q_MOC_OUTPUT_REVISION 61
+#define Q_MOC_OUTPUT_REVISION 62
#endif
// The following macros are our "extensions" to C++
@@ -150,6 +150,7 @@ inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {}
public: \
Q_OBJECT_CHECK \
static const QMetaObject staticMetaObject; \
+ static const QMetaObject &getStaticMetaObject(); \
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
QT_TR_FUNCTIONS \
@@ -161,6 +162,7 @@ private:
#define Q_GADGET \
public: \
static const QMetaObject staticMetaObject; \
+ static const QMetaObject &getStaticMetaObject(); \
private:
#else // Q_MOC_RUN
#define slots slots
@@ -330,10 +332,11 @@ struct Q_CORE_EXPORT QMetaObject
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, int signal_index, void **argv); //obsolete
+ static void activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv); //obsolete
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);
+ static void activate(QObject *sender, const QMetaObject *, int from_local_signal_index, int to_local_signal_index, void **argv); //obsolete
+
// internal guarded pointers
static void addGuard(QObject **ptr);
static void removeGuard(QObject **ptr);
@@ -428,6 +431,7 @@ struct Q_CORE_EXPORT QMetaObject
};
int static_metacall(Call, int, void **) const;
+ static int metacall(QObject *, Call, int, void **);
#ifdef QT3_SUPPORT
QT3_SUPPORT const char *superClassName() const;
@@ -439,11 +443,18 @@ struct Q_CORE_EXPORT QMetaObject
const uint *data;
const void *extradata;
} d;
+
};
+typedef const QMetaObject& (*QMetaObjectAccessor)();
+
struct QMetaObjectExtraData
{
+#ifdef Q_NO_DATA_RELOCATION
+ const QMetaObjectAccessor *objects;
+#else
const QMetaObject **objects;
+#endif
int (*static_metacall)(QMetaObject::Call, int, void **);
};
diff --git a/src/corelib/kernel/qpointer.cpp b/src/corelib/kernel/qpointer.cpp
index e53849b..040d186 100644
--- a/src/corelib/kernel/qpointer.cpp
+++ b/src/corelib/kernel/qpointer.cpp
@@ -44,7 +44,7 @@
\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
diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp
index d58b440..5c78f82 100644
--- a/src/corelib/kernel/qsharedmemory.cpp
+++ b/src/corelib/kernel/qsharedmemory.cpp
@@ -44,7 +44,9 @@
#include "qsystemsemaphore.h"
#include <qdir.h>
#include <qcryptographichash.h>
-
+#ifdef Q_OS_SYMBIAN
+#include <e32const.h>
+#endif
#include <qdebug.h>
QT_BEGIN_NAMESPACE
@@ -57,6 +59,7 @@ QT_BEGIN_NAMESPACE
the subset that the win/unix kernel allows.
On Unix this will be a file name
+ On Symbian key will be truncated to 80 characters
*/
QString
QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
@@ -70,10 +73,12 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
QString part1 = key;
part1.replace(QRegExp(QLatin1String("[^A-Za-z]")), QString());
result.append(part1);
+#ifdef Q_OS_SYMBIAN
+ return result.left(KMaxKernelName);
+#endif
QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
result.append(QLatin1String(hex));
-
#ifdef Q_OS_WIN
return result;
#else
@@ -86,7 +91,6 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
/*!
\class QSharedMemory
- \ingroup ipc
\since 4.4
\brief The QSharedMemory class provides access to a shared memory segment.
@@ -118,6 +122,14 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
process. This means that QSharedMemory should not be used across
multiple threads in the same process in HP-UX.
+ \o Symbian: 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 Symbian kernel
+ releases the shared memory segment automatically.
+ Also, access to a shared memory segment cannot be limited to read-only
+ in Symbian.
+
\endlist
Remember to lock the shared memory with lock() before reading from
diff --git a/src/corelib/kernel/qsharedmemory_p.h b/src/corelib/kernel/qsharedmemory_p.h
index 7cf62ed..5becca8 100644
--- a/src/corelib/kernel/qsharedmemory_p.h
+++ b/src/corelib/kernel/qsharedmemory_p.h
@@ -71,6 +71,9 @@ namespace QSharedMemoryPrivate
#ifdef Q_OS_WIN
#include <qt_windows.h>
+#elif defined(Q_OS_SYMBIAN)
+#include <e32std.h>
+#include <sys/types.h>
#else
#include <sys/sem.h>
#endif
@@ -140,7 +143,11 @@ public:
bool attach(QSharedMemory::AccessMode mode);
bool detach();
+#ifdef Q_OS_SYMBIAN
+ void setErrorString(const QString &function, TInt errorCode);
+#else
void setErrorString(const QString &function);
+#endif
#ifndef QT_NO_SYSTEMSEMAPHORE
bool tryLocker(QSharedMemoryLocker *locker, const QString function) {
@@ -156,6 +163,8 @@ public:
private:
#ifdef Q_OS_WIN
HANDLE hand;
+#elif defined(Q_OS_SYMBIAN)
+ RChunk chunk;
#else
key_t unix_key;
#endif
diff --git a/src/corelib/kernel/qsharedmemory_symbian.cpp b/src/corelib/kernel/qsharedmemory_symbian.cpp
new file mode 100644
index 0000000..fee6293
--- /dev/null
+++ b/src/corelib/kernel/qsharedmemory_symbian.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsharedmemory.h"
+#include "qsharedmemory_p.h"
+#include "qsystemsemaphore.h"
+#include "qcore_symbian_p.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_SHAREDMEMORY
+
+#define QSHAREDMEMORY_DEBUG
+
+QSharedMemoryPrivate::QSharedMemoryPrivate() : QObjectPrivate(),
+ memory(0), size(0), error(QSharedMemory::NoError),
+ systemSemaphore(QString()), lockedByMe(false)
+{
+}
+
+void QSharedMemoryPrivate::setErrorString(const QString &function, TInt errorCode)
+{
+ if (errorCode == KErrNone)
+ return;
+ switch (errorCode) {
+ case KErrAlreadyExists:
+ error = QSharedMemory::AlreadyExists;
+ errorString = QSharedMemory::tr("%1: already exists").arg(function);
+ break;
+ case KErrNotFound:
+ error = QSharedMemory::NotFound;
+ errorString = QSharedMemory::tr("%1: doesn't exists").arg(function);
+ break;
+ case KErrArgument:
+ error = QSharedMemory::InvalidSize;
+ errorString = QSharedMemory::tr("%1: invalid size").arg(function);
+ break;
+ case KErrNoMemory:
+ error = QSharedMemory::OutOfResources;
+ errorString = QSharedMemory::tr("%1: out of resources").arg(function);
+ break;
+ case KErrPermissionDenied:
+ error = QSharedMemory::PermissionDenied;
+ errorString = QSharedMemory::tr("%1: permission denied").arg(function);
+ break;
+ default:
+ errorString = QSharedMemory::tr("%1: unknown error %2").arg(function).arg(errorCode);
+ error = QSharedMemory::UnknownError;
+#if defined QSHAREDMEMORY_DEBUG
+ qDebug() << errorString << "key" << key;
+#endif
+ }
+}
+
+key_t QSharedMemoryPrivate::handle()
+{
+ // Not really cost effective to check here if shared memory is attachable, as it requires
+ // exactly the same call as attaching, so always assume handle is valid and return failure
+ // from attach.
+ return 1;
+}
+
+bool QSharedMemoryPrivate::cleanHandle()
+{
+ chunk.Close();
+ 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;
+ }
+
+ TPtrC ptr(qt_QString2TPtrC(safeKey));
+
+ TInt err = chunk.CreateGlobal(ptr, size, size);
+
+ setErrorString(function, err);
+
+ if (err != KErrNone)
+ return false;
+
+ // Zero out the created chunk
+ Mem::FillZ(chunk.Base(), chunk.Size());
+
+ return true;
+}
+
+bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode /* mode */)
+{
+ // Grab a pointer to the memory block
+ if (!chunk.Handle()) {
+ 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;
+ }
+
+ TPtrC ptr(qt_QString2TPtrC(safeKey));
+
+ TInt err = KErrNoMemory;
+
+ err = chunk.OpenGlobal(ptr, false);
+
+ if (err != KErrNone) {
+ setErrorString(function, err);
+ return false;
+ }
+ }
+
+ size = chunk.Size();
+ memory = chunk.Base();
+
+ return true;
+}
+
+bool QSharedMemoryPrivate::detach()
+{
+ chunk.Close();
+
+ memory = 0;
+ size = 0;
+
+ return true;
+}
+
+#endif //QT_NO_SHAREDMEMORY
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qsharedmemory_unix.cpp b/src/corelib/kernel/qsharedmemory_unix.cpp
index 2fe5528..e411681 100644
--- a/src/corelib/kernel/qsharedmemory_unix.cpp
+++ b/src/corelib/kernel/qsharedmemory_unix.cpp
@@ -51,8 +51,6 @@
#ifndef QT_NO_SHAREDMEMORY
-QT_BEGIN_NAMESPACE
-
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
@@ -61,6 +59,10 @@ QT_BEGIN_NAMESPACE
#include <fcntl.h>
#include <unistd.h>
+#include "private/qcore_unix_p.h"
+
+QT_BEGIN_NAMESPACE
+
QSharedMemoryPrivate::QSharedMemoryPrivate()
: QObjectPrivate(), memory(0), size(0), error(QSharedMemory::NoError),
#ifndef QT_NO_SYSTEMSEMAPHORE
@@ -83,7 +85,7 @@ void QSharedMemoryPrivate::setErrorString(const QString &function)
error = QSharedMemory::AlreadyExists;
break;
case ENOENT:
- errorString = QSharedMemory::tr("%1: doesn't exists").arg(function);
+ errorString = QSharedMemory::tr("%1: doesn't exist").arg(function);
error = QSharedMemory::NotFound;
break;
case EMFILE:
@@ -122,7 +124,7 @@ key_t QSharedMemoryPrivate::handle()
// 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:"));
+ errorString = QSharedMemory::tr("%1: UNIX key file doesn't exist").arg(QLatin1String("QSharedMemory::handle:"));
error = QSharedMemory::NotFound;
return 0;
}
@@ -153,7 +155,7 @@ int QSharedMemoryPrivate::createUnixKeyFile(const QString &fileName)
if (QFile::exists(fileName))
return 0;
- int fd = open(QFile::encodeName(fileName).constData(),
+ int fd = qt_safe_open(QFile::encodeName(fileName).constData(),
O_EXCL | O_CREAT | O_RDWR, 0640);
if (-1 == fd) {
if (errno == EEXIST)
diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp
index 7dabac6..4b05771 100644
--- a/src/corelib/kernel/qsharedmemory_win.cpp
+++ b/src/corelib/kernel/qsharedmemory_win.cpp
@@ -71,7 +71,7 @@ void QSharedMemoryPrivate::setErrorString(const QString &function)
case ERROR_INVALID_PARAMETER:
#endif
error = QSharedMemory::NotFound;
- errorString = QSharedMemory::tr("%1: doesn't exists").arg(function);
+ errorString = QSharedMemory::tr("%1: doesn't exist").arg(function);
break;
case ERROR_COMMITMENT_LIMIT:
error = QSharedMemory::InvalidSize;
@@ -106,16 +106,11 @@ HANDLE QSharedMemoryPrivate::handle()
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());
- });
+ hand = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, (wchar_t*)safeKey.utf16());
#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());
+ hand = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, 0, (wchar_t*)safeKey.utf16());
#endif
if (!hand) {
setErrorString(function);
@@ -148,13 +143,7 @@ bool QSharedMemoryPrivate::create(int size)
}
// 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());
- } );
+ hand = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size, (wchar_t*)safeKey.utf16());
setErrorString(function);
// hand is valid when it already exists unlike unix so explicitly check
diff --git a/src/corelib/kernel/qsignalmapper.cpp b/src/corelib/kernel/qsignalmapper.cpp
index 19ad307..f32ad9d 100644
--- a/src/corelib/kernel/qsignalmapper.cpp
+++ b/src/corelib/kernel/qsignalmapper.cpp
@@ -66,8 +66,8 @@ public:
\class QSignalMapper
\brief The QSignalMapper class bundles signals from identifiable senders.
- \ingroup io
- \mainclass
+ \ingroup objectmodel
+
This class collects a set of parameterless signals, and re-emits
them with integer, string or widget parameters corresponding to
diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp
index e3e973b..1047eca 100644
--- a/src/corelib/kernel/qsocketnotifier.cpp
+++ b/src/corelib/kernel/qsocketnotifier.cpp
@@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE
\brief The QSocketNotifier class provides support for monitoring
activity on a file descriptor.
+ \ingroup network
\ingroup io
The QSocketNotifier makes it possible to integrate Qt's event
diff --git a/src/corelib/kernel/qsystemsemaphore.cpp b/src/corelib/kernel/qsystemsemaphore.cpp
index 3f91b42..1d414d4 100644
--- a/src/corelib/kernel/qsystemsemaphore.cpp
+++ b/src/corelib/kernel/qsystemsemaphore.cpp
@@ -49,7 +49,6 @@ QT_BEGIN_NAMESPACE
/*!
\class QSystemSemaphore
- \ingroup ipc
\since 4.4
\brief The QSystemSemaphore class provides a general counting system semaphore.
@@ -123,6 +122,11 @@ QT_BEGIN_NAMESPACE
operations that were not released. Thus if the process acquires a
resource and then exits without releasing it, Unix will release that
resource.
+
+ \o Symbian: QSystemSemaphore behaves the same as Windows semaphores.
+ In other words, the operating system owns the semaphore and ignores
+ QSystemSemaphore::AccessMode.
+
\endlist
\sa QSharedMemory, QSemaphore
@@ -147,7 +151,7 @@ QT_BEGIN_NAMESPACE
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
+ In Windows and in Symbian, \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
@@ -165,8 +169,8 @@ QT_BEGIN_NAMESPACE
\sa acquire(), key()
*/
QSystemSemaphore::QSystemSemaphore(const QString &key, int initialValue, AccessMode mode)
+ : d(new QSystemSemaphorePrivate)
{
- d = new QSystemSemaphorePrivate;
setKey(key, initialValue, mode);
}
@@ -188,7 +192,6 @@ QSystemSemaphore::QSystemSemaphore(const QString &key, int initialValue, AccessM
QSystemSemaphore::~QSystemSemaphore()
{
d->cleanHandle();
- delete d;
}
/*!
@@ -198,7 +201,7 @@ QSystemSemaphore::~QSystemSemaphore()
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
+ reuses the semaphore. In Windows and in Symbian, where semaphores can't survive a
crash, this enum has no effect.
\value Open If the semaphore already exists, its initial resource
@@ -211,7 +214,7 @@ QSystemSemaphore::~QSystemSemaphore()
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
+ Windows and in Symbian, where a semaphore can't survive a crash, Create and Open
have the same behavior.
*/
@@ -231,7 +234,7 @@ void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode m
return;
d->error = NoError;
d->errorString = QString();
-#ifndef Q_OS_WIN
+#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN)
// optimization to not destroy/create the file & semaphore
if (key == d->key && mode == Create && d->createdSemaphore && d->createdFile) {
d->initialValue = initialValue;
diff --git a/src/corelib/kernel/qsystemsemaphore.h b/src/corelib/kernel/qsystemsemaphore.h
index 78437a6..69fb98c 100644
--- a/src/corelib/kernel/qsystemsemaphore.h
+++ b/src/corelib/kernel/qsystemsemaphore.h
@@ -43,6 +43,7 @@
#define QSYSTEMSEMAPHORE_H
#include <QtCore/qstring.h>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_HEADER
@@ -89,7 +90,7 @@ public:
private:
Q_DISABLE_COPY(QSystemSemaphore)
- QSystemSemaphorePrivate *d;
+ QScopedPointer<QSystemSemaphorePrivate> d;
};
#endif // QT_NO_SYSTEMSEMAPHORE
diff --git a/src/corelib/kernel/qsystemsemaphore_p.h b/src/corelib/kernel/qsystemsemaphore_p.h
index 7fc3946..b547e6d 100644
--- a/src/corelib/kernel/qsystemsemaphore_p.h
+++ b/src/corelib/kernel/qsystemsemaphore_p.h
@@ -62,6 +62,10 @@
# include <sys/types.h>
#endif
+#ifdef Q_OS_SYMBIAN
+class RSemaphore;
+#endif
+
QT_BEGIN_NAMESPACE
class QSystemSemaphorePrivate
@@ -77,10 +81,14 @@ public:
#ifdef Q_OS_WIN
HANDLE handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open);
+ void setErrorString(const QString &function);
+#elif defined(Q_OS_SYMBIAN)
+ int handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open);
+ void setErrorString(const QString &function,int err = 0);
#else
key_t handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open);
-#endif
void setErrorString(const QString &function);
+#endif
void cleanHandle();
bool modifySemaphore(int count);
@@ -90,13 +98,14 @@ public:
#ifdef Q_OS_WIN
HANDLE semaphore;
HANDLE semaphoreLock;
+#elif defined(Q_OS_SYMBIAN)
+ RSemaphore semaphore;
#else
int semaphore;
bool createdFile;
bool createdSemaphore;
key_t unix_key;
#endif
-
QString errorString;
QSystemSemaphore::SystemSemaphoreError error;
};
diff --git a/src/corelib/kernel/qsystemsemaphore_symbian.cpp b/src/corelib/kernel/qsystemsemaphore_symbian.cpp
new file mode 100644
index 0000000..3af441a
--- /dev/null
+++ b/src/corelib/kernel/qsystemsemaphore_symbian.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsystemsemaphore.h"
+#include "qsystemsemaphore_p.h"
+#include "qcoreapplication.h"
+#include <qdebug.h>
+
+#include <qcore_symbian_p.h>
+#include <e32cmn.h>
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_SYSTEMSEMAPHORE
+
+QSystemSemaphorePrivate::QSystemSemaphorePrivate() :
+ error(QSystemSemaphore::NoError)
+{
+}
+
+void QSystemSemaphorePrivate::setErrorString(const QString &function, int err)
+{
+ if (err == KErrNone){
+ return;
+ }
+ switch(err){
+ case KErrAlreadyExists:
+ errorString = QCoreApplication::tr("%1: already exists", "QSystemSemaphore").arg(function);
+ error = QSystemSemaphore::AlreadyExists;
+ break;
+ case KErrNotFound:
+ errorString = QCoreApplication::tr("%1: doesn't exists", "QSystemSemaphore").arg(function);
+ error = QSystemSemaphore::NotFound;
+ break;
+ case KErrNoMemory:
+ case KErrInUse:
+ errorString = QCoreApplication::tr("%1: out of resources", "QSystemSemaphore").arg(function);
+ error = QSystemSemaphore::OutOfResources;
+ break;
+default:
+ errorString = QCoreApplication::tr("%1: unknown error %2", "QSystemSemaphore").arg(function).arg(err);
+ error = QSystemSemaphore::UnknownError;
+ }
+
+#if defined QSYSTEMSEMAPHORE_DEBUG
+ qDebug() << errorString << "key" << key;
+#endif
+}
+
+int QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode)
+{
+ // don't allow making handles on empty keys
+ if (key.isEmpty())
+ return 0;
+ QString safeName = makeKeyFileName();
+ TPtrC name(qt_QString2TPtrC(safeName));
+ int err;
+ err = semaphore.OpenGlobal(name,EOwnerProcess);
+ if (err == KErrNotFound){
+ err = semaphore.CreateGlobal(name,initialValue, EOwnerProcess);
+ }
+ if (err){
+ setErrorString(QLatin1String("QSystemSemaphore::handle"),err);
+ return 0;
+ }
+ return semaphore.Handle();
+}
+
+void QSystemSemaphorePrivate::cleanHandle()
+{
+ semaphore.Close();
+}
+
+bool QSystemSemaphorePrivate::modifySemaphore(int count)
+{
+ if (0 == handle())
+ return false;
+
+ if (count > 0) {
+ semaphore.Signal(count);
+ } else {
+ semaphore.Wait();
+ }
+ return true;
+}
+
+#endif //QT_NO_SYSTEMSEMAPHORE
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qsystemsemaphore_win.cpp b/src/corelib/kernel/qsystemsemaphore_win.cpp
index 7ddacd0..3cd5ede 100644
--- a/src/corelib/kernel/qsystemsemaphore_win.cpp
+++ b/src/corelib/kernel/qsystemsemaphore_win.cpp
@@ -87,11 +87,7 @@ HANDLE QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode)
// 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());
- });
+ semaphore = CreateSemaphore(0, initialValue, MAXLONG, (wchar_t*)safeName.utf16());
if (semaphore == NULL)
setErrorString(QLatin1String("QSystemSemaphore::handle"));
}
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp
index 6c77455..4254d3c 100644
--- a/src/corelib/kernel/qtimer.cpp
+++ b/src/corelib/kernel/qtimer.cpp
@@ -50,9 +50,8 @@ 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
@@ -101,11 +100,22 @@ QT_BEGIN_NAMESPACE
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.
+ \section1 Accuracy and Timer Resolution
+
+ Timers will never time out earlier than the specified timeout value
+ and they are not guaranteed to time out at the exact value specified.
+ In many situations, they may time out late by a period of time that
+ depends on the accuracy of the system timers.
+
+ The accuracy of timers depends on the underlying operating system
+ and hardware. Most platforms support a resolution of 1 millisecond,
+ though the accuracy of the timer will not equal this resolution
+ in many real-world situations.
+
+ If Qt is unable to deliver the requested number of timer clicks,
+ it will silently discard some.
+
+ \section1 Alternatives to QTimer
An alternative to using QTimer is to call QObject::startTimer()
for your object and reimplement the QObject::timerEvent() event
@@ -211,7 +221,7 @@ void QTimer::start()
*/
void QTimer::start(int msec)
{
- setInterval(msec);
+ inter = msec;
start();
}
@@ -251,7 +261,7 @@ void QTimer::stop()
/*!
- \reimp
+ \reimp
*/
void QTimer::timerEvent(QTimerEvent *e)
{
@@ -269,7 +279,7 @@ class QSingleShotTimer : public QObject
public:
~QSingleShotTimer();
QSingleShotTimer(int msec, QObject *r, const char * m);
-signals:
+Q_SIGNALS:
void timeout();
protected:
void timerEvent(QTimerEvent *);
diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp
index 4623145..9025e2c 100644
--- a/src/corelib/kernel/qtranslator.cpp
+++ b/src/corelib/kernel/qtranslator.cpp
@@ -58,6 +58,7 @@
#if defined(Q_OS_UNIX)
#define QT_USE_MMAP
+#include "private/qcore_unix_p.h"
#endif
// most of the headers below are already included in qplatformdefs.h
@@ -209,8 +210,6 @@ static int numerusHelper(int n, const uchar *rules, int rulesSize)
return -1;
}
-extern bool qt_detectRTLLanguage();
-
class QTranslatorPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QTranslator)
@@ -250,8 +249,6 @@ public:
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
@@ -351,7 +348,7 @@ QTranslator::QTranslator(QObject * parent, const char * name)
QTranslator::~QTranslator()
{
if (QCoreApplication::instance())
- QCoreApplication::instance()->removeTranslator(this);
+ QCoreApplication::removeTranslator(this);
Q_D(QTranslator);
d->clear();
}
@@ -504,7 +501,7 @@ bool QTranslator::load(const QString & filename, const QString & directory,
\overload load()
\fn bool QTranslator::load(const uchar *data, int len)
- Loads the .qm file data \a data of length \a len into the
+ 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
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index d8094c1..099fdf4 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -71,27 +71,6 @@ QT_BEGIN_NAMESPACE
# 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;
@@ -179,6 +158,12 @@ static void construct(QVariant::Private *x, const void *copy)
case QVariant::Double:
x->data.d = copy ? *static_cast<const double*>(copy) : 0.0;
break;
+ case QMetaType::Float:
+ x->data.f = copy ? *static_cast<const float*>(copy) : 0.0f;
+ break;
+ case QMetaType::QObjectStar:
+ x->data.o = copy ? *static_cast<QObject *const*>(copy) : 0;
+ break;
case QVariant::LongLong:
x->data.ll = copy ? *static_cast<const qlonglong *>(copy) : Q_INT64_C(0);
break;
@@ -189,10 +174,13 @@ static void construct(QVariant::Private *x, const void *copy)
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)
+ void *ptr = QMetaType::construct(x->type, copy);
+ if (!ptr) {
x->type = QVariant::Invalid;
+ } else {
+ x->is_shared = true;
+ x->data.shared = new QVariant::PrivateShared(ptr);
+ }
break;
}
x->is_null = !copy;
@@ -274,6 +262,8 @@ static void clear(QVariant::Private *d)
case QVariant::LongLong:
case QVariant::ULongLong:
case QVariant::Double:
+ case QMetaType::Float:
+ case QMetaType::QObjectStar:
break;
case QVariant::Invalid:
case QVariant::UserType:
@@ -342,6 +332,8 @@ static bool isNull(const QVariant::Private *d)
case QVariant::ULongLong:
case QVariant::Bool:
case QVariant::Double:
+ case QMetaType::Float:
+ case QMetaType::QObjectStar:
break;
}
return d->is_null;
@@ -433,6 +425,10 @@ static bool compare(const QVariant::Private *a, const QVariant::Private *b)
return a->data.b == b->data.b;
case QVariant::Double:
return a->data.d == b->data.d;
+ case QMetaType::Float:
+ return a->data.f == b->data.f;
+ case QMetaType::QObjectStar:
+ return a->data.o == b->data.o;
case QVariant::Date:
return *v_cast<QDate>(a) == *v_cast<QDate>(b);
case QVariant::Time:
@@ -463,15 +459,17 @@ static bool compare(const QVariant::Private *a, const QVariant::Private *b)
if (!QMetaType::isRegistered(a->type))
qFatal("QVariant::compare: type %d unknown to QVariant.", a->type);
+ const void *a_ptr = a->is_shared ? a->data.shared->ptr : &(a->data.ptr);
+ const void *b_ptr = b->is_shared ? b->data.shared->ptr : &(b->data.ptr);
+
/* 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 *static_cast<void *const *>(a_ptr) == *static_cast<void *const *>(b_ptr);
- return a->data.shared->ptr == b->data.shared->ptr;
+ return a_ptr == b_ptr;
}
/*!
@@ -491,7 +489,7 @@ static qlonglong qMetaTypeNumber(const QVariant::Private *d)
case QMetaType::Long:
return qlonglong(*static_cast<long *>(d->data.shared->ptr));
case QMetaType::Float:
- return qRound64(*static_cast<float *>(d->data.shared->ptr));
+ return qRound64(d->data.f);
case QVariant::Double:
return qRound64(d->data.d);
}
@@ -605,6 +603,15 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result,
ok = &dummy;
switch (uint(t)) {
+ case QVariant::Url:
+ switch (d->type) {
+ case QVariant::String:
+ *static_cast<QUrl *>(result) = QUrl(*v_cast<QString>(d));
+ break;
+ default:
+ return false;
+ }
+ break;
case QVariant::String: {
QString *str = static_cast<QString *>(result);
switch (d->type) {
@@ -628,7 +635,7 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result,
*str = QString::number(qMetaTypeUNumber(d));
break;
case QMetaType::Float:
- *str = QString::number(*static_cast<float *>(d->data.shared->ptr), 'g', FLT_DIG);
+ *str = QString::number(d->data.f, 'g', FLT_DIG);
break;
case QVariant::Double:
*str = QString::number(d->data.d, 'g', DBL_DIG);
@@ -654,6 +661,9 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result,
if (v_cast<QStringList>(d)->count() == 1)
*str = v_cast<QStringList>(d)->at(0);
break;
+ case QVariant::Url:
+ *str = v_cast<QUrl>(d)->toString();
+ break;
default:
return false;
}
@@ -799,7 +809,7 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result,
*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);
+ *ba = QByteArray::number(d->data.f, 'g', FLT_DIG);
break;
case QMetaType::Char:
case QMetaType::UChar:
@@ -901,7 +911,7 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result,
*f = double(d->data.b);
break;
case QMetaType::Float:
- *f = *static_cast<float *>(d->data.shared->ptr);
+ *f = double(d->data.f);
break;
case QVariant::LongLong:
case QVariant::Int:
@@ -931,10 +941,10 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result,
float *f = static_cast<float *>(result);
switch (d->type) {
case QVariant::String:
- *f = float(v_cast<QString>(d)->toDouble(ok));
+ *f = v_cast<QString>(d)->toFloat(ok);
break;
case QVariant::ByteArray:
- *f = float(v_cast<QByteArray>(d)->toDouble(ok));
+ *f = v_cast<QByteArray>(d)->toFloat(ok);
break;
case QVariant::Bool:
*f = float(d->data.b);
@@ -1035,7 +1045,7 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result,
#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM)
static void streamDebug(QDebug dbg, const QVariant &v)
{
- switch (v.type()) {
+ switch (v.userType()) {
case QVariant::Int:
dbg.nospace() << v.toInt();
break;
@@ -1048,6 +1058,12 @@ static void streamDebug(QDebug dbg, const QVariant &v)
case QVariant::ULongLong:
dbg.nospace() << v.toULongLong();
break;
+ case QMetaType::Float:
+ dbg.nospace() << v.toFloat();
+ break;
+ case QMetaType::QObjectStar:
+ dbg.nospace() << qVariantValue<QObject *>(v);
+ break;
case QVariant::Double:
dbg.nospace() << v.toDouble();
break;
@@ -1153,9 +1169,8 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
\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
@@ -1187,8 +1202,8 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
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 can
- have a defined type with no value set. However, note that QVariant
+ QVariant also supports the notion of null values, where you can
+ have a defined type with no value set. However, note that QVariant
types can only be cast when they have had a value set.
\snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 1
@@ -1264,6 +1279,7 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
\value Map a QVariantMap
\value Matrix a QMatrix
\value Transform a QTransform
+ \value Matrix4x4 a QMatrix4x4
\value Palette a QPalette
\value Pen a QPen
\value Pixmap a QPixmap
@@ -1271,6 +1287,7 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
\value PointArray a QPointArray
\value PointF a QPointF
\value Polygon a QPolygon
+ \value Quaternion a QQuaternion
\value Rect a QRect
\value RectF a QRectF
\value RegExp a QRegExp
@@ -1286,6 +1303,9 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
\value UInt a \l uint
\value ULongLong a \l qulonglong
\value Url a QUrl
+ \value Vector2D a QVector2D
+ \value Vector3D a QVector3D
+ \value Vector4D a QVector4D
\value UserType Base value for user-defined types.
@@ -1356,7 +1376,7 @@ void QVariant::create(int type, const void *copy)
QVariant::~QVariant()
{
- if (d.type > Char && (!d.is_shared || !d.data.shared->ref.deref()))
+ if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared && d.type > Char && d.type < UserType))
handler->clear(&d);
}
@@ -1372,7 +1392,7 @@ QVariant::QVariant(const QVariant &p)
{
if (d.is_shared) {
d.data.shared->ref.ref();
- } else if (p.d.type > Char) {
+ } else if (p.d.type > Char && p.d.type < QVariant::UserType) {
handler->construct(&d, p.constData());
d.is_null = p.d.is_null;
}
@@ -1566,6 +1586,12 @@ QVariant::QVariant(const char *val)
*/
/*!
+ \fn QVariant::QVariant(float 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.
@@ -1606,6 +1632,22 @@ QVariant::QVariant(Type type)
{ create(type, 0); }
QVariant::QVariant(int typeOrUserType, const void *copy)
{ create(typeOrUserType, copy); d.is_null = false; }
+
+/*! \internal
+ flags is true if it is a pointer type
+ */
+QVariant::QVariant(int typeOrUserType, const void *copy, uint flags)
+{
+ if (flags) { //type is a pointer type
+ d.type = typeOrUserType;
+ d.data.ptr = *reinterpret_cast<void *const*>(copy);
+ d.is_null = false;
+ } else {
+ 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)
@@ -1620,44 +1662,44 @@ QVariant::QVariant(double val)
{ d.is_null = false; d.type = Double; d.data.d = val; }
QVariant::QVariant(const QByteArray &val)
-{ create(ByteArray, &val); }
+{ d.is_null = false; d.type = ByteArray; v_construct<QByteArray>(&d, val); }
QVariant::QVariant(const QBitArray &val)
-{ create(BitArray, &val); }
+{ d.is_null = false; d.type = BitArray; v_construct<QBitArray>(&d, val); }
QVariant::QVariant(const QString &val)
-{ create(String, &val); }
+{ d.is_null = false; d.type = String; v_construct<QString>(&d, val); }
QVariant::QVariant(const QChar &val)
-{ create (Char, &val); }
+{ d.is_null = false; d.type = Char; v_construct<QChar>(&d, val); }
QVariant::QVariant(const QLatin1String &val)
-{ QString str(val); create(String, &str); }
+{ QString str(val); d.is_null = false; d.type = String; v_construct<QString>(&d, str); }
QVariant::QVariant(const QStringList &val)
-{ create(StringList, &val); }
+{ d.is_null = false; d.type = StringList; v_construct<QStringList>(&d, val); }
QVariant::QVariant(const QDate &val)
-{ create(Date, &val); }
+{ d.is_null = false; d.type = Date; v_construct<QDate>(&d, val); }
QVariant::QVariant(const QTime &val)
-{ create(Time, &val); }
+{ d.is_null = false; d.type = Time; v_construct<QTime>(&d, val); }
QVariant::QVariant(const QDateTime &val)
-{ create(DateTime, &val); }
+{ d.is_null = false; d.type = DateTime; v_construct<QDateTime>(&d, val); }
QVariant::QVariant(const QList<QVariant> &list)
-{ create(List, &list); }
+{ d.is_null = false; d.type = List; v_construct<QVariantList>(&d, list); }
QVariant::QVariant(const QMap<QString, QVariant> &map)
-{ create(Map, &map); }
+{ d.is_null = false; d.type = Map; v_construct<QVariantMap>(&d, map); }
QVariant::QVariant(const QHash<QString, QVariant> &hash)
-{ create(Hash, &hash); }
+{ d.is_null = false; d.type = Hash; v_construct<QVariantHash>(&d, 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); }
+QVariant::QVariant(const QPoint &pt) { d.is_null = false; d.type = Point; v_construct<QPoint>(&d, pt); }
+QVariant::QVariant(const QPointF &pt) { d.is_null = false; d.type = PointF; v_construct<QPointF>(&d, pt); }
+QVariant::QVariant(const QRectF &r) { d.is_null = false; d.type = RectF; v_construct<QRectF>(&d, r); }
+QVariant::QVariant(const QLineF &l) { d.is_null = false; d.type = LineF; v_construct<QLineF>(&d, l); }
+QVariant::QVariant(const QLine &l) { d.is_null = false; d.type = Line; v_construct<QLine>(&d, l); }
+QVariant::QVariant(const QRect &r) { d.is_null = false; d.type = Rect; v_construct<QRect>(&d, r); }
+QVariant::QVariant(const QSize &s) { d.is_null = false; d.type = Size; v_construct<QSize>(&d, s); }
+QVariant::QVariant(const QSizeF &s) { d.is_null = false; d.type = SizeF; v_construct<QSizeF>(&d, s); }
#endif
-QVariant::QVariant(const QUrl &u) { create(Url, &u); }
-QVariant::QVariant(const QLocale &l) { create(Locale, &l); }
+QVariant::QVariant(const QUrl &u) { d.is_null = false; d.type = Url; v_construct<QUrl>(&d, u); }
+QVariant::QVariant(const QLocale &l) { d.is_null = false; d.type = Locale; v_construct<QLocale>(&d, l); }
#ifndef QT_NO_REGEXP
-QVariant::QVariant(const QRegExp &regExp) { create(RegExp, &regExp); }
+QVariant::QVariant(const QRegExp &regExp) { d.is_null = false; d.type = RegExp; v_construct<QRegExp>(&d, regExp); }
#endif
QVariant::QVariant(Qt::GlobalColor color) { create(62, &color); }
@@ -1671,7 +1713,7 @@ QVariant::QVariant(Qt::GlobalColor color) { create(62, &color); }
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.
+ QMetaType::QRegExp and QMetaType::QFont through QMetaType::QQuaternion.
Pay particular attention when working with char and QChar
variants. Note that there is no QVariant constructor specifically
@@ -1722,7 +1764,7 @@ QVariant& QVariant::operator=(const QVariant &variant)
if (variant.d.is_shared) {
variant.d.data.shared->ref.ref();
d = variant.d;
- } else if (variant.d.type > Char) {
+ } else if (variant.d.type > Char && variant.d.type < UserType) {
d.type = variant.d.type;
handler->construct(&d, variant.constData());
d.is_null = variant.d.is_null;
@@ -1776,7 +1818,7 @@ const char *QVariant::typeName() const
*/
void QVariant::clear()
{
- if (!d.is_shared || !d.data.shared->ref.deref())
+ if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared && d.type < UserType && d.type > Char))
handler->clear(&d);
d.type = Invalid;
d.is_null = true;
@@ -1828,7 +1870,7 @@ QVariant::Type QVariant::nameToType(const char *name)
#ifndef QT_NO_DATASTREAM
enum { MapFromThreeCount = 35 };
-static const uint map_from_three[MapFromThreeCount] =
+static const ushort map_from_three[MapFromThreeCount] =
{
QVariant::Invalid,
QVariant::Map,
@@ -1899,7 +1941,7 @@ void QVariant::load(QDataStream &s)
create(static_cast<int>(u), 0);
d.is_null = is_null;
- if (d.type == QVariant::Invalid) {
+ if (!isValid()) {
// Since we wrote something, we should read something
QString x;
s >> x;
@@ -1908,7 +1950,7 @@ void QVariant::load(QDataStream &s)
}
// const cast is safe since we operate on a newly constructed variant
- if (!QMetaType::load(s, d.type, const_cast<void *>(constDataHelper(d)))) {
+ if (!QMetaType::load(s, d.type, const_cast<void *>(constData()))) {
s.setStatus(QDataStream::ReadCorruptData);
qWarning("QVariant::load: unable to load type %d.", d.type);
}
@@ -1943,12 +1985,12 @@ void QVariant::save(QDataStream &s) const
s << QMetaType::typeName(userType());
}
- if (d.type == QVariant::Invalid) {
+ if (!isValid()) {
s << QString();
return;
}
- if (!QMetaType::save(s, d.type, constDataHelper(d))) {
+ if (!QMetaType::save(s, d.type, constData())) {
Q_ASSERT_X(false, "QVariant::save", "Invalid type to save");
qWarning("QVariant::save: unable to save type %d.", d.type);
}
@@ -2309,16 +2351,17 @@ QBitArray QVariant::toBitArray() const
}
template <typename T>
-inline T qNumVariantToHelper(const QVariant::Private &d, QVariant::Type t,
+inline T qNumVariantToHelper(const QVariant::Private &d,
const QVariant::Handler *handler, bool *ok, const T& val)
{
+ uint t = qMetaTypeId<T>();
if (ok)
*ok = true;
if (d.type == t)
return val;
T ret;
- if (!handler->convert(&d, t, &ret, ok) && ok)
+ if (!handler->convert(&d, QVariant::Type(t), &ret, ok) && ok)
*ok = false;
return ret;
}
@@ -2340,7 +2383,7 @@ inline T qNumVariantToHelper(const QVariant::Private &d, QVariant::Type t,
*/
int QVariant::toInt(bool *ok) const
{
- return qNumVariantToHelper<int>(d, Int, handler, ok, d.data.i);
+ return qNumVariantToHelper<int>(d, handler, ok, d.data.i);
}
/*!
@@ -2360,7 +2403,7 @@ int QVariant::toInt(bool *ok) const
*/
uint QVariant::toUInt(bool *ok) const
{
- return qNumVariantToHelper<uint>(d, UInt, handler, ok, d.data.u);
+ return qNumVariantToHelper<uint>(d, handler, ok, d.data.u);
}
/*!
@@ -2375,7 +2418,7 @@ uint QVariant::toUInt(bool *ok) const
*/
qlonglong QVariant::toLongLong(bool *ok) const
{
- return qNumVariantToHelper<qlonglong>(d, LongLong, handler, ok, d.data.ll);
+ return qNumVariantToHelper<qlonglong>(d, handler, ok, d.data.ll);
}
/*!
@@ -2391,7 +2434,7 @@ qlonglong QVariant::toLongLong(bool *ok) const
*/
qulonglong QVariant::toULongLong(bool *ok) const
{
- return qNumVariantToHelper<qulonglong>(d, ULongLong, handler, ok, d.data.ull);
+ return qNumVariantToHelper<qulonglong>(d, handler, ok, d.data.ull);
}
/*!
@@ -2418,7 +2461,7 @@ bool QVariant::toBool() const
/*!
Returns the variant as a double if the variant has type() \l
- Double, \l Bool, \l ByteArray, \l Int, \l LongLong, \l String, \l
+ Double, \l QMetaType::Float, \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
@@ -2428,7 +2471,41 @@ bool QVariant::toBool() const
*/
double QVariant::toDouble(bool *ok) const
{
- return qNumVariantToHelper<double>(d, Double, handler, ok, d.data.d);
+ return qNumVariantToHelper<double>(d, handler, ok, d.data.d);
+}
+
+/*!
+ Returns the variant as a float if the variant has type() \l
+ Double, \l QMetaType::Float, \l Bool, \l ByteArray, \l Int, \l LongLong, \l String, \l
+ UInt, or \l ULongLong; otherwise returns 0.0.
+
+ \since 4.6
+
+ 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()
+*/
+float QVariant::toFloat(bool *ok) const
+{
+ return qNumVariantToHelper<float>(d, handler, ok, d.data.f);
+}
+
+/*!
+ Returns the variant as a qreal if the variant has type() \l
+ Double, \l QMetaType::Float, \l Bool, \l ByteArray, \l Int, \l LongLong, \l String, \l
+ UInt, or \l ULongLong; otherwise returns 0.0.
+
+ \since 4.6
+
+ 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()
+*/
+qreal QVariant::toReal(bool *ok) const
+{
+ return qNumVariantToHelper<qreal>(d, handler, ok, d.data.real);
}
/*!
@@ -2489,7 +2566,8 @@ static const quint32 qCanConvertMatrix[QVariant::LastCoreType + 1] =
/*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,
+ | 1 << QVariant::LongLong | 1 << QVariant::ULongLong | 1 << QVariant::Char
+ | 1 << QVariant::Url,
/*QStringList*/ 1 << QVariant::List | 1 << QVariant::String,
@@ -2504,7 +2582,7 @@ static const quint32 qCanConvertMatrix[QVariant::LastCoreType + 1] =
/*QDateTime*/ 1 << QVariant::String | 1 << QVariant::Date,
-/*QUrl*/ 0,
+/*QUrl*/ 1 << QVariant::String,
/*QLocale*/ 0,
@@ -2566,57 +2644,63 @@ static const quint32 qCanConvertMatrix[QVariant::LastCoreType + 1] =
*/
bool QVariant::canConvert(Type t) const
{
- if (d.type == uint(t))
+ //we can treat floats as double
+ //the reason for not doing it the "proper" way is that QMetaType::Float's value is 135,
+ //which can't be handled by qCanConvertMatrix
+ //In addition QVariant::Type doesn't have a Float value, so we're using QMetaType::Float
+ const uint currentType = ((d.type == QMetaType::Float) ? QVariant::Double : d.type);
+ if (uint(t) == uint(QMetaType::Float)) t = QVariant::Double;
+
+ if (currentType == uint(t))
return true;
- if (d.type > QVariant::LastCoreType || t > QVariant::LastCoreType) {
+ if (currentType > 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;
+ return currentType == QVariant::KeySequence
+ || currentType == QMetaType::ULong
+ || currentType == QMetaType::Long
+ || currentType == QMetaType::UShort
+ || currentType == QMetaType::UChar
+ || currentType == QMetaType::Char
+ || currentType == QMetaType::Short;
case QVariant::Image:
- return d.type == QVariant::Pixmap || d.type == QVariant::Bitmap;
+ return currentType == QVariant::Pixmap || currentType == QVariant::Bitmap;
case QVariant::Pixmap:
- return d.type == QVariant::Image || d.type == QVariant::Bitmap
- || d.type == QVariant::Brush;
+ return currentType == QVariant::Image || currentType == QVariant::Bitmap
+ || currentType == QVariant::Brush;
case QVariant::Bitmap:
- return d.type == QVariant::Pixmap || d.type == QVariant::Image;
+ return currentType == QVariant::Pixmap || currentType == QVariant::Image;
case QVariant::ByteArray:
- return d.type == QVariant::Color;
+ return currentType == QVariant::Color;
case QVariant::String:
- return d.type == QVariant::KeySequence || d.type == QVariant::Font
- || d.type == QVariant::Color;
+ return currentType == QVariant::KeySequence || currentType == QVariant::Font
+ || currentType == QVariant::Color;
case QVariant::KeySequence:
- return d.type == QVariant::String || d.type == QVariant::Int;
+ return currentType == QVariant::String || currentType == QVariant::Int;
case QVariant::Font:
- return d.type == QVariant::String;
+ return currentType == QVariant::String;
case QVariant::Color:
- return d.type == QVariant::String || d.type == QVariant::ByteArray
- || d.type == QVariant::Brush;
+ return currentType == QVariant::String || currentType == QVariant::ByteArray
+ || currentType == QVariant::Brush;
case QVariant::Brush:
- return d.type == QVariant::Color || d.type == QVariant::Pixmap;
+ return currentType == QVariant::Color || currentType == 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;
+ return qCanConvertMatrix[QVariant::Int] & (1 << currentType) || currentType == QVariant::Int;
default:
return false;
}
}
- if(t == String && d.type == StringList)
+ if(t == String && currentType == StringList)
return v_cast<QStringList>(&d)->count() == 1;
else
- return qCanConvertMatrix[t] & (1 << d.type);
+ return qCanConvertMatrix[t] & (1 << currentType);
}
/*!
@@ -2712,7 +2796,7 @@ bool QVariant::cmp(const QVariant &v) const
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());
+ return qFuzzyCompare(toReal(), v.toReal());
else
return toLongLong() == v.toLongLong();
}
@@ -2727,7 +2811,7 @@ bool QVariant::cmp(const QVariant &v) const
const void *QVariant::constData() const
{
- return constDataHelper(d);
+ return d.is_shared ? d.data.shared->ptr : reinterpret_cast<const void *>(&d.data.ptr);
}
/*!
@@ -2740,7 +2824,7 @@ const void *QVariant::constData() const
void* QVariant::data()
{
detach();
- return const_cast<void *>(constDataHelper(d));
+ return const_cast<void *>(constData());
}
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 95baeee..7f23007 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -154,7 +154,12 @@ class Q_CORE_EXPORT QVariant
TextFormat = 79,
Matrix = 80,
Transform = 81,
- LastGuiType = Transform,
+ Matrix4x4 = 82,
+ Vector2D = 83,
+ Vector3D = 84,
+ Vector4D = 85,
+ Quaternion = 86,
+ LastGuiType = Quaternion,
UserType = 127,
#ifdef QT3_SUPPORT
@@ -169,6 +174,7 @@ class Q_CORE_EXPORT QVariant
~QVariant();
QVariant(Type type);
QVariant(int typeOrUserType, const void *copy);
+ QVariant(int typeOrUserType, const void *copy, uint flags);
QVariant(const QVariant &other);
#ifndef QT_NO_DATASTREAM
@@ -181,6 +187,7 @@ class Q_CORE_EXPORT QVariant
QVariant(qulonglong ull);
QVariant(bool b);
QVariant(double d);
+ QVariant(float f) { d.is_null = false; d.type = QMetaType::Float; d.data.f = f; }
#ifndef QT_NO_CAST_FROM_ASCII
QT_ASCII_CAST_WARN_CONSTRUCTOR QVariant(const char *str);
#endif
@@ -244,6 +251,8 @@ class Q_CORE_EXPORT QVariant
qulonglong toULongLong(bool *ok = 0) const;
bool toBool() const;
double toDouble(bool *ok = 0) const;
+ float toFloat(bool *ok = 0) const;
+ qreal toReal(bool *ok = 0) const;
QByteArray toByteArray() const;
QBitArray toBitArray() const;
QString toString() const;
@@ -349,8 +358,11 @@ class Q_CORE_EXPORT QVariant
uint u;
bool b;
double d;
+ float f;
+ qreal real;
qlonglong ll;
qulonglong ull;
+ QObject *o;
void *ptr;
PrivateShared *shared;
} data;
@@ -434,7 +446,7 @@ inline bool qvariant_cast_helper(const QVariant &v, QVariant::Type tp, void *ptr
template <typename T>
inline QVariant qVariantFromValue(const T &t)
{
- return QVariant(qMetaTypeId<T>(reinterpret_cast<T *>(0)), &t);
+ return QVariant(qMetaTypeId<T>(reinterpret_cast<T *>(0)), &t, QTypeInfo<T>::isPointer);
}
template <>
@@ -443,7 +455,18 @@ 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);
+ //if possible we reuse the current QVariant private
+ const int type = qMetaTypeId<T>(reinterpret_cast<T *>(0));
+ QVariant::Private &d = v.data_ptr();
+ if (v.isDetached() && (type <= int(QVariant::Char) || type == d.type)) {
+ d.type = type;
+ T *old = reinterpret_cast<T*>(d.is_shared ? d.data.shared->ptr : &d.data.ptr);
+ if (QTypeInfo<T>::isComplex)
+ old->~T();
+ new (old) T(t); //call the copy constructor
+ } else {
+ v = QVariant(type, &t, QTypeInfo<T>::isPointer);
+ }
}
inline QVariant::QVariant() {}
diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h
index 8c41570..c7edd0b 100644
--- a/src/corelib/kernel/qvariant_p.h
+++ b/src/corelib/kernel/qvariant_p.h
@@ -57,6 +57,7 @@
// to a pointer of the input type
#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
@@ -91,13 +92,25 @@ inline T *v_cast(QVariant::Private *d, T * = 0)
#endif
+
+//a simple template that avoids to allocate 2 memory chunks when creating a QVariant
+template <class T> class QVariantPrivateSharedEx : public QVariant::PrivateShared
+{
+public:
+ QVariantPrivateSharedEx() : QVariant::PrivateShared(&m_t) { }
+ 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 void *copy, T * = 0)
{
if (sizeof(T) > sizeof(QVariant::Private::Data)) {
- x->data.shared = copy ? new QVariant::PrivateShared(new T(*static_cast<const T *>(copy)))
- : new QVariant::PrivateShared(new T);
+ x->data.shared = copy ? new QVariantPrivateSharedEx<T>(*static_cast<const T *>(copy))
+ : new QVariantPrivateSharedEx<T>;
x->is_shared = true;
} else {
if (copy)
@@ -107,18 +120,34 @@ inline void v_construct(QVariant::Private *x, const void *copy, T * = 0)
}
}
+template <class T>
+inline void v_construct(QVariant::Private *x, const T &t)
+{
+ if (sizeof(T) > sizeof(QVariant::Private::Data)) {
+ x->data.shared = new QVariantPrivateSharedEx<T>(t);
+ x->is_shared = true;
+ } else {
+ new (&x->data.ptr) T(t);
+ }
+}
+
// deletes the internal structures
template <class T>
inline void v_clear(QVariant::Private *d, T* = 0)
{
+
if (sizeof(T) > sizeof(QVariant::Private::Data)) {
- delete v_cast<T>(d);
- delete d->data.shared;
+ //now we need to cast
+ //because QVariant::PrivateShared doesn't have a virtual destructor
+ delete static_cast<QVariantPrivateSharedEx<T>*>(d->data.shared);
} else {
v_cast<T>(d)->~T();
}
+
}
+Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler();
+
QT_END_NAMESPACE
#endif // QVARIANT_P_H
diff --git a/src/corelib/kernel/qwineventnotifier_p.cpp b/src/corelib/kernel/qwineventnotifier_p.cpp
index ca49790..208737f 100644
--- a/src/corelib/kernel/qwineventnotifier_p.cpp
+++ b/src/corelib/kernel/qwineventnotifier_p.cpp
@@ -52,8 +52,6 @@ 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
diff --git a/src/corelib/plugin/plugin.pri b/src/corelib/plugin/plugin.pri
index aaecec9..c05ff48 100644
--- a/src/corelib/plugin/plugin.pri
+++ b/src/corelib/plugin/plugin.pri
@@ -22,3 +22,5 @@ win32 {
unix {
SOURCES += plugin/qlibrary_unix.cpp
}
+
+LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp
index ed22d34..0cd6f9c 100644
--- a/src/corelib/plugin/qfactoryloader.cpp
+++ b/src/corelib/plugin/qfactoryloader.cpp
@@ -55,7 +55,7 @@
QT_BEGIN_NAMESPACE
-Q_GLOBAL_STATIC(QList<QFactoryLoader *>, qt_factory_loaders);
+Q_GLOBAL_STATIC(QList<QFactoryLoader *>, qt_factory_loaders)
Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_factoryloader_mutex, (QMutex::Recursive))
@@ -64,6 +64,7 @@ class QFactoryLoaderPrivate : public QObjectPrivate
Q_DECLARE_PUBLIC(QFactoryLoader)
public:
QFactoryLoaderPrivate(){}
+ ~QFactoryLoaderPrivate();
mutable QMutex mutex;
QByteArray iid;
QList<QLibraryPrivate*> libraryList;
@@ -76,6 +77,12 @@ public:
void unloadPath(const QString &path);
};
+QFactoryLoaderPrivate::~QFactoryLoaderPrivate()
+{
+ for (int i = 0; i < libraryList.count(); ++i)
+ libraryList.at(i)->release();
+}
+
QFactoryLoader::QFactoryLoader(const char *iid,
const QString &suffix,
Qt::CaseSensitivity cs)
@@ -89,8 +96,8 @@ QFactoryLoader::QFactoryLoader(const char *iid,
QMutexLocker locker(qt_factoryloader_mutex());
- qt_factory_loaders()->append(this);
update();
+ qt_factory_loaders()->append(this);
}
@@ -197,10 +204,6 @@ void QFactoryLoader::update()
QFactoryLoader::~QFactoryLoader()
{
- Q_D(QFactoryLoader);
- for (int i = 0; i < d->libraryList.count(); ++i)
- d->libraryList.at(i)->release();
-
QMutexLocker locker(qt_factoryloader_mutex());
qt_factory_loaders()->removeAll(this);
}
diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp
index 2e6a9a4..7ebfbfe 100644
--- a/src/corelib/plugin/qlibrary.cpp
+++ b/src/corelib/plugin/qlibrary.cpp
@@ -85,7 +85,7 @@ Q_GLOBAL_STATIC(QMutex, qt_library_mutex)
\reentrant
\brief The QLibrary class loads shared libraries at runtime.
- \mainclass
+
\ingroup plugins
An instance of a QLibrary object operates on a single shared
@@ -98,10 +98,10 @@ Q_GLOBAL_STATIC(QMutex, qt_library_mutex)
Unix), unless the file name has an absolute path. If the file
cannot be found, QLibrary tries the name with different
platform-specific file suffixes, like ".so" on Unix, ".dylib" on
- the Mac, or ".dll" on Windows. This makes it possible to specify
- shared libraries that are only identified by their basename (i.e.
- without their suffix), so the same code will work on different
- operating systems.
+ the Mac, or ".dll" on Windows and Symbian. This makes it possible
+ to specify shared libraries that are only identified by their
+ basename (i.e. without their suffix), so the same code will work
+ on different operating systems.
The most important functions are load() to dynamically load the
library file, isLoaded() to check whether loading was successful,
@@ -120,6 +120,11 @@ Q_GLOBAL_STATIC(QMutex, qt_library_mutex)
linking", which is done by the link step in the build process when
linking an executable against a library.
+ Note: In Symbian resolving symbols using their names is supported
+ only if the library is built as STDDLL. Otherwise ordinals must
+ be used. Also, in Symbian the path of the library is ignored and
+ system default library location is always used.
+
The following code snippet loads a library, resolves the symbol
"mysymbol", and calls the function if everything succeeded. If
something goes wrong, e.g. the library file does not exist or the
@@ -288,7 +293,7 @@ static bool qt_parse_pattern(const char *s, uint *version, bool *debug, QByteArr
}
#endif // QT_NO_PLUGIN_CHECK
-#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(QT_NO_PLUGIN_CHECK)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK)
#if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX)
# define USE_MMAP
@@ -361,7 +366,7 @@ static bool qt_unix_query(const QString &library, uint *version, bool *debug, QB
char *filedata = 0;
ulong fdlen = 0;
-#ifdef USE_MMAP
+# ifdef USE_MMAP
char *mapaddr = 0;
size_t maplen = file.size();
mapaddr = (char *) mmap(mapaddr, maplen, PROT_READ, MAP_PRIVATE, file.handle(), 0);
@@ -378,14 +383,14 @@ static bool qt_unix_query(const QString &library, uint *version, bool *debug, QB
lib->errorString = QLibrary::tr("Could not mmap '%1': %2")
.arg(library)
.arg(qt_error_string());
-#endif // USE_MMAP
+# endif // USE_MMAP
// try reading the data into memory instead
data = file.readAll();
filedata = data.data();
fdlen = data.size();
-#ifdef USE_MMAP
+# ifdef USE_MMAP
}
-#endif // USE_MMAP
+# endif // USE_MMAP
// verify that the pattern is present in the plugin
const char pattern[] = "pattern=QT_PLUGIN_VERIFICATION_DATA";
@@ -398,7 +403,7 @@ static bool qt_unix_query(const QString &library, uint *version, bool *debug, QB
if (!ret && lib)
lib->errorString = QLibrary::tr("Plugin verification data mismatch in '%1'").arg(library);
-#ifdef USE_MMAP
+# ifdef USE_MMAP
if (mapaddr != MAP_FAILED && munmap(mapaddr, maplen) != 0) {
if (qt_debug_component())
qWarning("munmap: %s", qPrintable(qt_error_string(errno)));
@@ -407,16 +412,33 @@ static bool qt_unix_query(const QString &library, uint *version, bool *debug, QB
.arg(library)
.arg( qt_error_string() );
}
-#endif // USE_MMAP
+# endif // USE_MMAP
file.close();
return ret;
}
-#endif // Q_OS_UNIX && !Q_OS_MAC && !defined(QT_NO_PLUGIN_CHECK)
+#endif // Q_OS_UNIX && !Q_OS_MAC && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK)
typedef QMap<QString, QLibraryPrivate*> LibraryMap;
-Q_GLOBAL_STATIC(LibraryMap, libraryMap)
+
+struct LibraryData {
+ LibraryData() : settings(0) { }
+ ~LibraryData() {
+ delete settings;
+ }
+
+ QSettings *settings;
+ LibraryMap libraryMap;
+};
+
+Q_GLOBAL_STATIC(LibraryData, libraryData)
+
+static LibraryMap *libraryMap()
+{
+ LibraryData *data = libraryData();
+ return data ? &data->libraryMap : 0;
+}
QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version)
:pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0), qt_version(0),
@@ -493,6 +515,14 @@ bool QLibraryPrivate::loadPlugin()
}
if (load()) {
instance = (QtPluginInstanceFunction)resolve("qt_plugin_instance");
+#if defined(Q_OS_SYMBIAN)
+ if (!instance) {
+ // If resolving with function name failed (i.e. not STDDLL),
+ // try resolving using known ordinal, which for
+ // qt_plugin_instance function is always "2".
+ instance = (QtPluginInstanceFunction)resolve("2");
+ }
+#endif
return instance;
}
return false;
@@ -517,6 +547,10 @@ bool QLibrary::isLibrary(const QString &fileName)
{
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
return fileName.endsWith(QLatin1String(".dll"));
+#elif defined(Q_OS_SYMBIAN)
+ // Plugin stubs are also considered libraries in Symbian.
+ return (fileName.endsWith(QLatin1String(".dll")) ||
+ fileName.endsWith(QLatin1String(".qtplugin")));
#else
QString completeSuffix = QFileInfo(fileName).completeSuffix();
if (completeSuffix.isEmpty())
@@ -597,10 +631,12 @@ bool QLibraryPrivate::isPlugin(QSettings *settings)
.arg(fileName);
QStringList reg;
#ifndef QT_NO_SETTINGS
- bool madeSettings = false;
if (!settings) {
- settings = new QSettings(QSettings::UserScope, QLatin1String("Trolltech"));
- madeSettings = true;
+ settings = libraryData()->settings;
+ if (!settings) {
+ settings = new QSettings(QSettings::UserScope, QLatin1String("Trolltech"));
+ libraryData()->settings = settings;
+ }
}
reg = settings->value(regkey).toStringList();
#endif
@@ -610,7 +646,7 @@ bool QLibraryPrivate::isPlugin(QSettings *settings)
key = reg.at(2).toLatin1();
success = qt_version != 0;
} else {
-#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN)
if (!pHnd) {
// use unix shortcut to avoid loading the library
success = qt_unix_query(fileName, &qt_version, &debug, &key, this);
@@ -623,12 +659,12 @@ bool QLibraryPrivate::isPlugin(QSettings *settings)
#endif
if (!pHnd) {
#ifdef Q_OS_WIN
- QT_WA({
- hTempModule = ::LoadLibraryExW((wchar_t*)QDir::toNativeSeparators(fileName).utf16(), 0, DONT_RESOLVE_DLL_REFERENCES);
- } , {
- temporary_load = load_sys();
- });
+ hTempModule = ::LoadLibraryEx((wchar_t*)QDir::toNativeSeparators(fileName).utf16(), 0, DONT_RESOLVE_DLL_REFERENCES);
#else
+# if defined(Q_OS_SYMBIAN)
+ //Guard against accidentally trying to load non-plugin libraries by making sure the stub exists
+ if (fileinfo.exists())
+# endif
temporary_load = load_sys();
#endif
}
@@ -641,14 +677,23 @@ bool QLibraryPrivate::isPlugin(QSettings *settings)
QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = hTempModule
? (QtPluginQueryVerificationDataFunction)
#ifdef Q_OS_WINCE
- ::GetProcAddressW(hTempModule, L"qt_plugin_query_verification_data")
+ ::GetProcAddress(hTempModule, L"qt_plugin_query_verification_data")
#else
::GetProcAddress(hTempModule, "qt_plugin_query_verification_data")
#endif
: (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
#else
- QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction =
- (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
+ QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = NULL;
+# if defined(Q_OS_SYMBIAN)
+ if (temporary_load) {
+ qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
+ // If resolving with function name failed (i.e. not STDDLL), try resolving using known ordinal
+ if (!qtPluginQueryVerificationDataFunction)
+ qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("1");
+ }
+# else
+ qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
+# endif
#endif
if (!qtPluginQueryVerificationDataFunction
@@ -671,19 +716,18 @@ bool QLibraryPrivate::isPlugin(QSettings *settings)
#endif
}
+ // Qt 4.5 compatibility: stl doesn't affect binary compatibility
+ key.replace(" no-stl", "");
+
+#ifndef QT_NO_SETTINGS
QStringList queried;
queried << QString::number(qt_version,16)
<< QString::number((int)debug)
<< QLatin1String(key)
<< lastModified;
-#ifndef QT_NO_SETTINGS
settings->setValue(regkey, queried);
#endif
}
-#ifndef QT_NO_SETTINGS
- if (madeSettings)
- delete settings;
-#endif
if (!success) {
if (errorString.isEmpty()){
@@ -819,6 +863,8 @@ QLibrary::QLibrary(QObject *parent)
QLibrary will automatically look for the file with the appropriate
suffix in accordance with the platform, e.g. ".so" on Unix,
".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
+
+ Note: In Symbian the path portion of the \a fileName is ignored.
*/
QLibrary::QLibrary(const QString& fileName, QObject *parent)
:QObject(parent), d(0), did_load(false)
@@ -830,13 +876,15 @@ QLibrary::QLibrary(const QString& fileName, QObject *parent)
/*!
Constructs a library object with the given \a parent that will
load the library specified by \a fileName and major version number \a verNum.
- Currently, the version number is ignored on Windows.
+ Currently, the version number is ignored on Windows and Symbian.
We recommend omitting the file's suffix in \a fileName, since
QLibrary will automatically look for the file with the appropriate
suffix in accordance with the platform, e.g. ".so" on Unix,
".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
- */
+
+ Note: In Symbian the path portion of the \a fileName is ignored.
+*/
QLibrary::QLibrary(const QString& fileName, int verNum, QObject *parent)
:QObject(parent), d(0), did_load(false)
{
@@ -846,12 +894,14 @@ QLibrary::QLibrary(const QString& fileName, int verNum, QObject *parent)
/*!
Constructs a library object with the given \a parent that will
load the library specified by \a fileName and full version number \a version.
- Currently, the version number is ignored on Windows.
+ Currently, the version number is ignored on Windows and Symbian.
We recommend omitting the file's suffix in \a fileName, since
QLibrary will automatically look for the file with the appropriate
suffix in accordance with the platform, e.g. ".so" on Unix,
".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
+
+ Note: In Symbian the path portion of the \a fileName is ignored.
*/
QLibrary::QLibrary(const QString& fileName, const QString &version, QObject *parent)
:QObject(parent), d(0), did_load(false)
@@ -893,6 +943,8 @@ QLibrary::~QLibrary()
platforms, fileName() will return "libGL.so". If the file name was
originally passed as "/usr/lib/libGL", fileName() will return
"/usr/lib/libGL.so".
+
+ Note: In Symbian the path portion of the \a fileName is ignored.
*/
void QLibrary::setFileName(const QString &fileName)
@@ -920,7 +972,10 @@ QString QLibrary::fileName() const
Sets the fileName property and major version number to \a fileName
and \a versionNumber respectively.
- The \a versionNumber is ignored on Windows.
+ The \a versionNumber is ignored on Windows and Symbian.
+
+ Note: In Symbian the path portion of the \a fileName is ignored.
+
\sa setFileName()
*/
void QLibrary::setFileNameAndVersion(const QString &fileName, int verNum)
@@ -941,7 +996,10 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, int verNum)
Sets the fileName property and full version number to \a fileName
and \a version respectively.
- The \a version parameter is ignored on Windows.
+ The \a version parameter is ignored on Windows and Symbian.
+
+ Note: In Symbian the path portion of the \a fileName is ignored.
+
\sa setFileName()
*/
void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &version)
@@ -977,6 +1035,8 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver
\snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 4
+ Note: In Symbian resolving with symbol names works only if the loaded
+ library was built as STDDLL. Otherwise, the ordinals must be used.
*/
void *QLibrary::resolve(const char *symbol)
{
@@ -996,6 +1056,9 @@ void *QLibrary::resolve(const char *symbol)
The function returns 0 if the symbol could not be resolved or if
the library could not be loaded.
+ Note: In Symbian resolving with symbol names works only if the loaded
+ library was built as STDDLL. Otherwise, the ordinals must be used.
+
\sa resolve()
*/
void *QLibrary::resolve(const QString &fileName, const char *symbol)
@@ -1016,6 +1079,9 @@ void *QLibrary::resolve(const QString &fileName, const char *symbol)
The function returns 0 if the symbol could not be resolved or if
the library could not be loaded.
+ Note: In Symbian resolving with symbol names works only if the loaded
+ library was built as STDDLL. Otherwise, the ordinals must be used.
+
\sa resolve()
*/
void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol)
@@ -1037,6 +1103,9 @@ void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol)
The function returns 0 if the symbol could not be resolved or if
the library could not be loaded.
+ Note: In Symbian resolving with symbol names works only if the loaded
+ library was built as STDDLL. Otherwise, the ordinals must be used.
+
\sa resolve()
*/
void *QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol)
diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp
index 97539fd..8bdf6fc 100644
--- a/src/corelib/plugin/qlibrary_unix.cpp
+++ b/src/corelib/plugin/qlibrary_unix.cpp
@@ -58,7 +58,7 @@
QT_BEGIN_NAMESPACE
-#if !defined(QT_HPUX_LD)
+#if !defined(QT_HPUX_LD) && !defined(Q_OS_VXWORKS)
QT_BEGIN_INCLUDE_NAMESPACE
#include <dlfcn.h>
QT_END_INCLUDE_NAMESPACE
@@ -66,29 +66,46 @@ QT_END_INCLUDE_NAMESPACE
static QString qdlerror()
{
-#if !defined(QT_HPUX_LD)
+#if defined(Q_OS_VXWORKS)
+ const char *err = "VxWorks does not support dynamic libraries.";
+#elif !defined(QT_HPUX_LD)
const char *err = dlerror();
#else
const char *err = strerror(errno);
#endif
- return err ? QLatin1String("(")+QString::fromLocal8Bit(err) + QLatin1String(")"): QString();
+ return err ? QLatin1Char('(') + QString::fromLocal8Bit(err) + QLatin1Char(')'): QString();
}
bool QLibraryPrivate::load_sys()
{
+ QString attempt;
+#if !defined(Q_OS_VXWORKS)
QFileInfo fi(fileName);
+
+#if defined(Q_OS_SYMBIAN)
+ QString path; // In Symbian, always resolve with just the filename
+ QString name;
+
+ // Replace possible ".qtplugin" suffix with ".dll"
+ if (fi.suffix() == QLatin1String("qtplugin"))
+ name = fi.completeBaseName() + QLatin1String(".dll");
+ else
+ name = fi.fileName();
+#else
QString path = fi.path();
QString name = fi.fileName();
if (path == QLatin1String(".") && !fileName.startsWith(path))
path.clear();
else
path += QLatin1Char('/');
-
+#endif
// The first filename we want to attempt to load is the filename as the callee specified.
// Thus, the first attempt we do must be with an empty prefix and empty suffix.
QStringList suffixes(QLatin1String("")), prefixes(QLatin1String(""));
if (pluginState != IsAPlugin) {
+#if !defined(Q_OS_SYMBIAN)
prefixes << QLatin1String("lib");
+#endif
#if defined(Q_OS_HPUX)
// according to
// http://docs.hp.com/en/B2355-90968/linkerdifferencesiapa.htm
@@ -116,6 +133,9 @@ bool QLibraryPrivate::load_sys()
}
#elif defined(Q_OS_AIX)
suffixes << ".a";
+
+#elif defined(Q_OS_SYMBIAN)
+ suffixes << QLatin1String(".dll");
#else
if (!fullVersion.isEmpty()) {
suffixes << QString::fromLatin1(".so.%1").arg(fullVersion);
@@ -153,7 +173,7 @@ bool QLibraryPrivate::load_sys()
else {
#if defined(Q_OS_MAC)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4)
-#endif
+#endif
dlFlags |= RTLD_LOCAL;
}
#endif
@@ -163,7 +183,6 @@ bool QLibraryPrivate::load_sys()
}
#endif
#endif // QT_HPUX_LD
- QString attempt;
bool retry = true;
for(int prefix = 0; retry && !pHnd && prefix < prefixes.size(); prefix++) {
for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) {
@@ -185,6 +204,12 @@ bool QLibraryPrivate::load_sys()
#else
pHnd = dlopen(QFile::encodeName(attempt), dlFlags);
#endif
+
+#if defined(Q_OS_SYMBIAN)
+ // Never try again in symbian, dlopen already handles the library search logic,
+ // and there is only one possible suffix.
+ retry = false;
+#else
if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) {
// We only want to continue if dlopen failed due to that the shared library did not exist.
// However, we are only able to apply this check for absolute filenames (since they are
@@ -192,6 +217,7 @@ bool QLibraryPrivate::load_sys()
// This is all because dlerror is flawed and cannot tell us the reason why it failed.
retry = false;
}
+#endif
}
}
@@ -204,7 +230,8 @@ bool QLibraryPrivate::load_sys()
attempt = str;
}
}
-# endif
+#endif
+#endif // Q_OS_VXWORKS
if (!pHnd) {
errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qdlerror());
}
@@ -217,14 +244,16 @@ bool QLibraryPrivate::load_sys()
bool QLibraryPrivate::unload_sys()
{
-#if defined(QT_HPUX_LD)
+#if !defined(Q_OS_VXWORKS)
+# if defined(QT_HPUX_LD)
if (shl_unload((shl_t)pHnd)) {
-#else
+# else
if (dlclose(pHnd)) {
-#endif
+# endif
errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName).arg(qdlerror());
return false;
}
+#endif
errorString.clear();
return true;
}
@@ -249,6 +278,8 @@ void* QLibraryPrivate::resolve_sys(const char* symbol)
void* address = 0;
if (shl_findsym((shl_t*)&pHnd, symbol, TYPE_UNDEFINED, &address) < 0)
address = 0;
+#elif defined(Q_OS_VXWORKS)
+ void *address = 0;
#else
void* address = dlsym(pHnd, symbol);
#endif
diff --git a/src/corelib/plugin/qlibrary_win.cpp b/src/corelib/plugin/qlibrary_win.cpp
index 57e1263..52212e0 100644
--- a/src/corelib/plugin/qlibrary_win.cpp
+++ b/src/corelib/plugin/qlibrary_win.cpp
@@ -67,30 +67,18 @@ bool QLibraryPrivate::load_sys()
//avoid 'Bad Image' message box
UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
- QT_WA({
- pHnd = LoadLibraryW((TCHAR*)QDir::toNativeSeparators(attempt).utf16());
- } , {
- pHnd = LoadLibraryA(QFile::encodeName(QDir::toNativeSeparators(attempt)).data());
- });
-
+ pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16());
+
if (pluginState != IsAPlugin) {
#if defined(Q_OS_WINCE)
if (!pHnd && ::GetLastError() == ERROR_MOD_NOT_FOUND) {
QString secondAttempt = fileName;
- QT_WA({
- pHnd = LoadLibraryW((TCHAR*)QDir::toNativeSeparators(secondAttempt).utf16());
- } , {
- pHnd = LoadLibraryA(QFile::encodeName(QDir::toNativeSeparators(secondAttempt)).data());
- });
+ pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(secondAttempt).utf16());
}
#endif
if (!pHnd && ::GetLastError() == ERROR_MOD_NOT_FOUND) {
attempt += QLatin1String(".dll");
- QT_WA({
- pHnd = LoadLibraryW((TCHAR*)QDir::toNativeSeparators(attempt).utf16());
- } , {
- pHnd = LoadLibraryA(QFile::encodeName(QDir::toNativeSeparators(attempt)).data());
- });
+ pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16());
}
}
@@ -100,15 +88,11 @@ bool QLibraryPrivate::load_sys()
}
if (pHnd) {
errorString.clear();
- QT_WA({
- TCHAR buffer[MAX_PATH + 1];
- ::GetModuleFileNameW(pHnd, buffer, MAX_PATH);
- attempt = QString::fromUtf16(reinterpret_cast<const ushort *>(&buffer));
- }, {
- char buffer[MAX_PATH + 1];
- ::GetModuleFileNameA(pHnd, buffer, MAX_PATH);
- attempt = QString::fromLocal8Bit(buffer);
- });
+
+ wchar_t buffer[MAX_PATH];
+ ::GetModuleFileName(pHnd, buffer, MAX_PATH);
+ attempt = QString::fromWCharArray(buffer);
+
const QDir dir = QFileInfo(fileName).dir();
const QString realfilename = attempt.mid(attempt.lastIndexOf(QLatin1Char('\\')) + 1);
if (dir.path() == QLatin1String("."))
diff --git a/src/corelib/plugin/qplugin.h b/src/corelib/plugin/qplugin.h
index af02e63..36bb0d1 100644
--- a/src/corelib/plugin/qplugin.h
+++ b/src/corelib/plugin/qplugin.h
@@ -114,7 +114,7 @@ void Q_CORE_EXPORT qRegisterStaticPluginInstanceFunction(QtPluginInstanceFunctio
"pattern=""QT_PLUGIN_VERIFICATION_DATA""\n" \
"version="QT_VERSION_STR"\n" \
"debug="QPLUGIN_DEBUG_STR"\n" \
- "buildkey="QT_BUILD_KEY"\0";
+ "buildkey="QT_BUILD_KEY;
# if defined (Q_OS_WIN32) && defined(Q_CC_BOR)
# define Q_STANDARD_CALL __stdcall
diff --git a/src/corelib/plugin/qplugin.qdoc b/src/corelib/plugin/qplugin.qdoc
new file mode 100644
index 0000000..17aff62
--- /dev/null
+++ b/src/corelib/plugin/qplugin.qdoc
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \headerfile <QtPlugin>
+ \title Macros for Defining Plugins
+
+ \brief The <QtPlugin> header files defines macros for defining plugins.
+
+ \sa {How to Create Qt Plugins}
+*/
+
+/*!
+ \macro Q_DECLARE_INTERFACE(ClassName, Identifier)
+ \relates <QtPlugin>
+
+ This macro associates the given \a Identifier (a string literal)
+ to the interface class called \a ClassName. The \a Identifier must
+ be unique. For example:
+
+ \snippet examples/tools/plugandpaint/interfaces.h 3
+
+ This macro is normally used right after the class definition for
+ \a ClassName, in a header file. See the
+ \l{tools/plugandpaint}{Plug & Paint} example for details.
+
+ If you want to use Q_DECLARE_INTERFACE with interface classes
+ declared in a namespace then you have to make sure the Q_DECLARE_INTERFACE
+ is not inside a namespace though. For example:
+ \snippet doc/src/snippets/code/doc_src_qplugin.qdoc 0
+
+ \sa Q_INTERFACES(), Q_EXPORT_PLUGIN2(), {How to Create Qt Plugins}
+*/
+
+/*!
+ \macro Q_EXPORT_PLUGIN(ClassName)
+ \relates <QtPlugin>
+ \obsolete
+
+ Use Q_EXPORT_PLUGIN2() instead. This macro is equivalent to
+ Q_EXPORT_PLUGIN2(\a ClassName, \a ClassName).
+*/
+
+/*!
+ \macro Q_EXPORT_PLUGIN2(PluginName, ClassName)
+ \relates <QtPlugin>
+ \since 4.1
+ \keyword Q_EXPORT_PLUGIN2
+
+ This macro exports the plugin class \a ClassName for the plugin specified
+ by \a PluginName. The value of \a PluginName should correspond to the
+ \l{qmake Variable Reference#TARGET}{TARGET} specified in the plugin's
+ project file.
+
+ There should be exactly one occurrence of this macro in the source code
+ for a Qt plugin, and it should be used where the implementation is written
+ rather than in a header file.
+
+ Example:
+
+ \snippet doc/src/snippets/code/doc_src_qplugin.qdoc 1
+
+ See the \l{tools/plugandpaint}{Plug & Paint} example for details.
+
+ \sa Q_DECLARE_INTERFACE(), {How to Create Qt Plugins}
+*/
+
+/*!
+ \macro Q_IMPORT_PLUGIN(PluginName)
+ \relates <QtPlugin>
+
+ This macro imports the plugin named \a PluginName, corresponding
+ to the \l{qmake Variable Reference#TARGET}{TARGET} specified in the
+ plugin's project file.
+
+ Inserting this macro into your application's source code will allow
+ you to make use of a static plugin.
+
+ Example:
+
+ \snippet doc/src/snippets/code/doc_src_qplugin.qdoc 2
+
+ Static plugins must also be included by the linker when your
+ application is built. For Qt's predefined plugins,
+ you can use the \c QTPLUGIN to add
+ the required plugins to your build. For example:
+
+ \snippet doc/src/snippets/code/doc_src_qplugin.qdoc 3
+
+ \sa {Static Plugins}, {How to Create Qt Plugins}, {Using qmake}
+*/
+
+/*!
+ \macro Q_EXPORT_STATIC_PLUGIN(ClassName)
+ \relates <QtPlugin>
+ \internal
+*/
diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp
index 099cf5b..eb963d0 100644
--- a/src/corelib/plugin/qpluginloader.cpp
+++ b/src/corelib/plugin/qpluginloader.cpp
@@ -46,6 +46,7 @@
#include <qfileinfo.h>
#include "qlibrary_p.h"
#include "qdebug.h"
+#include "qdir.h"
#ifndef QT_NO_LIBRARY
@@ -56,7 +57,7 @@ QT_BEGIN_NAMESPACE
\reentrant
\brief The QPluginLoader class loads a plugin at run-time.
- \mainclass
+
\ingroup plugins
QPluginLoader provides access to a \l{How to Create Qt
@@ -116,6 +117,16 @@ QT_BEGIN_NAMESPACE
link to plugins statically. You can use QLibrary if you need to
load dynamic libraries in a statically linked application.
+ \note In Symbian the plugin stub files must be used whenever a
+ path to plugin is needed. For the purposes of loading plugins,
+ the stubs can be considered to have the same name as the actual
+ plugin binary. In practice they have ".qtplugin" extension
+ instead of ".dll", but this difference is handled transparently
+ by QPluginLoader and QLibrary to avoid need for Symbian specific
+ plugin handling in most Qt applications. Plugin stubs are needed
+ because Symbian Platform Security denies all access to the directory
+ where the actual plugin binaries are located.
+
\sa QLibrary, {Plug & Paint Example}
*/
@@ -136,6 +147,8 @@ QPluginLoader::QPluginLoader(QObject *parent)
Unix, - \c .dylib on Mac OS X, and \c .dll on Windows. The suffix
can be verified with QLibrary::isLibrary().
+ Note: In Symbian the \a fileName must point to plugin stub file.
+
\sa setFileName()
*/
QPluginLoader::QPluginLoader(const QString &fileName, QObject *parent)
@@ -170,7 +183,7 @@ QPluginLoader::~QPluginLoader()
The root component, returned by this function, is not deleted when
the QPluginLoader is destroyed. If you want to ensure that the root
component is deleted, you should call unload() as soon you don't
- need to access the core component anymore. When the library is
+ need to access the core component anymore. When the library is
finally unloaded, the root component will automatically be deleted.
The component object is a QObject. Use qobject_cast() to access
@@ -221,9 +234,9 @@ bool QPluginLoader::load()
call will fail, and unloading will only happen when every instance
has called unload().
- Don't try to delete the root component. Instead rely on
+ Don't try to delete the root component. Instead rely on
that unload() will automatically delete it when needed.
-
+
\sa instance(), load()
*/
bool QPluginLoader::unload()
@@ -261,6 +274,8 @@ bool QPluginLoader::isLoaded() const
By default, this property contains an empty string.
+ Note: In Symbian the \a fileName must point to plugin stub file.
+
\sa load()
*/
void QPluginLoader::setFileName(const QString &fileName)
@@ -273,7 +288,42 @@ void QPluginLoader::setFileName(const QString &fileName)
d = 0;
did_load = false;
}
+
+#if defined(Q_OS_SYMBIAN)
+ // In Symbian we actually look for plugin stub, so modify the filename
+ // to make canonicalFilePath find the file, if .dll is specified.
+ QFileInfo fi(fileName);
+
+ if (fi.suffix() == QLatin1String("dll")) {
+ QString stubName = fileName;
+ stubName.chop(3);
+ stubName += QLatin1String("qtplugin");
+ fi = QFileInfo(stubName);
+ }
+
+ QString fn = fi.canonicalFilePath();
+ // If not found directly, check also all the available drives
+ if (!fn.length()) {
+ QString stubPath(fi.fileName().length() ? fi.absoluteFilePath() : QString());
+ if (stubPath.length() > 1) {
+ if (stubPath.at(1).toAscii() == ':')
+ stubPath.remove(0,2);
+ QFileInfoList driveList(QDir::drives());
+ foreach(const QFileInfo& drive, driveList) {
+ QString testFilePath(drive.absolutePath() + stubPath);
+ testFilePath = QDir::cleanPath(testFilePath);
+ if (QFile::exists(testFilePath)) {
+ fn = testFilePath;
+ break;
+ }
+ }
+ }
+ }
+
+#else
QString fn = QFileInfo(fileName).canonicalFilePath();
+#endif
+
d = QLibraryPrivate::findOrCreate(fn);
d->loadHints = lh;
if (fn.isEmpty())
diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp
index d65a531..2daa784 100644
--- a/src/corelib/plugin/quuid.cpp
+++ b/src/corelib/plugin/quuid.cpp
@@ -50,7 +50,6 @@ QT_BEGIN_NAMESPACE
\brief The QUuid class stores a Universally Unique Identifier (UUID).
\reentrant
- \ingroup misc
Using \e{U}niversally \e{U}nique \e{ID}entifiers (UUID) is a
standard way to uniquely identify entities in a distributed
@@ -405,7 +404,7 @@ QDataStream &operator>>(QDataStream &s, QUuid &id)
}
return s;
}
-#endif
+#endif // QT_NO_DATASTREAM
/*!
Returns true if this is the null UUID
@@ -558,7 +557,7 @@ bool QUuid::operator>(const QUuid &other) const
\sa variant(), version()
*/
-#if defined(Q_OS_WIN32)
+#if defined(Q_OS_WIN32) && ! defined(Q_CC_MWERKS)
QT_BEGIN_INCLUDE_NAMESPACE
#include <objbase.h> // For CoCreateGuid
diff --git a/src/corelib/statemachine/qabstractstate.cpp b/src/corelib/statemachine/qabstractstate.cpp
new file mode 100644
index 0000000..3760833
--- /dev/null
+++ b/src/corelib/statemachine/qabstractstate.cpp
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractstate.h"
+
+#ifndef QT_NO_STATEMACHINE
+
+#include "qabstractstate_p.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractState
+
+ \brief The QAbstractState class is the base class of states of a QStateMachine.
+
+ \since 4.6
+ \ingroup statemachine
+
+ The QAbstractState class is the abstract base class of states that are part
+ of a QStateMachine. It defines the interface that all state objects have in
+ common. QAbstractState is part of \l{The State Machine Framework}.
+
+ The entered() signal is emitted when the state has been entered. The
+ exited() signal is emitted when the state has been exited.
+
+ The parentState() function returns the state's parent state. The machine()
+ function returns the state machine that the state is part of.
+
+ \section1 Subclassing
+
+ The onEntry() function is called when the state is entered; reimplement this
+ function to perform custom processing when the state is entered.
+
+ The onExit() function is called when the state is exited; reimplement this
+ function to perform custom processing when the state is exited.
+*/
+
+QAbstractStatePrivate::QAbstractStatePrivate()
+{
+}
+
+QAbstractStatePrivate *QAbstractStatePrivate::get(QAbstractState *q)
+{
+ return q->d_func();
+}
+
+QStateMachine *QAbstractStatePrivate::machine() const
+{
+ QObject *par = parent;
+ while (par != 0) {
+ if (QStateMachine *mach = qobject_cast<QStateMachine*>(par))
+ return mach;
+ par = par->parent();
+ }
+ return 0;
+}
+
+void QAbstractStatePrivate::callOnEntry(QEvent *e)
+{
+ Q_Q(QAbstractState);
+ q->onEntry(e);
+}
+
+void QAbstractStatePrivate::callOnExit(QEvent *e)
+{
+ Q_Q(QAbstractState);
+ q->onExit(e);
+}
+
+void QAbstractStatePrivate::emitEntered()
+{
+ Q_Q(QAbstractState);
+ emit q->entered();
+}
+
+void QAbstractStatePrivate::emitExited()
+{
+ Q_Q(QAbstractState);
+ emit q->exited();
+}
+
+/*!
+ Constructs a new state with the given \a parent state.
+*/
+QAbstractState::QAbstractState(QState *parent)
+ : QObject(*new QAbstractStatePrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QAbstractState::QAbstractState(QAbstractStatePrivate &dd, QState *parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
+ Destroys this state.
+*/
+QAbstractState::~QAbstractState()
+{
+}
+
+/*!
+ Returns this state's parent state, or 0 if the state has no parent state.
+*/
+QState *QAbstractState::parentState() const
+{
+ return qobject_cast<QState*>(parent());
+}
+
+/*!
+ Returns the state machine that this state is part of, or 0 if the state is
+ not part of a state machine.
+*/
+QStateMachine *QAbstractState::machine() const
+{
+ Q_D(const QAbstractState);
+ return d->machine();
+}
+
+/*!
+ \fn QAbstractState::onExit(QEvent *event)
+
+ This function is called when the state is exited. The given \a event is what
+ caused the state to be exited. Reimplement this function to perform custom
+ processing when the state is exited.
+*/
+
+/*!
+ \fn QAbstractState::onEntry(QEvent *event)
+
+ This function is called when the state is entered. The given \a event is
+ what caused the state to be entered. Reimplement this function to perform
+ custom processing when the state is entered.
+*/
+
+/*!
+ \fn QAbstractState::entered()
+
+ This signal is emitted when the state has been entered (after onEntry() has
+ been called).
+*/
+
+/*!
+ \fn QAbstractState::exited()
+
+ This signal is emitted when the state has been exited (after onExit() has
+ been called).
+*/
+
+/*!
+ \reimp
+*/
+bool QAbstractState::event(QEvent *e)
+{
+ return QObject::event(e);
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_STATEMACHINE
diff --git a/src/corelib/statemachine/qabstractstate.h b/src/corelib/statemachine/qabstractstate.h
new file mode 100644
index 0000000..b0903b5
--- /dev/null
+++ b/src/corelib/statemachine/qabstractstate.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSTATE_H
+#define QABSTRACTSTATE_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_STATEMACHINE
+
+class QState;
+class QStateMachine;
+
+class QAbstractStatePrivate;
+class Q_CORE_EXPORT QAbstractState : public QObject
+{
+ Q_OBJECT
+public:
+ ~QAbstractState();
+
+ QState *parentState() const;
+ QStateMachine *machine() const;
+
+Q_SIGNALS:
+#if !defined(Q_MOC_RUN) && !defined(qdoc)
+private: // can only be emitted by QAbstractState
+#endif
+ void entered();
+ void exited();
+
+protected:
+ QAbstractState(QState *parent = 0);
+
+ virtual void onEntry(QEvent *event) = 0;
+ virtual void onExit(QEvent *event) = 0;
+
+ bool event(QEvent *e);
+
+protected:
+ QAbstractState(QAbstractStatePrivate &dd, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QAbstractState)
+ Q_DECLARE_PRIVATE(QAbstractState)
+};
+
+#endif //QT_NO_STATEMACHINE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qabstractstate_p.h b/src/corelib/statemachine/qabstractstate_p.h
new file mode 100644
index 0000000..84a561d
--- /dev/null
+++ b/src/corelib/statemachine/qabstractstate_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSTATE_P_H
+#define QABSTRACTSTATE_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 <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QStateMachine;
+
+class QAbstractState;
+class QAbstractStatePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractState)
+
+public:
+ QAbstractStatePrivate();
+
+ static QAbstractStatePrivate *get(QAbstractState *q);
+
+ QStateMachine *machine() const;
+
+ void callOnEntry(QEvent *e);
+ void callOnExit(QEvent *e);
+
+ void emitEntered();
+ void emitExited();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp
new file mode 100644
index 0000000..fe237f7
--- /dev/null
+++ b/src/corelib/statemachine/qabstracttransition.cpp
@@ -0,0 +1,331 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstracttransition.h"
+
+#ifndef QT_NO_STATEMACHINE
+
+#include "qabstracttransition_p.h"
+#include "qabstractstate.h"
+#include "qstate.h"
+#include "qstatemachine.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractTransition
+
+ \brief The QAbstractTransition class is the base class of transitions between QAbstractState objects.
+
+ \since 4.6
+ \ingroup statemachine
+
+ The QAbstractTransition class is the abstract base class of transitions
+ between states (QAbstractState objects) of a
+ QStateMachine. QAbstractTransition is part of \l{The State Machine
+ Framework}.
+
+ The sourceState() function returns the source of the transition. The
+ targetStates() function returns the targets of the transition. The machine()
+ function returns the state machine that the transition is part of.
+
+ The triggered() signal is emitted when the transition has been triggered.
+
+ Transitions can cause animations to be played. Use the addAnimation()
+ function to add an animation to the transition.
+
+ \section1 Subclassing
+
+ The eventTest() function is called by the state machine to determine whether
+ an event should trigger the transition. In your reimplementation you
+ typically check the event type and cast the event object to the proper type,
+ and check that one or more properties of the event meet your criteria.
+
+ The onTransition() function is called when the transition is triggered;
+ reimplement this function to perform custom processing for the transition.
+*/
+
+/*!
+ \property QAbstractTransition::sourceState
+
+ \brief the source state (parent) of this transition
+*/
+
+/*!
+ \property QAbstractTransition::targetState
+
+ \brief the target state of this transition
+*/
+
+/*!
+ \property QAbstractTransition::targetStates
+
+ \brief the target states of this transition
+
+ If multiple states are specified, all must be descendants of the same
+ parallel group state.
+*/
+
+QAbstractTransitionPrivate::QAbstractTransitionPrivate()
+{
+}
+
+QAbstractTransitionPrivate *QAbstractTransitionPrivate::get(QAbstractTransition *q)
+{
+ return q->d_func();
+}
+
+QStateMachine *QAbstractTransitionPrivate::machine() const
+{
+ QState *source = sourceState();
+ if (!source)
+ return 0;
+ return source->machine();
+}
+
+bool QAbstractTransitionPrivate::callEventTest(QEvent *e)
+{
+ Q_Q(QAbstractTransition);
+ return q->eventTest(e);
+}
+
+void QAbstractTransitionPrivate::callOnTransition(QEvent *e)
+{
+ Q_Q(QAbstractTransition);
+ q->onTransition(e);
+}
+
+QState *QAbstractTransitionPrivate::sourceState() const
+{
+ return qobject_cast<QState*>(parent);
+}
+
+void QAbstractTransitionPrivate::emitTriggered()
+{
+ Q_Q(QAbstractTransition);
+ emit q->triggered();
+}
+
+/*!
+ Constructs a new QAbstractTransition object with the given \a sourceState.
+*/
+QAbstractTransition::QAbstractTransition(QState *sourceState)
+ : QObject(*new QAbstractTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ \internal
+*/
+QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd,
+ QState *parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
+ Destroys this transition.
+*/
+QAbstractTransition::~QAbstractTransition()
+{
+}
+
+/*!
+ Returns the source state of this transition, or 0 if this transition has no
+ source state.
+*/
+QState *QAbstractTransition::sourceState() const
+{
+ Q_D(const QAbstractTransition);
+ return d->sourceState();
+}
+
+/*!
+ Returns the target state of this transition, or 0 if the transition has no
+ target.
+*/
+QAbstractState *QAbstractTransition::targetState() const
+{
+ Q_D(const QAbstractTransition);
+ if (d->targetStates.isEmpty())
+ return 0;
+ return d->targetStates.first();
+}
+
+/*!
+ Sets the \a target state of this transition.
+*/
+void QAbstractTransition::setTargetState(QAbstractState* target)
+{
+ Q_D(QAbstractTransition);
+ if (!target)
+ d->targetStates.clear();
+ else
+ setTargetStates(QList<QAbstractState*>() << target);
+}
+
+/*!
+ Returns the target states of this transition, or an empty list if this
+ transition has no target states.
+*/
+QList<QAbstractState*> QAbstractTransition::targetStates() const
+{
+ Q_D(const QAbstractTransition);
+ QList<QAbstractState*> result;
+ for (int i = 0; i < d->targetStates.size(); ++i) {
+ QAbstractState *target = d->targetStates.at(i);
+ if (target)
+ result.append(target);
+ }
+ return result;
+}
+
+/*!
+ Sets the target states of this transition to be the given \a targets.
+*/
+void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets)
+{
+ Q_D(QAbstractTransition);
+
+ for (int i=0; i<targets.size(); ++i) {
+ QAbstractState *target = targets.at(i);
+ if (!target) {
+ qWarning("QAbstractTransition::setTargetStates: target state(s) cannot be null");
+ return;
+ }
+ }
+
+ d->targetStates.clear();
+ for (int i = 0; i < targets.size(); ++i)
+ d->targetStates.append(targets.at(i));
+}
+
+/*!
+ Returns the state machine that this transition is part of, or 0 if the
+ transition is not part of a state machine.
+*/
+QStateMachine *QAbstractTransition::machine() const
+{
+ Q_D(const QAbstractTransition);
+ return d->machine();
+}
+
+#ifndef QT_NO_ANIMATION
+
+/*!
+ Adds the given \a animation to this transition.
+ The transition does not take ownership of the animation.
+
+ \sa removeAnimation(), animations()
+*/
+void QAbstractTransition::addAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QAbstractTransition);
+ if (!animation) {
+ qWarning("QAbstractTransition::addAnimation: cannot add null animation");
+ return;
+ }
+ d->animations.append(animation);
+}
+
+/*!
+ Removes the given \a animation from this transition.
+
+ \sa addAnimation()
+*/
+void QAbstractTransition::removeAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QAbstractTransition);
+ if (!animation) {
+ qWarning("QAbstractTransition::removeAnimation: cannot remove null animation");
+ return;
+ }
+ d->animations.removeOne(animation);
+}
+
+/*!
+ Returns the list of animations associated with this transition, or an empty
+ list if it has no animations.
+
+ \sa addAnimation()
+*/
+QList<QAbstractAnimation*> QAbstractTransition::animations() const
+{
+ Q_D(const QAbstractTransition);
+ return d->animations;
+}
+
+#endif
+
+/*!
+ \fn QAbstractTransition::eventTest(QEvent *event)
+
+ This function is called to determine whether the given \a event should cause
+ this transition to trigger. Reimplement this function and return true if the
+ event should trigger the transition, otherwise return false.
+*/
+
+/*!
+ \fn QAbstractTransition::onTransition(QEvent *event)
+
+ This function is called when the transition is triggered. The given \a event
+ is what caused the transition to trigger. Reimplement this function to
+ perform custom processing when the transition is triggered.
+*/
+
+/*!
+ \fn QAbstractTransition::triggered()
+
+ This signal is emitted when the transition has been triggered (after
+ onTransition() has been called).
+*/
+
+/*!
+ \reimp
+*/
+bool QAbstractTransition::event(QEvent *e)
+{
+ return QObject::event(e);
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_STATEMACHINE
diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h
new file mode 100644
index 0000000..43f6c34
--- /dev/null
+++ b/src/corelib/statemachine/qabstracttransition.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTTRANSITION_H
+#define QABSTRACTTRANSITION_H
+
+#include <QtCore/qobject.h>
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_STATEMACHINE
+
+class QEvent;
+class QAbstractState;
+class QState;
+class QStateMachine;
+
+#ifndef QT_NO_ANIMATION
+class QAbstractAnimation;
+#endif
+
+class QAbstractTransitionPrivate;
+class Q_CORE_EXPORT QAbstractTransition : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QState* sourceState READ sourceState)
+ Q_PROPERTY(QAbstractState* targetState READ targetState WRITE setTargetState)
+ Q_PROPERTY(QList<QAbstractState*> targetStates READ targetStates WRITE setTargetStates)
+public:
+ QAbstractTransition(QState *sourceState = 0);
+ virtual ~QAbstractTransition();
+
+ QState *sourceState() const;
+ QAbstractState *targetState() const;
+ void setTargetState(QAbstractState* target);
+ QList<QAbstractState*> targetStates() const;
+ void setTargetStates(const QList<QAbstractState*> &targets);
+
+ QStateMachine *machine() const;
+
+#ifndef QT_NO_ANIMATION
+ void addAnimation(QAbstractAnimation *animation);
+ void removeAnimation(QAbstractAnimation *animation);
+ QList<QAbstractAnimation*> animations() const;
+#endif
+
+Q_SIGNALS:
+#if !defined(Q_MOC_RUN) && !defined(qdoc)
+private: // can only be emitted by QAbstractTransition
+#endif
+ void triggered();
+
+protected:
+ virtual bool eventTest(QEvent *event) = 0;
+
+ virtual void onTransition(QEvent *event) = 0;
+
+ bool event(QEvent *e);
+
+protected:
+ QAbstractTransition(QAbstractTransitionPrivate &dd, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QAbstractTransition)
+ Q_DECLARE_PRIVATE(QAbstractTransition)
+};
+
+#endif //QT_NO_STATEMACHINE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qabstracttransition_p.h b/src/corelib/statemachine/qabstracttransition_p.h
new file mode 100644
index 0000000..33e4474
--- /dev/null
+++ b/src/corelib/statemachine/qabstracttransition_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTTRANSITION_P_H
+#define QABSTRACTTRANSITION_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 <private/qobject_p.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractState;
+class QState;
+class QStateMachine;
+
+class QAbstractTransition;
+class Q_CORE_EXPORT QAbstractTransitionPrivate
+ : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractTransition)
+public:
+ QAbstractTransitionPrivate();
+
+ static QAbstractTransitionPrivate *get(QAbstractTransition *q);
+
+ bool callEventTest(QEvent *e);
+ virtual void callOnTransition(QEvent *e);
+ QState *sourceState() const;
+ QStateMachine *machine() const;
+ void emitTriggered();
+
+ QList<QPointer<QAbstractState> > targetStates;
+
+#ifndef QT_NO_ANIMATION
+ QList<QAbstractAnimation*> animations;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qeventtransition.cpp b/src/corelib/statemachine/qeventtransition.cpp
new file mode 100644
index 0000000..89dabde
--- /dev/null
+++ b/src/corelib/statemachine/qeventtransition.cpp
@@ -0,0 +1,260 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeventtransition.h"
+
+#ifndef QT_NO_STATEMACHINE
+
+#include "qeventtransition_p.h"
+#include "qwrappedevent.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QEventTransition
+
+ \brief The QEventTransition class provides a QObject-specific transition for Qt events.
+
+ \since 4.6
+ \ingroup statemachine
+
+ A QEventTransition object binds an event to a particular QObject.
+ QEventTransition is part of \l{The State Machine Framework}.
+
+ Example:
+
+ \code
+ QPushButton *button = ...;
+ QState *s1 = ...;
+ QState *s2 = ...;
+ // If in s1 and the button receives an Enter event, transition to s2
+ QEventTransition *enterTransition = new QEventTransition(button, QEvent::Enter);
+ enterTransition->setTargetState(s2);
+ s1->addTransition(enterTransition);
+ // If in s2 and the button receives an Exit event, transition back to s1
+ QEventTransition *leaveTransition = new QEventTransition(button, QEvent::Leave);
+ leaveTransition->setTargetState(s1);
+ s2->addTransition(leaveTransition);
+ \endcode
+
+ \section1 Subclassing
+
+ When reimplementing the eventTest() function, you should first call the base
+ implementation to verify that the event is a QWrappedEvent for the proper
+ object and event type. You may then cast the event to a QWrappedEvent and
+ get the original event by calling QWrappedEvent::event(), and perform
+ additional checks on that object.
+
+ \sa QState::addTransition()
+*/
+
+/*!
+ \property QEventTransition::eventSource
+
+ \brief the event source that this event transition is associated with
+*/
+
+/*!
+ \property QEventTransition::eventType
+
+ \brief the type of event that this event transition is associated with
+*/
+QEventTransitionPrivate::QEventTransitionPrivate()
+{
+ object = 0;
+ eventType = QEvent::None;
+ registered = false;
+}
+
+QEventTransitionPrivate *QEventTransitionPrivate::get(QEventTransition *q)
+{
+ return q->d_func();
+}
+
+void QEventTransitionPrivate::unregister()
+{
+ Q_Q(QEventTransition);
+ if (!registered || !machine())
+ return;
+ QStateMachinePrivate::get(machine())->unregisterEventTransition(q);
+}
+
+void QEventTransitionPrivate::maybeRegister()
+{
+ Q_Q(QEventTransition);
+ if (!machine() || !machine()->configuration().contains(sourceState()))
+ return;
+ QStateMachinePrivate::get(machine())->registerEventTransition(q);
+}
+
+/*!
+ Constructs a new QEventTransition object with the given \a sourceState.
+*/
+QEventTransition::QEventTransition(QState *sourceState)
+ : QAbstractTransition(*new QEventTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ Constructs a new QEventTransition object associated with events of the given
+ \a type for the given \a object, and with the given \a sourceState.
+*/
+QEventTransition::QEventTransition(QObject *object, QEvent::Type type,
+ QState *sourceState)
+ : QAbstractTransition(*new QEventTransitionPrivate, sourceState)
+{
+ Q_D(QEventTransition);
+ d->registered = false;
+ d->object = object;
+ d->eventType = type;
+}
+
+/*!
+ \internal
+*/
+QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QState *parent)
+ : QAbstractTransition(dd, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QObject *object,
+ QEvent::Type type, QState *parent)
+ : QAbstractTransition(dd, parent)
+{
+ Q_D(QEventTransition);
+ d->registered = false;
+ d->object = object;
+ d->eventType = type;
+}
+
+/*!
+ Destroys this QObject event transition.
+*/
+QEventTransition::~QEventTransition()
+{
+}
+
+/*!
+ Returns the event type that this event transition is associated with.
+*/
+QEvent::Type QEventTransition::eventType() const
+{
+ Q_D(const QEventTransition);
+ return d->eventType;
+}
+
+/*!
+ Sets the event \a type that this event transition is associated with.
+*/
+void QEventTransition::setEventType(QEvent::Type type)
+{
+ Q_D(QEventTransition);
+ if (d->eventType == type)
+ return;
+ d->unregister();
+ d->eventType = type;
+ d->maybeRegister();
+}
+
+/*!
+ Returns the event source associated with this event transition.
+*/
+QObject *QEventTransition::eventSource() const
+{
+ Q_D(const QEventTransition);
+ return d->object;
+}
+
+/*!
+ Sets the event source associated with this event transition to be the given
+ \a object.
+*/
+void QEventTransition::setEventSource(QObject *object)
+{
+ Q_D(QEventTransition);
+ if (d->object == object)
+ return;
+ d->unregister();
+ d->object = object;
+ d->maybeRegister();
+}
+
+/*!
+ \reimp
+*/
+bool QEventTransition::eventTest(QEvent *event)
+{
+ Q_D(const QEventTransition);
+ if (event->type() == QEvent::Wrapped) {
+ QWrappedEvent *we = static_cast<QWrappedEvent*>(event);
+ return (we->object() == d->object)
+ && (we->event()->type() == d->eventType);
+ }
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QEventTransition::onTransition(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+bool QEventTransition::event(QEvent *e)
+{
+ return QAbstractTransition::event(e);
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_STATEMACHINE
diff --git a/src/corelib/statemachine/qeventtransition.h b/src/corelib/statemachine/qeventtransition.h
new file mode 100644
index 0000000..941bfa5
--- /dev/null
+++ b/src/corelib/statemachine/qeventtransition.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEVENTTRANSITION_H
+#define QEVENTTRANSITION_H
+
+#include <QtCore/qabstracttransition.h>
+#include <QtCore/qcoreevent.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_STATEMACHINE
+
+class QEventTransitionPrivate;
+class Q_CORE_EXPORT QEventTransition : public QAbstractTransition
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject* eventSource READ eventSource WRITE setEventSource)
+ Q_PROPERTY(QEvent::Type eventType READ eventType WRITE setEventType)
+public:
+ QEventTransition(QState *sourceState = 0);
+ QEventTransition(QObject *object, QEvent::Type type, QState *sourceState = 0);
+ ~QEventTransition();
+
+ QObject *eventSource() const;
+ void setEventSource(QObject *object);
+
+ QEvent::Type eventType() const;
+ void setEventType(QEvent::Type type);
+
+protected:
+ bool eventTest(QEvent *event);
+ void onTransition(QEvent *event);
+
+ bool event(QEvent *e);
+
+protected:
+ QEventTransition(QEventTransitionPrivate &dd, QState *parent);
+ QEventTransition(QEventTransitionPrivate &dd, QObject *object,
+ QEvent::Type type, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QEventTransition)
+ Q_DECLARE_PRIVATE(QEventTransition)
+};
+
+#endif //QT_NO_STATEMACHINE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qeventtransition_p.h b/src/corelib/statemachine/qeventtransition_p.h
new file mode 100644
index 0000000..e145098
--- /dev/null
+++ b/src/corelib/statemachine/qeventtransition_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEVENTTRANSITION_P_H
+#define QEVENTTRANSITION_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 "private/qabstracttransition_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEventTransition;
+class Q_CORE_EXPORT QEventTransitionPrivate : public QAbstractTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QEventTransition)
+public:
+ QEventTransitionPrivate();
+
+ static QEventTransitionPrivate *get(QEventTransition *q);
+
+ void unregister();
+ void maybeRegister();
+
+ bool registered;
+ QObject *object;
+ QEvent::Type eventType;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qfinalstate.cpp b/src/corelib/statemachine/qfinalstate.cpp
new file mode 100644
index 0000000..880b60a
--- /dev/null
+++ b/src/corelib/statemachine/qfinalstate.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfinalstate.h"
+
+#ifndef QT_NO_STATEMACHINE
+
+#include "qabstractstate_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QFinalState
+
+ \brief The QFinalState class provides a final state.
+
+ \since 4.6
+ \ingroup statemachine
+
+ A final state is used to communicate that (part of) a QStateMachine has
+ finished its work. When a final top-level state is entered, the state
+ machine's \l{QStateMachine::finished()}{finished}() signal is emitted. In
+ general, when a final substate (a child of a QState) is entered, the parent
+ state's \l{QState::finished()}{finished}() signal is emitted. QFinalState
+ is part of \l{The State Machine Framework}.
+
+ To use a final state, you create a QFinalState object and add a transition
+ to it from another state. Example:
+
+ \code
+ QPushButton button;
+
+ QStateMachine machine;
+ QState *s1 = new QState();
+ QFinalState *s2 = new QFinalState();
+ s1->addTransition(&button, SIGNAL(clicked()), s2);
+ machine.addState(s1);
+ machine.addState(s2);
+
+ QObject::connect(&machine, SIGNAL(finished()), QApplication::instance(), SLOT(quit()));
+ machine.setInitialState(s1);
+ machine.start();
+ \endcode
+
+ \sa QStateMachine::finished(), QState::finished()
+*/
+
+class QFinalStatePrivate : public QAbstractStatePrivate
+{
+ Q_DECLARE_PUBLIC(QFinalState)
+
+public:
+ QFinalStatePrivate();
+};
+
+QFinalStatePrivate::QFinalStatePrivate()
+{
+}
+
+/*!
+ Constructs a new QFinalState object with the given \a parent state.
+*/
+QFinalState::QFinalState(QState *parent)
+ : QAbstractState(*new QFinalStatePrivate, parent)
+{
+}
+
+/*!
+ Destroys this final state.
+*/
+QFinalState::~QFinalState()
+{
+}
+
+/*!
+ \reimp
+*/
+void QFinalState::onEntry(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QFinalState::onExit(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+bool QFinalState::event(QEvent *e)
+{
+ return QAbstractState::event(e);
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_STATEMACHINE
diff --git a/src/corelib/statemachine/qfinalstate.h b/src/corelib/statemachine/qfinalstate.h
new file mode 100644
index 0000000..f7394b3
--- /dev/null
+++ b/src/corelib/statemachine/qfinalstate.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFINALSTATE_H
+#define QFINALSTATE_H
+
+#include <QtCore/qabstractstate.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_STATEMACHINE
+
+class QFinalStatePrivate;
+class Q_CORE_EXPORT QFinalState : public QAbstractState
+{
+ Q_OBJECT
+public:
+ QFinalState(QState *parent = 0);
+ ~QFinalState();
+
+protected:
+ void onEntry(QEvent *event);
+ void onExit(QEvent *event);
+
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QFinalState)
+ Q_DECLARE_PRIVATE(QFinalState)
+};
+
+#endif //QT_NO_STATEMACHINE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp
new file mode 100644
index 0000000..04987f7
--- /dev/null
+++ b/src/corelib/statemachine/qhistorystate.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhistorystate.h"
+
+#ifndef QT_NO_STATEMACHINE
+
+#include "qhistorystate_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QHistoryState
+
+ \brief The QHistoryState class provides a means of returning to a previously active substate.
+
+ \since 4.6
+ \ingroup statemachine
+
+ A history state is a pseudo-state that represents the child state that the
+ parent state was in the last time the parent state was exited. A transition
+ with a history state as its target is in fact a transition to one of the
+ other child states of the parent state. QHistoryState is part of \l{The
+ State Machine Framework}.
+
+ Use the setDefaultState() function to set the state that should be entered
+ if the parent state has never been entered. Example:
+
+ \code
+ QStateMachine machine;
+
+ QState *s1 = new QState();
+ QState *s11 = new QState(s1);
+ QState *s12 = new QState(s1);
+
+ QHistoryState *s1h = new QHistoryState(s1);
+ s1h->setDefaultState(s11);
+
+ machine.addState(s1);
+
+ QState *s2 = new QState();
+ machine.addState(s2);
+
+ QPushButton *button = new QPushButton();
+ // Clicking the button will cause the state machine to enter the child state
+ // that s1 was in the last time s1 was exited, or the history state's default
+ // state if s1 has never been entered.
+ s1->addTransition(button, SIGNAL(clicked()), s1h);
+ \endcode
+
+ By default a history state is shallow, meaning that it won't remember nested
+ states. This can be configured through the historyType property.
+*/
+
+/*!
+ \property QHistoryState::defaultState
+
+ \brief the default state of this history state
+*/
+
+/*!
+ \property QHistoryState::historyType
+
+ \brief the type of history that this history state records
+
+ The default value of this property is QHistoryState::ShallowHistory.
+*/
+
+/*!
+ \enum QHistoryState::HistoryType
+
+ This enum specifies the type of history that a QHistoryState records.
+
+ \value ShallowHistory Only the immediate child states of the parent state
+ are recorded. In this case a transition with the history state as its
+ target will end up in the immediate child state that the parent was in the
+ last time it was exited. This is the default.
+
+ \value DeepHistory Nested states are recorded. In this case a transition
+ with the history state as its target will end up in the most deeply nested
+ descendant state the parent was in the last time it was exited.
+*/
+
+QHistoryStatePrivate::QHistoryStatePrivate()
+ : defaultState(0), historyType(QHistoryState::ShallowHistory)
+{
+}
+
+QHistoryStatePrivate *QHistoryStatePrivate::get(QHistoryState *q)
+{
+ return q->d_func();
+}
+
+/*!
+ Constructs a new shallow history state with the given \a parent state.
+*/
+QHistoryState::QHistoryState(QState *parent)
+ : QAbstractState(*new QHistoryStatePrivate, parent)
+{
+}
+/*!
+ Constructs a new history state of the given \a type, with the given \a
+ parent state.
+*/
+QHistoryState::QHistoryState(HistoryType type, QState *parent)
+ : QAbstractState(*new QHistoryStatePrivate, parent)
+{
+ Q_D(QHistoryState);
+ d->historyType = type;
+}
+
+/*!
+ Destroys this history state.
+*/
+QHistoryState::~QHistoryState()
+{
+}
+
+/*!
+ Returns this history state's default state. The default state indicates the
+ state to transition to if the parent state has never been entered before.
+*/
+QAbstractState *QHistoryState::defaultState() const
+{
+ Q_D(const QHistoryState);
+ return d->defaultState;
+}
+
+/*!
+ Sets this history state's default state to be the given \a state.
+ \a state must be a sibling of this history state.
+*/
+void QHistoryState::setDefaultState(QAbstractState *state)
+{
+ Q_D(QHistoryState);
+ if (state && state->parentState() != parentState()) {
+ qWarning("QHistoryState::setDefaultState: state %p does not belong "
+ "to this history state's group (%p)", state, parentState());
+ return;
+ }
+ d->defaultState = state;
+}
+
+/*!
+ Returns the type of history that this history state records.
+*/
+QHistoryState::HistoryType QHistoryState::historyType() const
+{
+ Q_D(const QHistoryState);
+ return d->historyType;
+}
+
+/*!
+ Sets the \a type of history that this history state records.
+*/
+void QHistoryState::setHistoryType(HistoryType type)
+{
+ Q_D(QHistoryState);
+ d->historyType = type;
+}
+
+/*!
+ \reimp
+*/
+void QHistoryState::onEntry(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QHistoryState::onExit(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+bool QHistoryState::event(QEvent *e)
+{
+ return QAbstractState::event(e);
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_STATEMACHINE
diff --git a/src/corelib/statemachine/qhistorystate.h b/src/corelib/statemachine/qhistorystate.h
new file mode 100644
index 0000000..a4cafe2
--- /dev/null
+++ b/src/corelib/statemachine/qhistorystate.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHISTORYSTATE_H
+#define QHISTORYSTATE_H
+
+#include <QtCore/qabstractstate.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_STATEMACHINE
+
+class QHistoryStatePrivate;
+class Q_CORE_EXPORT QHistoryState : public QAbstractState
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractState* defaultState READ defaultState WRITE setDefaultState)
+ Q_PROPERTY(HistoryType historyType READ historyType WRITE setHistoryType)
+ Q_ENUMS(HistoryType)
+public:
+ enum HistoryType {
+ ShallowHistory,
+ DeepHistory
+ };
+
+ QHistoryState(QState *parent = 0);
+ QHistoryState(HistoryType type, QState *parent = 0);
+ ~QHistoryState();
+
+ QAbstractState *defaultState() const;
+ void setDefaultState(QAbstractState *state);
+
+ HistoryType historyType() const;
+ void setHistoryType(HistoryType type);
+
+protected:
+ void onEntry(QEvent *event);
+ void onExit(QEvent *event);
+
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QHistoryState)
+ Q_DECLARE_PRIVATE(QHistoryState)
+};
+
+#endif //QT_NO_STATEMACHINE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qhistorystate_p.h b/src/corelib/statemachine/qhistorystate_p.h
new file mode 100644
index 0000000..02979b1
--- /dev/null
+++ b/src/corelib/statemachine/qhistorystate_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHISTORYSTATE_P_H
+#define QHISTORYSTATE_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 "private/qabstractstate_p.h"
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHistoryState;
+class QHistoryStatePrivate : public QAbstractStatePrivate
+{
+ Q_DECLARE_PUBLIC(QHistoryState)
+
+public:
+ QHistoryStatePrivate();
+
+ static QHistoryStatePrivate *get(QHistoryState *q);
+
+ QAbstractState *defaultState;
+ QHistoryState::HistoryType historyType;
+ QList<QAbstractState*> configuration;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qsignalevent.h b/src/corelib/statemachine/qsignalevent.h
new file mode 100644
index 0000000..de166f4
--- /dev/null
+++ b/src/corelib/statemachine/qsignalevent.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIGNALEVENT_H
+#define QSIGNALEVENT_H
+
+#include <QtCore/qcoreevent.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_STATEMACHINE
+
+class Q_CORE_EXPORT QSignalEvent : public QEvent
+{
+public:
+ QSignalEvent(QObject *sender, int signalIndex,
+ const QList<QVariant> &arguments);
+ ~QSignalEvent();
+
+ inline QObject *sender() const { return m_sender; }
+ inline int signalIndex() const { return m_signalIndex; }
+ inline QList<QVariant> arguments() const { return m_arguments; }
+
+private:
+ QObject *m_sender;
+ int m_signalIndex;
+ QList<QVariant> m_arguments;
+
+ friend class QSignalTransitionPrivate;
+};
+
+#endif //QT_NO_STATEMACHINE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qsignaleventgenerator_p.h b/src/corelib/statemachine/qsignaleventgenerator_p.h
new file mode 100644
index 0000000..419f26c
--- /dev/null
+++ b/src/corelib/statemachine/qsignaleventgenerator_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIGNALEVENTGENERATOR_P_H
+#define QSIGNALEVENTGENERATOR_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/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QStateMachine;
+
+class QSignalEventGenerator : public QObject
+{
+public:
+ QSignalEventGenerator(QStateMachine *parent);
+
+ static const QMetaObject staticMetaObject;
+ virtual const QMetaObject *metaObject() const;
+ virtual void *qt_metacast(const char *);
+ virtual int qt_metacall(QMetaObject::Call, int, void **argv);
+
+private:
+ Q_DISABLE_COPY(QSignalEventGenerator)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp
new file mode 100644
index 0000000..fb28c08
--- /dev/null
+++ b/src/corelib/statemachine/qsignaltransition.cpp
@@ -0,0 +1,267 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsignaltransition.h"
+
+#ifndef QT_NO_STATEMACHINE
+
+#include "qsignaltransition_p.h"
+#include "qsignalevent.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSignalTransition
+
+ \brief The QSignalTransition class provides a transition based on a Qt signal.
+
+ \since 4.6
+ \ingroup statemachine
+
+ Typically you would use the overload of QState::addTransition() that takes a
+ sender and signal as arguments, rather than creating QSignalTransition
+ objects directly. QSignalTransition is part of \l{The State Machine
+ Framework}.
+
+ You can subclass QSignalTransition and reimplement eventTest() to make a
+ signal transition conditional; the event object passed to eventTest() will
+ be a QSignalEvent object. Example:
+
+ \code
+ class CheckedTransition : public QSignalTransition
+ {
+ public:
+ CheckedTransition(QCheckBox *check)
+ : QSignalTransition(check, SIGNAL(stateChanged(int))) {}
+ protected:
+ bool eventTest(QEvent *e) const {
+ if (!QSignalTransition::eventTest(e))
+ return false;
+ QSignalEvent *se = static_cast<QSignalEvent*>(e);
+ return (se->arguments().at(0).toInt() == Qt::Checked);
+ }
+ };
+
+ ...
+
+ QCheckBox *check = new QCheckBox();
+ check->setTristate(true);
+
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+ CheckedTransition *t1 = new CheckedTransition(check);
+ t1->setTargetState(s2);
+ s1->addTransition(t1);
+ \endcode
+*/
+
+/*!
+ \property QSignalTransition::senderObject
+
+ \brief the sender object that this signal transition is associated with
+*/
+
+/*!
+ \property QSignalTransition::signal
+
+ \brief the signal that this signal transition is associated with
+*/
+
+QSignalTransitionPrivate::QSignalTransitionPrivate()
+{
+ sender = 0;
+ signalIndex = -1;
+}
+
+QSignalTransitionPrivate *QSignalTransitionPrivate::get(QSignalTransition *q)
+{
+ return q->d_func();
+}
+
+void QSignalTransitionPrivate::unregister()
+{
+ Q_Q(QSignalTransition);
+ if ((signalIndex == -1) || !machine())
+ return;
+ QStateMachinePrivate::get(machine())->unregisterSignalTransition(q);
+}
+
+void QSignalTransitionPrivate::maybeRegister()
+{
+ Q_Q(QSignalTransition);
+ if (!machine() || !machine()->configuration().contains(sourceState()))
+ return;
+ QStateMachinePrivate::get(machine())->registerSignalTransition(q);
+}
+
+/*!
+ Constructs a new signal transition with the given \a sourceState.
+*/
+QSignalTransition::QSignalTransition(QState *sourceState)
+ : QAbstractTransition(*new QSignalTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ Constructs a new signal transition associated with the given \a signal of
+ the given \a sender, and with the given \a sourceState.
+*/
+QSignalTransition::QSignalTransition(QObject *sender, const char *signal,
+ QState *sourceState)
+ : QAbstractTransition(*new QSignalTransitionPrivate, sourceState)
+{
+ Q_D(QSignalTransition);
+ d->sender = sender;
+ d->signal = signal;
+}
+
+/*!
+ Destroys this signal transition.
+*/
+QSignalTransition::~QSignalTransition()
+{
+}
+
+/*!
+ Returns the sender object associated with this signal transition.
+*/
+QObject *QSignalTransition::senderObject() const
+{
+ Q_D(const QSignalTransition);
+ return d->sender;
+}
+
+/*!
+ Sets the \a sender object associated with this signal transition.
+*/
+void QSignalTransition::setSenderObject(QObject *sender)
+{
+ Q_D(QSignalTransition);
+ if (sender == d->sender)
+ return;
+ d->unregister();
+ d->sender = sender;
+ d->maybeRegister();
+}
+
+/*!
+ Returns the signal associated with this signal transition.
+*/
+QByteArray QSignalTransition::signal() const
+{
+ Q_D(const QSignalTransition);
+ return d->signal;
+}
+
+/*!
+ Sets the \a signal associated with this signal transition.
+*/
+void QSignalTransition::setSignal(const QByteArray &signal)
+{
+ Q_D(QSignalTransition);
+ if (signal == d->signal)
+ return;
+ d->unregister();
+ d->signal = signal;
+ d->maybeRegister();
+}
+
+/*!
+ \reimp
+
+ The \a event is a QSignalEvent object. The default implementation returns
+ true if the event's sender and signal index match this transition, and
+ returns false otherwise.
+*/
+bool QSignalTransition::eventTest(QEvent *event)
+{
+ Q_D(const QSignalTransition);
+ if (event->type() == QEvent::Signal) {
+ if (d->signalIndex == -1)
+ return false;
+ QSignalEvent *se = static_cast<QSignalEvent*>(event);
+ return (se->sender() == d->sender)
+ && (se->signalIndex() == d->signalIndex);
+ }
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QSignalTransition::onTransition(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+bool QSignalTransition::event(QEvent *e)
+{
+ return QAbstractTransition::event(e);
+}
+
+void QSignalTransitionPrivate::callOnTransition(QEvent *e)
+{
+ Q_Q(QSignalTransition);
+
+ QSignalEvent *se = static_cast<QSignalEvent *>(e);
+ int savedSignalIndex;
+ if (e->type() == QEvent::Signal) {
+ savedSignalIndex = se->m_signalIndex;
+ se->m_signalIndex = originalSignalIndex;
+ }
+
+ q->onTransition(e);
+
+ if (e->type() == QEvent::Signal)
+ se->m_signalIndex = savedSignalIndex;
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_STATEMACHINE
diff --git a/src/corelib/statemachine/qsignaltransition.h b/src/corelib/statemachine/qsignaltransition.h
new file mode 100644
index 0000000..416fc26
--- /dev/null
+++ b/src/corelib/statemachine/qsignaltransition.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIGNALTRANSITION_H
+#define QSIGNALTRANSITION_H
+
+#include <QtCore/qabstracttransition.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_STATEMACHINE
+
+class QSignalTransitionPrivate;
+class Q_CORE_EXPORT QSignalTransition : public QAbstractTransition
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject* senderObject READ senderObject WRITE setSenderObject)
+ Q_PROPERTY(QByteArray signal READ signal WRITE setSignal)
+public:
+ QSignalTransition(QState *sourceState = 0);
+ QSignalTransition(QObject *sender, const char *signal,
+ QState *sourceState = 0);
+ ~QSignalTransition();
+
+ QObject *senderObject() const;
+ void setSenderObject(QObject *sender);
+
+ QByteArray signal() const;
+ void setSignal(const QByteArray &signal);
+
+protected:
+ bool eventTest(QEvent *event);
+ void onTransition(QEvent *event);
+
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QSignalTransition)
+ Q_DECLARE_PRIVATE(QSignalTransition)
+};
+
+#endif //QT_NO_STATEMACHINE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qsignaltransition_p.h b/src/corelib/statemachine/qsignaltransition_p.h
new file mode 100644
index 0000000..8d895e2
--- /dev/null
+++ b/src/corelib/statemachine/qsignaltransition_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIGNALTRANSITION_P_H
+#define QSIGNALTRANSITION_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 "private/qabstracttransition_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSignalTransition;
+class QSignalTransitionPrivate : public QAbstractTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QSignalTransition)
+public:
+ QSignalTransitionPrivate();
+
+ static QSignalTransitionPrivate *get(QSignalTransition *q);
+
+ void unregister();
+ void maybeRegister();
+
+ virtual void callOnTransition(QEvent *e);
+
+ QObject *sender;
+ QByteArray signal;
+ int signalIndex;
+ int originalSignalIndex;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp
new file mode 100644
index 0000000..0fdbfd2
--- /dev/null
+++ b/src/corelib/statemachine/qstate.cpp
@@ -0,0 +1,492 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstate.h"
+
+#ifndef QT_NO_STATEMACHINE
+
+#include "qstate_p.h"
+#include "qhistorystate.h"
+#include "qhistorystate_p.h"
+#include "qabstracttransition.h"
+#include "qabstracttransition_p.h"
+#include "qsignaltransition.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QState
+
+ \brief The QState class provides a general-purpose state for QStateMachine.
+
+ \since 4.6
+ \ingroup statemachine
+
+ QState objects can have child states, and can have transitions to other
+ states. QState is part of \l{The State Machine Framework}.
+
+ The addTransition() function adds a transition. The removeTransition()
+ function removes a transition.
+
+ The assignProperty() function is used for defining property assignments that
+ should be performed when a state is entered.
+
+ Top-level states must be passed a QStateMachine object as their parent
+ state, or added to a state machine using QStateMachine::addState().
+
+ \section1 States with Child States
+
+ The childMode property determines how child states are treated. For
+ non-parallel state groups, the setInitialState() function must be called to
+ set the initial state. The child states are mutually exclusive states, and
+ the state machine needs to know which child state to enter when the parent
+ state is the target of a transition.
+
+ The state emits the QState::finished() signal when a final child state
+ (QFinalState) is entered.
+
+ The setErrorState() sets the state's error state. The error state is the
+ state that the state machine will transition to if an error is detected when
+ attempting to enter the state (e.g. because no initial state has been set).
+
+*/
+
+/*!
+ \property QState::initialState
+
+ \brief the initial state of this state (one of its child states)
+*/
+
+/*!
+ \property QState::errorState
+
+ \brief the error state of this state
+*/
+
+/*!
+ \property QState::childMode
+
+ \brief the child mode of this state
+
+ The default value of this property is QState::ExclusiveStates.
+*/
+
+/*!
+ \enum QState::ChildMode
+
+ This enum specifies how a state's child states are treated.
+
+ \value ExclusiveStates The child states are mutually exclusive and an
+ initial state must be set by calling QState::setInitialState().
+
+ \value ParallelStates The child states are parallel. When the parent state
+ is entered, all its child states are entered in parallel.
+*/
+
+QStatePrivate::QStatePrivate()
+ : errorState(0), initialState(0), childMode(QState::ExclusiveStates)
+{
+}
+
+QStatePrivate::~QStatePrivate()
+{
+}
+
+void QStatePrivate::emitFinished()
+{
+ Q_Q(QState);
+ emit q->finished();
+}
+
+void QStatePrivate::emitPolished()
+{
+ Q_Q(QState);
+ emit q->polished();
+}
+
+/*!
+ Constructs a new state with the given \a parent state.
+*/
+QState::QState(QState *parent)
+ : QAbstractState(*new QStatePrivate, parent)
+{
+}
+
+/*!
+ Constructs a new state with the given \a childMode and the given \a parent
+ state.
+*/
+QState::QState(ChildMode childMode, QState *parent)
+ : QAbstractState(*new QStatePrivate, parent)
+{
+ Q_D(QState);
+ d->childMode = childMode;
+}
+
+/*!
+ \internal
+*/
+QState::QState(QStatePrivate &dd, QState *parent)
+ : QAbstractState(dd, parent)
+{
+}
+
+/*!
+ Destroys this state.
+*/
+QState::~QState()
+{
+}
+
+QList<QAbstractState*> QStatePrivate::childStates() const
+{
+ QList<QAbstractState*> result;
+ QList<QObject*>::const_iterator it;
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QAbstractState *s = qobject_cast<QAbstractState*>(*it);
+ if (!s || qobject_cast<QHistoryState*>(s))
+ continue;
+ result.append(s);
+ }
+ return result;
+}
+
+QList<QHistoryState*> QStatePrivate::historyStates() const
+{
+ QList<QHistoryState*> result;
+ QList<QObject*>::const_iterator it;
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QHistoryState *h = qobject_cast<QHistoryState*>(*it);
+ if (h)
+ result.append(h);
+ }
+ return result;
+}
+
+QList<QAbstractTransition*> QStatePrivate::transitions() const
+{
+ QList<QAbstractTransition*> result;
+ QList<QObject*>::const_iterator it;
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QAbstractTransition *t = qobject_cast<QAbstractTransition*>(*it);
+ if (t)
+ result.append(t);
+ }
+ return result;
+}
+
+#ifndef QT_NO_PROPERTIES
+
+/*!
+ Instructs this state to set the property with the given \a name of the given
+ \a object to the given \a value when the state is entered.
+
+ \sa polished()
+*/
+void QState::assignProperty(QObject *object, const char *name,
+ const QVariant &value)
+{
+ Q_D(QState);
+ if (!object) {
+ qWarning("QState::assignProperty: cannot assign property '%s' of null object", name);
+ return;
+ }
+ for (int i = 0; i < d->propertyAssignments.size(); ++i) {
+ QPropertyAssignment &assn = d->propertyAssignments[i];
+ if ((assn.object == object) && (assn.propertyName == name)) {
+ assn.value = value;
+ return;
+ }
+ }
+ d->propertyAssignments.append(QPropertyAssignment(object, name, value));
+}
+
+#endif // QT_NO_PROPERTIES
+
+/*!
+ Returns this state's error state.
+
+ \sa QStateMachine::error()
+*/
+QAbstractState *QState::errorState() const
+{
+ Q_D(const QState);
+ return d->errorState;
+}
+
+/*!
+ Sets this state's error state to be the given \a state. If the error state
+ is not set, or if it is set to 0, the state will inherit its parent's error
+ state recursively. If no error state is set for the state itself or any of
+ its ancestors, an error will cause the machine to stop executing and an error
+ will be printed to the console.
+*/
+void QState::setErrorState(QAbstractState *state)
+{
+ Q_D(QState);
+ if (state != 0 && qobject_cast<QStateMachine*>(state)) {
+ qWarning("QStateMachine::setErrorState: root state cannot be error state");
+ return;
+ }
+ if (state != 0 && (!state->machine() || ((state->machine() != machine()) && !qobject_cast<QStateMachine*>(this)))) {
+ qWarning("QState::setErrorState: error state cannot belong "
+ "to a different state machine");
+ return;
+ }
+
+ d->errorState = state;
+}
+
+/*!
+ Adds the given \a transition. The transition has this state as the source.
+ This state takes ownership of the transition. If the transition is successfully
+ added, the function will return the \a transition pointer. Otherwise it will return null.
+*/
+QAbstractTransition *QState::addTransition(QAbstractTransition *transition)
+{
+ Q_D(QState);
+ if (!transition) {
+ qWarning("QState::addTransition: cannot add null transition");
+ return 0;
+ }
+
+ transition->setParent(this);
+ const QList<QPointer<QAbstractState> > &targets = QAbstractTransitionPrivate::get(transition)->targetStates;
+ for (int i = 0; i < targets.size(); ++i) {
+ QAbstractState *t = targets.at(i);
+ if (!t) {
+ qWarning("QState::addTransition: cannot add transition to null state");
+ return 0;
+ }
+ if ((QAbstractStatePrivate::get(t)->machine() != d->machine())
+ && QAbstractStatePrivate::get(t)->machine() && d->machine()) {
+ qWarning("QState::addTransition: cannot add transition "
+ "to a state in a different state machine");
+ return 0;
+ }
+ }
+ if (machine() != 0 && machine()->configuration().contains(this))
+ QStateMachinePrivate::get(machine())->registerTransitions(this);
+ return transition;
+}
+
+/*!
+ Adds a transition associated with the given \a signal of the given \a sender
+ object, and returns the new QSignalTransition object. The transition has
+ this state as the source, and the given \a target as the target state.
+*/
+QSignalTransition *QState::addTransition(QObject *sender, const char *signal,
+ QAbstractState *target)
+{
+ if (!sender) {
+ qWarning("QState::addTransition: sender cannot be null");
+ return 0;
+ }
+ if (!signal) {
+ qWarning("QState::addTransition: signal cannot be null");
+ return 0;
+ }
+ if (!target) {
+ qWarning("QState::addTransition: cannot add transition to null state");
+ return 0;
+ }
+ int offset = (*signal == '0'+QSIGNAL_CODE) ? 1 : 0;
+ const QMetaObject *meta = sender->metaObject();
+ if (meta->indexOfSignal(signal+offset) == -1) {
+ if (meta->indexOfSignal(QMetaObject::normalizedSignature(signal+offset)) == -1) {
+ qWarning("QState::addTransition: no such signal %s::%s",
+ meta->className(), signal+offset);
+ return 0;
+ }
+ }
+ QSignalTransition *trans = new QSignalTransition(sender, signal);
+ trans->setTargetState(target);
+ addTransition(trans);
+ return trans;
+}
+
+namespace {
+
+// ### Make public?
+class UnconditionalTransition : public QAbstractTransition
+{
+public:
+ UnconditionalTransition(QAbstractState *target)
+ : QAbstractTransition()
+ { setTargetState(target); }
+protected:
+ void onTransition(QEvent *) {}
+ bool eventTest(QEvent *) { return true; }
+};
+
+} // namespace
+
+/*!
+ Adds an unconditional transition from this state to the given \a target
+ state, and returns then new transition object.
+*/
+QAbstractTransition *QState::addTransition(QAbstractState *target)
+{
+ if (!target) {
+ qWarning("QState::addTransition: cannot add transition to null state");
+ return 0;
+ }
+ UnconditionalTransition *trans = new UnconditionalTransition(target);
+ return addTransition(trans);
+}
+
+/*!
+ Removes the given \a transition from this state. The state releases
+ ownership of the transition.
+
+ \sa addTransition()
+*/
+void QState::removeTransition(QAbstractTransition *transition)
+{
+ Q_D(QState);
+ if (!transition) {
+ qWarning("QState::removeTransition: cannot remove null transition");
+ return;
+ }
+ if (transition->sourceState() != this) {
+ qWarning("QState::removeTransition: transition %p's source state (%p)"
+ " is different from this state (%p)",
+ transition, transition->sourceState(), this);
+ return;
+ }
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(d->machine());
+ if (mach)
+ mach->unregisterTransition(transition);
+ transition->setParent(0);
+}
+
+/*!
+ \reimp
+*/
+void QState::onEntry(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QState::onExit(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ Returns this state's initial state, or 0 if the state has no initial state.
+*/
+QAbstractState *QState::initialState() const
+{
+ Q_D(const QState);
+ return d->initialState;
+}
+
+/*!
+ Sets this state's initial state to be the given \a state.
+ \a state has to be a child of this state.
+*/
+void QState::setInitialState(QAbstractState *state)
+{
+ Q_D(QState);
+ if (d->childMode == QState::ParallelStates) {
+ qWarning("QState::setInitialState: ignoring attempt to set initial state "
+ "of parallel state group %p", this);
+ return;
+ }
+ if (state && (state->parentState() != this)) {
+ qWarning("QState::setInitialState: state %p is not a child of this state (%p)",
+ state, this);
+ return;
+ }
+ d->initialState = state;
+}
+
+/*!
+ Returns the child mode of this state.
+*/
+QState::ChildMode QState::childMode() const
+{
+ Q_D(const QState);
+ return d->childMode;
+}
+
+/*!
+ Sets the child \a mode of this state.
+*/
+void QState::setChildMode(ChildMode mode)
+{
+ Q_D(QState);
+ d->childMode = mode;
+}
+
+/*!
+ \reimp
+*/
+bool QState::event(QEvent *e)
+{
+ return QAbstractState::event(e);
+}
+
+/*!
+ \fn QState::finished()
+
+ This signal is emitted when a final child state of this state is entered.
+
+ \sa QFinalState
+*/
+
+/*!
+ \fn QState::polished()
+
+ This signal is emitted when all properties have been assigned their final value.
+
+ \sa QState::assignProperty(), QAbstractTransition::addAnimation()
+*/
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_STATEMACHINE
diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h
new file mode 100644
index 0000000..a8368df
--- /dev/null
+++ b/src/corelib/statemachine/qstate.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATE_H
+#define QSTATE_H
+
+#include <QtCore/qabstractstate.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_STATEMACHINE
+
+class QAbstractTransition;
+class QSignalTransition;
+
+class QStatePrivate;
+class Q_CORE_EXPORT QState : public QAbstractState
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractState* initialState READ initialState WRITE setInitialState)
+ Q_PROPERTY(QAbstractState* errorState READ errorState WRITE setErrorState)
+ Q_PROPERTY(ChildMode childMode READ childMode WRITE setChildMode)
+ Q_ENUMS(ChildMode)
+public:
+ enum ChildMode {
+ ExclusiveStates,
+ ParallelStates
+ };
+
+ QState(QState *parent = 0);
+ QState(ChildMode childMode, QState *parent = 0);
+ ~QState();
+
+ QAbstractState *errorState() const;
+ void setErrorState(QAbstractState *state);
+
+ QAbstractTransition *addTransition(QAbstractTransition *transition);
+ QSignalTransition *addTransition(QObject *sender, const char *signal, QAbstractState *target);
+ QAbstractTransition *addTransition(QAbstractState *target);
+ void removeTransition(QAbstractTransition *transition);
+
+ QAbstractState *initialState() const;
+ void setInitialState(QAbstractState *state);
+
+ ChildMode childMode() const;
+ void setChildMode(ChildMode mode);
+
+#ifndef QT_NO_PROPERTIES
+ void assignProperty(QObject *object, const char *name,
+ const QVariant &value);
+#endif
+
+Q_SIGNALS:
+ void finished();
+ void polished();
+
+protected:
+ void onEntry(QEvent *event);
+ void onExit(QEvent *event);
+
+ bool event(QEvent *e);
+
+protected:
+ QState(QStatePrivate &dd, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QState)
+ Q_DECLARE_PRIVATE(QState)
+};
+
+#endif //QT_NO_STATEMACHINE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qstate_p.h b/src/corelib/statemachine/qstate_p.h
new file mode 100644
index 0000000..42df19d
--- /dev/null
+++ b/src/corelib/statemachine/qstate_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATE_P_H
+#define QSTATE_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 "private/qabstractstate_p.h"
+
+#include <QtCore/qlist.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QPropertyAssignment
+{
+ QPropertyAssignment()
+ : object(0), explicitlySet(true) {}
+ QPropertyAssignment(QObject *o, const QByteArray &n,
+ const QVariant &v, bool es = true)
+ : object(o), propertyName(n), value(v), explicitlySet(es)
+ {}
+ QObject *object;
+ QByteArray propertyName;
+ QVariant value;
+ bool explicitlySet;
+};
+
+class QAbstractTransition;
+class QHistoryState;
+
+class QState;
+class Q_AUTOTEST_EXPORT QStatePrivate : public QAbstractStatePrivate
+{
+ Q_DECLARE_PUBLIC(QState)
+public:
+ QStatePrivate();
+ ~QStatePrivate();
+
+ static QStatePrivate *get(QState *q) { return q ? q->d_func() : 0; }
+ static const QStatePrivate *get(const QState *q) { return q? q->d_func() : 0; }
+
+ QList<QAbstractState*> childStates() const;
+ QList<QHistoryState*> historyStates() const;
+ QList<QAbstractTransition*> transitions() const;
+
+ void emitFinished();
+ void emitPolished();
+
+ QAbstractState *errorState;
+ QAbstractState *initialState;
+ QState::ChildMode childMode;
+
+ QList<QPropertyAssignment> propertyAssignments;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
new file mode 100644
index 0000000..e5bca2c
--- /dev/null
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -0,0 +1,2215 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstatemachine.h"
+
+#ifndef QT_NO_STATEMACHINE
+
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstatemachine_p.h"
+#include "qabstracttransition.h"
+#include "qabstracttransition_p.h"
+#include "qsignaltransition.h"
+#include "qsignaltransition_p.h"
+#include "qsignalevent.h"
+#include "qsignaleventgenerator_p.h"
+#include "qabstractstate.h"
+#include "qabstractstate_p.h"
+#include "qfinalstate.h"
+#include "qhistorystate.h"
+#include "qhistorystate_p.h"
+#include "private/qobject_p.h"
+#include "private/qthread_p.h"
+
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+#include "qeventtransition.h"
+#include "qeventtransition_p.h"
+#include "qwrappedevent.h"
+#endif
+
+#ifndef QT_NO_ANIMATION
+#include "qpropertyanimation.h"
+#include "qanimationgroup.h"
+#include <private/qvariantanimation_p.h>
+#endif
+
+#include <QtCore/qmetaobject.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QStateMachine
+ \reentrant
+
+ \brief The QStateMachine class provides a hierarchical finite state machine.
+
+ \since 4.6
+ \ingroup statemachine
+
+ QStateMachine is based on the concepts and notation of
+ \l{Statecharts: A visual formalism for complex
+ systems}{Statecharts}. QStateMachine is part of \l{The State
+ Machine Framework}.
+
+ A state machine manages a set of states (classes that inherit from
+ QAbstractState) and transitions (descendants of
+ QAbstractTransition) between those states; these states and
+ transitions define a state graph. Once a state graph has been
+ built, the state machine can execute it. QStateMachine's
+ execution algorithm is based on the \l{State Chart XML: State
+ Machine Notation for Control Abstraction}{State Chart XML (SCXML)}
+ algorithm. The framework's \l{The State Machine
+ Framework}{overview} gives several state graphs and the code to
+ build them.
+
+ Use the addState() function to add a top-level state to the state machine.
+ States are removed with the removeState() function. Removing states while
+ the machine is running is discouraged.
+
+ Before the machine can be started, the \l{initialState}{initial
+ state} must be set. The initial state is the state that the
+ machine enters when started. You can then start() the state
+ machine. The started() signal is emitted when the initial state is
+ entered.
+
+ The machine is event driven and keeps its own event loop. Events
+ are posted to the machine through postEvent(). Note that this
+ means that it executes asynchronously, and that it will not
+ progress without a running event loop. You will normally not have
+ to post events to the machine directly as Qt's transitions, e.g.,
+ QEventTransition and its subclasses, handle this. But for custom
+ transitions triggered by events, postEvent() is useful.
+
+ The state machine processes events and takes transitions until a
+ top-level final state is entered; the state machine then emits the
+ finished() signal. You can also stop() the state machine
+ explicitly. The stopped() signal is emitted in this case.
+
+ The following snippet shows a state machine that will finish when a button
+ is clicked:
+
+ \code
+ QPushButton button;
+
+ QStateMachine machine;
+ QState *s1 = new QState();
+ s1->assignProperty(&button, "text", "Click me");
+
+ QFinalState *s2 = new QFinalState();
+ s1->addTransition(&button, SIGNAL(clicked()), s2);
+
+ machine.addState(s1);
+ machine.addState(s2);
+ machine.setInitialState(s1);
+ machine.start();
+ \endcode
+
+ This code example uses QState, which inherits QAbstractState. The
+ QState class provides a state that you can use to set properties
+ and invoke methods on \l{QObject}s when the state is entered or
+ exited. It also contains convenience functions for adding
+ transitions, e.g., \l{QSignalTransition}s as in this example. See
+ the QState class description for further details.
+
+ If an error is encountered, the machine will look for an
+ \l{errorState}{error state}, and if one is available, it will
+ enter this state. The types of errors possible are described by the
+ \l{QStateMachine::}{Error} enum. After the error state is entered,
+ the type of the error can be retrieved with error(). The execution
+ of the state graph will not stop when the error state is entered. If
+ no error state applies to the erroneous state, the machine will stop
+ executing and an error message will be printed to the console.
+
+ \omit This stuff will be moved elsewhere
+This is
+ typically used in conjunction with \l{Signals and Slots}{signals}; the
+ signals determine the flow of the state graph, whereas the states' property
+ assignments and method invocations are the actions.
+
+ The postEvent() function posts an event to the state machine. This is useful
+ when you are using custom events to trigger transitions.
+ \endomit
+
+ \sa QAbstractState, QAbstractTransition, QState, {The State Machine Framework}
+*/
+
+/*!
+ \property QStateMachine::errorString
+
+ \brief the error string of this state machine
+*/
+
+/*!
+ \property QStateMachine::globalRestorePolicy
+
+ \brief the restore policy for states of this state machine.
+
+ The default value of this property is
+ QStateMachine::DoNotRestoreProperties.
+*/
+
+#ifndef QT_NO_ANIMATION
+/*!
+ \property QStateMachine::animationsEnabled
+
+ \brief whether animations are enabled
+
+ The default value of this property is true.
+
+ \sa QAbstractTransition::addAnimation()
+*/
+#endif
+
+// #define QSTATEMACHINE_DEBUG
+
+QStateMachinePrivate::QStateMachinePrivate()
+{
+ state = NotRunning;
+ _startState = 0;
+ processing = false;
+ processingScheduled = false;
+ stop = false;
+ stopProcessingReason = EventQueueEmpty;
+ error = QStateMachine::NoError;
+ globalRestorePolicy = QStateMachine::DoNotRestoreProperties;
+ signalEventGenerator = 0;
+#ifndef QT_NO_ANIMATION
+ animationsEnabled = true;
+#endif
+}
+
+QStateMachinePrivate::~QStateMachinePrivate()
+{
+ qDeleteAll(internalEventQueue);
+ qDeleteAll(externalEventQueue);
+}
+
+QStateMachinePrivate *QStateMachinePrivate::get(QStateMachine *q)
+{
+ if (q)
+ return q->d_func();
+ return 0;
+}
+
+QState *QStateMachinePrivate::rootState() const
+{
+ return const_cast<QStateMachine*>(q_func());
+}
+
+static QEvent *cloneEvent(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::None:
+ return new QEvent(*e);
+ case QEvent::Timer:
+ return new QTimerEvent(*static_cast<QTimerEvent*>(e));
+ default:
+ Q_ASSERT_X(false, "cloneEvent()", "not implemented");
+ break;
+ }
+ return 0;
+}
+
+const QStateMachinePrivate::Handler qt_kernel_statemachine_handler = {
+ cloneEvent
+};
+
+const QStateMachinePrivate::Handler *QStateMachinePrivate::handler = &qt_kernel_statemachine_handler;
+
+Q_CORE_EXPORT const QStateMachinePrivate::Handler *qcoreStateMachineHandler()
+{
+ return &qt_kernel_statemachine_handler;
+}
+
+static int indexOfDescendant(QState *s, QAbstractState *desc)
+{
+ QList<QAbstractState*> childStates = QStatePrivate::get(s)->childStates();
+ for (int i = 0; i < childStates.size(); ++i) {
+ QAbstractState *c = childStates.at(i);
+ if ((c == desc) || QStateMachinePrivate::isDescendantOf(desc, c)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState *s2)
+{
+ if (s1->parent() == s2->parent()) {
+ return s1->children().indexOf(s1)
+ < s2->children().indexOf(s2);
+ } else if (isDescendantOf(s1, s2)) {
+ return false;
+ } else if (isDescendantOf(s2, s1)) {
+ return true;
+ } else {
+ Q_ASSERT(s1->machine() != 0);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
+ QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
+ Q_ASSERT(lca != 0);
+ return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2));
+ }
+}
+
+bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState *s2)
+{
+ if (s1->parent() == s2->parent()) {
+ return s1->children().indexOf(s1)
+ < s2->children().indexOf(s2);
+ } else if (isDescendantOf(s1, s2)) {
+ return true;
+ } else if (isDescendantOf(s2, s1)) {
+ return false;
+ } else {
+ Q_ASSERT(s1->machine() != 0);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
+ QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
+ Q_ASSERT(lca != 0);
+ return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2));
+ }
+}
+
+QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states) const
+{
+ if (states.isEmpty())
+ return 0;
+ QList<QState*> ancestors = properAncestors(states.at(0), rootState()->parentState());
+ for (int i = 0; i < ancestors.size(); ++i) {
+ QState *anc = ancestors.at(i);
+ bool ok = true;
+ for (int j = states.size() - 1; (j > 0) && ok; --j) {
+ const QAbstractState *s = states.at(j);
+ if (!isDescendantOf(s, anc))
+ ok = false;
+ }
+ if (ok)
+ return anc;
+ }
+ return 0;
+}
+
+bool QStateMachinePrivate::isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const
+{
+ QSet<QAbstractTransition*>::const_iterator it;
+ for (it = transitions.constBegin(); it != transitions.constEnd(); ++it) {
+ QAbstractTransition *t = *it;
+ QList<QAbstractState*> lst = t->targetStates();
+ if (!lst.isEmpty()) {
+ lst.prepend(t->sourceState());
+ QAbstractState *lca = findLCA(lst);
+ if (isDescendantOf(s, lca)) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ':' << transitions << "preempts selection of a transition from"
+ << s << "because" << s << "is a descendant of" << lca;
+#endif
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+QSet<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event) const
+{
+ Q_Q(const QStateMachine);
+ QSet<QAbstractTransition*> enabledTransitions;
+ QSet<QAbstractState*>::const_iterator it;
+ const_cast<QStateMachine*>(q)->beginSelectTransitions(event);
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ QAbstractState *state = *it;
+ if (!isAtomic(state))
+ continue;
+ if (isPreempted(state, enabledTransitions))
+ continue;
+ QList<QState*> lst = properAncestors(state, rootState()->parentState());
+ if (QState *grp = qobject_cast<QState*>(state))
+ lst.prepend(grp);
+ bool found = false;
+ for (int j = 0; (j < lst.size()) && !found; ++j) {
+ QState *s = lst.at(j);
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(s)->transitions();
+ for (int k = 0; k < transitions.size(); ++k) {
+ QAbstractTransition *t = transitions.at(k);
+ if (QAbstractTransitionPrivate::get(t)->callEventTest(event)) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": selecting transition" << t;
+#endif
+ enabledTransitions.insert(t);
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ const_cast<QStateMachine*>(q)->endSelectTransitions(event);
+ return enabledTransitions;
+}
+
+void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions)
+{
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ')';
+ qDebug() << q_func() << ": configuration before exiting states:" << configuration;
+#endif
+ QList<QAbstractState*> exitedStates = exitStates(event, enabledTransitions);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": configuration after exiting states:" << configuration;
+#endif
+ executeTransitionContent(event, enabledTransitions);
+ QList<QAbstractState*> enteredStates = enterStates(event, enabledTransitions);
+#ifndef QT_NO_PROPERTIES
+ applyProperties(enabledTransitions, exitedStates, enteredStates);
+#endif
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": configuration after entering states:" << configuration;
+ qDebug() << q_func() << ": end microstep";
+#endif
+}
+
+QList<QAbstractState*> QStateMachinePrivate::exitStates(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions)
+{
+// qDebug() << "exitStates(" << enabledTransitions << ')';
+ QSet<QAbstractState*> statesToExit;
+// QSet<QAbstractState*> statesToSnapshot;
+ for (int i = 0; i < enabledTransitions.size(); ++i) {
+ QAbstractTransition *t = enabledTransitions.at(i);
+ QList<QAbstractState*> lst = t->targetStates();
+ if (lst.isEmpty())
+ continue;
+ lst.prepend(t->sourceState());
+ QAbstractState *lca = findLCA(lst);
+ if (lca == 0) {
+ setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState());
+ lst = pendingErrorStates.toList();
+ lst.prepend(t->sourceState());
+
+ lca = findLCA(lst);
+ Q_ASSERT(lca != 0);
+ }
+
+ {
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ QAbstractState *s = *it;
+ if (isDescendantOf(s, lca))
+ statesToExit.insert(s);
+ }
+ }
+ }
+ QList<QAbstractState*> statesToExit_sorted = statesToExit.toList();
+ qSort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan);
+ for (int i = 0; i < statesToExit_sorted.size(); ++i) {
+ QAbstractState *s = statesToExit_sorted.at(i);
+ if (QState *grp = qobject_cast<QState*>(s)) {
+ QList<QHistoryState*> hlst = QStatePrivate::get(grp)->historyStates();
+ for (int j = 0; j < hlst.size(); ++j) {
+ QHistoryState *h = hlst.at(j);
+ QHistoryStatePrivate::get(h)->configuration.clear();
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ QAbstractState *s0 = *it;
+ if (QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) {
+ if (isAtomic(s0) && isDescendantOf(s0, s))
+ QHistoryStatePrivate::get(h)->configuration.append(s0);
+ } else if (s0->parentState() == s) {
+ QHistoryStatePrivate::get(h)->configuration.append(s0);
+ }
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": recorded" << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow")
+ << "history for" << s << "in" << h << ':' << QHistoryStatePrivate::get(h)->configuration;
+#endif
+ }
+ }
+ }
+ for (int i = 0; i < statesToExit_sorted.size(); ++i) {
+ QAbstractState *s = statesToExit_sorted.at(i);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": exiting" << s;
+#endif
+ QAbstractStatePrivate::get(s)->callOnExit(event);
+ configuration.remove(s);
+ QAbstractStatePrivate::get(s)->emitExited();
+ }
+ return statesToExit_sorted;
+}
+
+void QStateMachinePrivate::executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions)
+{
+ for (int i = 0; i < enabledTransitions.size(); ++i) {
+ QAbstractTransition *t = enabledTransitions.at(i);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": triggering" << t;
+#endif
+ QAbstractTransitionPrivate::get(t)->callOnTransition(event);
+ QAbstractTransitionPrivate::get(t)->emitTriggered();
+ }
+}
+
+QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions)
+{
+#ifdef QSTATEMACHINE_DEBUG
+ Q_Q(QStateMachine);
+#endif
+// qDebug() << "enterStates(" << enabledTransitions << ')';
+ QSet<QAbstractState*> statesToEnter;
+ QSet<QAbstractState*> statesForDefaultEntry;
+
+ if (pendingErrorStates.isEmpty()) {
+ for (int i = 0; i < enabledTransitions.size(); ++i) {
+ QAbstractTransition *t = enabledTransitions.at(i);
+ QList<QAbstractState*> lst = t->targetStates();
+ if (lst.isEmpty())
+ continue;
+ lst.prepend(t->sourceState());
+ QState *lca = findLCA(lst);
+ for (int j = 1; j < lst.size(); ++j) {
+ QAbstractState *s = lst.at(j);
+ addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry);
+ if (isParallel(lca)) {
+ QList<QAbstractState*> lcac = QStatePrivate::get(lca)->childStates();
+ foreach (QAbstractState* child,lcac) {
+ if (!statesToEnter.contains(child))
+ addStatesToEnter(child,lca,statesToEnter,statesForDefaultEntry);
+ }
+ }
+ }
+ }
+ }
+
+ // Did an error occur while selecting transitions? Then we enter the error state.
+ if (!pendingErrorStates.isEmpty()) {
+ statesToEnter.clear();
+ statesToEnter = pendingErrorStates;
+ statesForDefaultEntry = pendingErrorStatesForDefaultEntry;
+ pendingErrorStates.clear();
+ pendingErrorStatesForDefaultEntry.clear();
+ }
+
+ QList<QAbstractState*> statesToEnter_sorted = statesToEnter.toList();
+ qSort(statesToEnter_sorted.begin(), statesToEnter_sorted.end(), stateEntryLessThan);
+
+ for (int i = 0; i < statesToEnter_sorted.size(); ++i) {
+ QAbstractState *s = statesToEnter_sorted.at(i);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": entering" << s;
+#endif
+ configuration.insert(s);
+ registerTransitions(s);
+ QAbstractStatePrivate::get(s)->callOnEntry(event);
+ QAbstractStatePrivate::get(s)->emitEntered();
+ if (statesForDefaultEntry.contains(s)) {
+ // ### executeContent(s.initial.transition.children())
+ }
+ if (isFinal(s)) {
+ QState *parent = s->parentState();
+ if (parent) {
+ if (parent != rootState()) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": emitting finished signal for" << parent;
+#endif
+ QStatePrivate::get(parent)->emitFinished();
+ }
+ QState *grandparent = parent->parentState();
+ if (grandparent && isParallel(grandparent)) {
+ bool allChildStatesFinal = true;
+ QList<QAbstractState*> childStates = QStatePrivate::get(grandparent)->childStates();
+ for (int j = 0; j < childStates.size(); ++j) {
+ QAbstractState *cs = childStates.at(j);
+ if (!isInFinalState(cs)) {
+ allChildStatesFinal = false;
+ break;
+ }
+ }
+ if (allChildStatesFinal && (grandparent != rootState())) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": emitting finished signal for" << grandparent;
+#endif
+ QStatePrivate::get(grandparent)->emitFinished();
+ }
+ }
+ }
+ }
+ }
+ {
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ if (isFinal(*it) && (*it)->parentState() == rootState()) {
+ processing = false;
+ stopProcessingReason = Finished;
+ break;
+ }
+ }
+ }
+// qDebug() << "configuration:" << configuration.toList();
+ return statesToEnter_sorted;
+}
+
+void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry)
+{
+ if (QHistoryState *h = qobject_cast<QHistoryState*>(s)) {
+ QList<QAbstractState*> hconf = QHistoryStatePrivate::get(h)->configuration;
+ if (!hconf.isEmpty()) {
+ for (int k = 0; k < hconf.size(); ++k) {
+ QAbstractState *s0 = hconf.at(k);
+ addStatesToEnter(s0, root, statesToEnter, statesForDefaultEntry);
+ }
+ #ifdef QSTATEMACHINE_DEBUG
+ qDebug() <<q_func() << ": restoring"
+ << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow")
+ << "history from" << s << ':' << hconf;
+ #endif
+ } else {
+ QList<QAbstractState*> hlst;
+ if (QHistoryStatePrivate::get(h)->defaultState)
+ hlst.append(QHistoryStatePrivate::get(h)->defaultState);
+
+ if (hlst.isEmpty()) {
+ setError(QStateMachine::NoDefaultStateInHistoryStateError, h);
+ } else {
+ for (int k = 0; k < hlst.size(); ++k) {
+ QAbstractState *s0 = hlst.at(k);
+ addStatesToEnter(s0, root, statesToEnter, statesForDefaultEntry);
+ }
+ #ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": initial history targets for" << s << ':' << hlst;
+ #endif
+ }
+ }
+ } else {
+ if (s == rootState()) {
+ // Error has already been set by exitStates().
+ Q_ASSERT(error != QStateMachine::NoError);
+ return;
+ }
+ statesToEnter.insert(s);
+ if (isParallel(s)) {
+ QState *grp = qobject_cast<QState*>(s);
+ QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
+ for (int i = 0; i < lst.size(); ++i) {
+ QAbstractState *child = lst.at(i);
+ addStatesToEnter(child, grp, statesToEnter, statesForDefaultEntry);
+ }
+ } else if (isCompound(s)) {
+ statesForDefaultEntry.insert(s);
+ QState *grp = qobject_cast<QState*>(s);
+ QAbstractState *initial = grp->initialState();
+ if (initial != 0) {
+ Q_ASSERT(initial->machine() == q_func());
+ addStatesToEnter(initial, grp, statesToEnter, statesForDefaultEntry);
+ } else {
+ setError(QStateMachine::NoInitialStateError, grp);
+ return;
+ }
+ }
+ QList<QState*> ancs = properAncestors(s, root);
+ for (int i = 0; i < ancs.size(); ++i) {
+ QState *anc = ancs.at(i);
+ if (!anc->parentState())
+ continue;
+ statesToEnter.insert(anc);
+ if (isParallel(anc)) {
+ QList<QAbstractState*> lst = QStatePrivate::get(anc)->childStates();
+ for (int j = 0; j < lst.size(); ++j) {
+ QAbstractState *child = lst.at(j);
+ bool hasDescendantInList = false;
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = statesToEnter.constBegin(); it != statesToEnter.constEnd(); ++it) {
+ if (isDescendantOf(*it, child)) {
+ hasDescendantInList = true;
+ break;
+ }
+ }
+ if (!hasDescendantInList)
+ addStatesToEnter(child, anc, statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+ }
+}
+
+#ifndef QT_NO_PROPERTIES
+
+void QStateMachinePrivate::applyProperties(const QList<QAbstractTransition*> &transitionList,
+ const QList<QAbstractState*> &exitedStates,
+ const QList<QAbstractState*> &enteredStates)
+{
+#ifdef QT_NO_ANIMATION
+ Q_UNUSED(transitionList);
+ Q_UNUSED(exitedStates);
+#else
+ Q_Q(QStateMachine);
+#endif
+ // Process the property assignments of the entered states.
+ QHash<QAbstractState*, QList<QPropertyAssignment> > propertyAssignmentsForState;
+ QHash<RestorableId, QVariant> pendingRestorables = registeredRestorables;
+ for (int i = 0; i < enteredStates.size(); ++i) {
+ QState *s = qobject_cast<QState*>(enteredStates.at(i));
+ if (!s)
+ continue;
+
+ QList<QPropertyAssignment> assignments = QStatePrivate::get(s)->propertyAssignments;
+ for (int j = 0; j < assignments.size(); ++j) {
+ const QPropertyAssignment &assn = assignments.at(j);
+ if (globalRestorePolicy == QStateMachine::RestoreProperties) {
+ registerRestorable(assn.object, assn.propertyName);
+ }
+ pendingRestorables.remove(RestorableId(assn.object, assn.propertyName));
+ propertyAssignmentsForState[s].append(assn);
+ }
+
+ // Remove pending restorables for all parent states to avoid restoring properties
+ // before the state that assigned them is exited. If state does not explicitly
+ // assign a property which is assigned by the parent, it inherits the parent's assignment.
+ QState *parentState = s;
+ while ((parentState = parentState->parentState()) != 0) {
+ assignments = QStatePrivate::get(parentState)->propertyAssignments;
+ for (int j=0; j<assignments.size(); ++j) {
+ const QPropertyAssignment &assn = assignments.at(j);
+ int c = pendingRestorables.remove(RestorableId(assn.object, assn.propertyName));
+ if (c > 0)
+ propertyAssignmentsForState[s].append(assn);
+ }
+ }
+ }
+ if (!pendingRestorables.isEmpty()) {
+ QAbstractState *s;
+ if (!enteredStates.isEmpty())
+ s = enteredStates.last(); // ### handle if parallel
+ else
+ s = 0;
+ propertyAssignmentsForState[s] << restorablesToPropertyList(pendingRestorables);
+ }
+
+#ifndef QT_NO_ANIMATION
+ // Gracefully terminate playing animations for states that are exited.
+ for (int i = 0; i < exitedStates.size(); ++i) {
+ QAbstractState *s = exitedStates.at(i);
+ QList<QAbstractAnimation*> animations = animationsForState.take(s);
+ for (int j = 0; j < animations.size(); ++j) {
+ QAbstractAnimation *anim = animations.at(j);
+ QObject::disconnect(anim, SIGNAL(finished()), q, SLOT(_q_animationFinished()));
+ stateForAnimation.remove(anim);
+
+ // Stop the (top-level) animation.
+ // ### Stopping nested animation has weird behavior.
+ QAbstractAnimation *topLevelAnim = anim;
+ while (QAnimationGroup *group = topLevelAnim->group())
+ topLevelAnim = group;
+ topLevelAnim->stop();
+
+ if (resetAnimationEndValues.contains(anim)) {
+ qobject_cast<QVariantAnimation*>(anim)->setEndValue(QVariant()); // ### generalize
+ resetAnimationEndValues.remove(anim);
+ }
+ QPropertyAssignment assn = propertyForAnimation.take(anim);
+ Q_ASSERT(assn.object != 0);
+ // If there is no property assignment that sets this property,
+ // set the property to its target value.
+ bool found = false;
+ QHash<QAbstractState*, QList<QPropertyAssignment> >::const_iterator it;
+ for (it = propertyAssignmentsForState.constBegin(); it != propertyAssignmentsForState.constEnd(); ++it) {
+ const QList<QPropertyAssignment> &assignments = it.value();
+ for (int k = 0; k < assignments.size(); ++k) {
+ if ((assignments.at(k).object == assn.object)
+ && (assignments.at(k).propertyName == assn.propertyName)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ assn.object->setProperty(assn.propertyName, assn.value);
+ }
+ }
+ }
+
+ // Find the animations to use for the state change.
+ QList<QAbstractAnimation*> selectedAnimations;
+ if (animationsEnabled) {
+ for (int i = 0; i < transitionList.size(); ++i) {
+ QAbstractTransition *transition = transitionList.at(i);
+
+ selectedAnimations << transition->animations();
+ selectedAnimations << defaultAnimationsForSource.values(transition->sourceState());
+
+ QList<QAbstractState *> targetStates = transition->targetStates();
+ for (int j=0; j<targetStates.size(); ++j)
+ selectedAnimations << defaultAnimationsForTarget.values(targetStates.at(j));
+ }
+ selectedAnimations << defaultAnimations;
+ }
+
+ // Initialize animations from property assignments.
+ for (int i = 0; i < selectedAnimations.size(); ++i) {
+ QAbstractAnimation *anim = selectedAnimations.at(i);
+ QHash<QAbstractState*, QList<QPropertyAssignment> >::iterator it;
+ for (it = propertyAssignmentsForState.begin(); it != propertyAssignmentsForState.end(); ) {
+ QList<QPropertyAssignment>::iterator it2;
+ QAbstractState *s = it.key();
+ QList<QPropertyAssignment> &assignments = it.value();
+ for (it2 = assignments.begin(); it2 != assignments.end(); ) {
+ QPair<QList<QAbstractAnimation*>, QList<QAbstractAnimation*> > ret;
+ ret = initializeAnimation(anim, *it2);
+ QList<QAbstractAnimation*> handlers = ret.first;
+ if (!handlers.isEmpty()) {
+ for (int j = 0; j < handlers.size(); ++j) {
+ QAbstractAnimation *a = handlers.at(j);
+ propertyForAnimation.insert(a, *it2);
+ stateForAnimation.insert(a, s);
+ animationsForState[s].append(a);
+ // ### connect to just the top-level animation?
+ QObject::connect(a, SIGNAL(finished()), q, SLOT(_q_animationFinished()), Qt::UniqueConnection);
+ }
+ it2 = assignments.erase(it2);
+ } else {
+ ++it2;
+ }
+ for (int j = 0; j < ret.second.size(); ++j)
+ resetAnimationEndValues.insert(ret.second.at(j));
+ }
+ if (assignments.isEmpty())
+ it = propertyAssignmentsForState.erase(it);
+ else
+ ++it;
+ }
+ // We require that at least one animation is valid.
+ // ### generalize
+ QList<QVariantAnimation*> variantAnims = qFindChildren<QVariantAnimation*>(anim);
+ if (QVariantAnimation *va = qobject_cast<QVariantAnimation*>(anim))
+ variantAnims.append(va);
+
+ bool hasValidEndValue = false;
+ for (int j = 0; j < variantAnims.size(); ++j) {
+ if (variantAnims.at(j)->endValue().isValid()) {
+ hasValidEndValue = true;
+ break;
+ }
+ }
+
+ if (hasValidEndValue) {
+ anim->start();
+ }
+ }
+#endif // !QT_NO_ANIMATION
+
+ // Immediately set the properties that are not animated.
+ {
+ QHash<QAbstractState*, QList<QPropertyAssignment> >::const_iterator it;
+ for (it = propertyAssignmentsForState.constBegin(); it != propertyAssignmentsForState.constEnd(); ++it) {
+ const QList<QPropertyAssignment> &assignments = it.value();
+ for (int i = 0; i < assignments.size(); ++i) {
+ const QPropertyAssignment &assn = assignments.at(i);
+ assn.object->setProperty(assn.propertyName, assn.value);
+ }
+ }
+ }
+
+ // Emit polished signal for entered states that have no animated properties.
+ for (int i = 0; i < enteredStates.size(); ++i) {
+ QState *s = qobject_cast<QState*>(enteredStates.at(i));
+ if (s
+#ifndef QT_NO_ANIMATION
+ && !animationsForState.contains(s)
+#endif
+ )
+ QStatePrivate::get(s)->emitPolished();
+ }
+}
+
+#endif // QT_NO_PROPERTIES
+
+bool QStateMachinePrivate::isFinal(const QAbstractState *s)
+{
+ return qobject_cast<const QFinalState*>(s) != 0;
+}
+
+bool QStateMachinePrivate::isParallel(const QAbstractState *s)
+{
+ const QState *ss = qobject_cast<const QState*>(s);
+ return ss && (QStatePrivate::get(ss)->childMode == QState::ParallelStates);
+}
+
+bool QStateMachinePrivate::isCompound(const QAbstractState *s) const
+{
+ const QState *group = qobject_cast<const QState*>(s);
+ if (!group)
+ return false;
+ bool isMachine = (qobject_cast<const QStateMachine*>(group) != 0);
+ // Don't treat the machine as compound if it's a sub-state of this machine
+ if (isMachine && (group != rootState()))
+ return false;
+ return (!isParallel(group) && !QStatePrivate::get(group)->childStates().isEmpty())
+ || isMachine;
+}
+
+bool QStateMachinePrivate::isAtomic(const QAbstractState *s) const
+{
+ const QState *ss = qobject_cast<const QState*>(s);
+ return (ss && QStatePrivate::get(ss)->childStates().isEmpty())
+ || isFinal(s)
+ // Treat the machine as atomic if it's a sub-state of this machine
+ || (ss && (qobject_cast<const QStateMachine*>(ss) != 0) && (ss != rootState()));
+}
+
+
+bool QStateMachinePrivate::isDescendantOf(const QAbstractState *state, const QAbstractState *other)
+{
+ Q_ASSERT(state != 0);
+ for (QAbstractState *s = state->parentState(); s != 0; s = s->parentState()) {
+ if (s == other)
+ return true;
+ }
+ return false;
+}
+
+QList<QState*> QStateMachinePrivate::properAncestors(const QAbstractState *state, const QState *upperBound)
+{
+ Q_ASSERT(state != 0);
+ QList<QState*> result;
+ for (QState *s = state->parentState(); s && s != upperBound; s = s->parentState()) {
+ result.append(s);
+ }
+ return result;
+}
+
+bool QStateMachinePrivate::isInFinalState(QAbstractState* s) const
+{
+ if (isCompound(s)) {
+ QState *grp = qobject_cast<QState*>(s);
+ QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
+ for (int i = 0; i < lst.size(); ++i) {
+ QAbstractState *cs = lst.at(i);
+ if (isFinal(cs) && configuration.contains(cs))
+ return true;
+ }
+ return false;
+ } else if (isParallel(s)) {
+ QState *grp = qobject_cast<QState*>(s);
+ QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
+ for (int i = 0; i < lst.size(); ++i) {
+ QAbstractState *cs = lst.at(i);
+ if (!isInFinalState(cs))
+ return false;
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+#ifndef QT_NO_PROPERTIES
+
+void QStateMachinePrivate::registerRestorable(QObject *object, const QByteArray &propertyName)
+{
+ RestorableId id(object, propertyName);
+ if (!registeredRestorables.contains(id))
+ registeredRestorables.insert(id, object->property(propertyName));
+}
+
+QList<QPropertyAssignment> QStateMachinePrivate::restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const
+{
+ QList<QPropertyAssignment> result;
+ QHash<RestorableId, QVariant>::const_iterator it;
+ for (it = restorables.constBegin(); it != restorables.constEnd(); ++it) {
+// qDebug() << "restorable:" << it.key().first << it.key().second << it.value();
+ result.append(QPropertyAssignment(it.key().first, it.key().second, it.value(), /*explicitlySet=*/false));
+ }
+ return result;
+}
+
+/*!
+ \internal
+ Returns true if the variable with the given \a id has been registered for restoration.
+*/
+bool QStateMachinePrivate::hasRestorable(QObject *object, const QByteArray &propertyName) const
+{
+ return registeredRestorables.contains(RestorableId(object, propertyName));
+}
+
+QVariant QStateMachinePrivate::restorableValue(QObject *object, const QByteArray &propertyName) const
+{
+ return registeredRestorables.value(RestorableId(object, propertyName), QVariant());
+}
+
+
+/*!
+ \internal
+ Unregisters the variable identified by \a id
+*/
+void QStateMachinePrivate::unregisterRestorable(QObject *object, const QByteArray &propertyName)
+{
+// qDebug() << "unregisterRestorable(" << object << propertyName << ')';
+ RestorableId id(object, propertyName);
+ registeredRestorables.remove(id);
+}
+
+#endif // QT_NO_PROPERTIES
+
+QAbstractState *QStateMachinePrivate::findErrorState(QAbstractState *context)
+{
+ // Find error state recursively in parent hierarchy if not set explicitly for context state
+ QAbstractState *errorState = 0;
+ if (context != 0) {
+ QState *s = qobject_cast<QState*>(context);
+ if (s != 0)
+ errorState = s->errorState();
+
+ if (errorState == 0)
+ errorState = findErrorState(context->parentState());
+ }
+
+ return errorState;
+}
+
+void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractState *currentContext)
+{
+ Q_Q(QStateMachine);
+
+ error = errorCode;
+ switch (errorCode) {
+ case QStateMachine::NoInitialStateError:
+ Q_ASSERT(currentContext != 0);
+
+ errorString = QStateMachine::tr("Missing initial state in compound state '%1'")
+ .arg(currentContext->objectName());
+
+ break;
+ case QStateMachine::NoDefaultStateInHistoryStateError:
+ Q_ASSERT(currentContext != 0);
+
+ errorString = QStateMachine::tr("Missing default state in history state '%1'")
+ .arg(currentContext->objectName());
+ break;
+
+ case QStateMachine::NoCommonAncestorForTransitionError:
+ Q_ASSERT(currentContext != 0);
+
+ errorString = QStateMachine::tr("No common ancestor for targets and source of transition from state '%1'")
+ .arg(currentContext->objectName());
+ break;
+ default:
+ errorString = QStateMachine::tr("Unknown error");
+ };
+
+ pendingErrorStates.clear();
+ pendingErrorStatesForDefaultEntry.clear();
+
+ QAbstractState *currentErrorState = findErrorState(currentContext);
+
+ // Avoid infinite loop if the error state itself has an error
+ if (currentContext == currentErrorState)
+ currentErrorState = 0;
+
+ Q_ASSERT(currentErrorState != rootState());
+
+ if (currentErrorState != 0) {
+ QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext);
+ addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry);
+ } else {
+ qWarning("Unrecoverable error detected in running state machine: %s",
+ qPrintable(errorString));
+ q->stop();
+ }
+}
+
+#ifndef QT_NO_ANIMATION
+
+QPair<QList<QAbstractAnimation*>, QList<QAbstractAnimation*> >
+QStateMachinePrivate::initializeAnimation(QAbstractAnimation *abstractAnimation,
+ const QPropertyAssignment &prop)
+{
+ QList<QAbstractAnimation*> handledAnimations;
+ QList<QAbstractAnimation*> localResetEndValues;
+ QAnimationGroup *group = qobject_cast<QAnimationGroup*>(abstractAnimation);
+ if (group) {
+ for (int i = 0; i < group->animationCount(); ++i) {
+ QAbstractAnimation *animationChild = group->animationAt(i);
+ QPair<QList<QAbstractAnimation*>, QList<QAbstractAnimation*> > ret;
+ ret = initializeAnimation(animationChild, prop);
+ handledAnimations << ret.first;
+ localResetEndValues << ret.second;
+ }
+ } else {
+ QPropertyAnimation *animation = qobject_cast<QPropertyAnimation *>(abstractAnimation);
+ if (animation != 0
+ && prop.object == animation->targetObject()
+ && prop.propertyName == animation->propertyName()) {
+
+ // Only change end value if it is undefined
+ if (!animation->endValue().isValid()) {
+ animation->setEndValue(prop.value);
+ localResetEndValues.append(animation);
+ }
+ handledAnimations.append(animation);
+ }
+ }
+ return qMakePair(handledAnimations, localResetEndValues);
+}
+
+void QStateMachinePrivate::_q_animationFinished()
+{
+ Q_Q(QStateMachine);
+ QAbstractAnimation *anim = qobject_cast<QAbstractAnimation*>(q->sender());
+ Q_ASSERT(anim != 0);
+ QObject::disconnect(anim, SIGNAL(finished()), q, SLOT(_q_animationFinished()));
+ if (resetAnimationEndValues.contains(anim)) {
+ qobject_cast<QVariantAnimation*>(anim)->setEndValue(QVariant()); // ### generalize
+ resetAnimationEndValues.remove(anim);
+ }
+
+#ifndef QT_NO_PROPERTIES
+ // Set the final property value.
+ QPropertyAssignment assn = propertyForAnimation.take(anim);
+ Q_ASSERT(assn.object != 0);
+ assn.object->setProperty(assn.propertyName, assn.value);
+ if (!assn.explicitlySet)
+ unregisterRestorable(assn.object, assn.propertyName);
+#endif
+
+ QAbstractState *state = stateForAnimation.take(anim);
+ Q_ASSERT(state != 0);
+ QHash<QAbstractState*, QList<QAbstractAnimation*> >::iterator it;
+ it = animationsForState.find(state);
+ Q_ASSERT(it != animationsForState.end());
+ QList<QAbstractAnimation*> &animations = it.value();
+ animations.removeOne(anim);
+ if (animations.isEmpty()) {
+ animationsForState.erase(it);
+ QStatePrivate::get(qobject_cast<QState*>(state))->emitPolished();
+ }
+}
+
+#endif // !QT_NO_ANIMATION
+
+namespace {
+
+class StartState : public QState
+{
+public:
+ StartState(QState *parent)
+ : QState(parent) {}
+protected:
+ void onEntry(QEvent *) {}
+ void onExit(QEvent *) {}
+};
+
+class InitialTransition : public QAbstractTransition
+{
+public:
+ InitialTransition(QAbstractState *target)
+ : QAbstractTransition()
+ { setTargetState(target); }
+protected:
+ virtual bool eventTest(QEvent *) { return true; }
+ virtual void onTransition(QEvent *) {}
+};
+
+} // namespace
+
+QState *QStateMachinePrivate::startState()
+{
+ Q_Q(QStateMachine);
+ if (_startState == 0)
+ _startState = new StartState(q);
+ return _startState;
+}
+
+void QStateMachinePrivate::removeStartState()
+{
+ delete _startState;
+ _startState = 0;
+}
+
+void QStateMachinePrivate::_q_start()
+{
+ Q_Q(QStateMachine);
+ Q_ASSERT(state == Starting);
+ Q_ASSERT(rootState() != 0);
+ QAbstractState *initial = rootState()->initialState();
+ configuration.clear();
+ qDeleteAll(internalEventQueue);
+ internalEventQueue.clear();
+ qDeleteAll(externalEventQueue);
+ externalEventQueue.clear();
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": starting";
+#endif
+ state = Running;
+ processingScheduled = true; // we call _q_process() below
+ emit q->started();
+
+ QState *start = startState();
+ Q_ASSERT(start != 0);
+
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(start)->transitions();
+
+ // If a transition has already been added, then we skip this step, as the
+ // initial transition in that case has been overridden.
+ if (transitions.isEmpty()) {
+ QAbstractTransition *initialTransition = new InitialTransition(initial);
+ start->addTransition(initialTransition);
+ transitions.append(initialTransition);
+ }
+
+ QEvent nullEvent(QEvent::None);
+ executeTransitionContent(&nullEvent, transitions);
+ QList<QAbstractState*> enteredStates = enterStates(&nullEvent, transitions);
+#ifndef QT_NO_PROPERTIES
+ applyProperties(transitions, QList<QAbstractState*>() << start,
+ enteredStates);
+#endif
+ removeStartState();
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": initial configuration:" << configuration;
+#endif
+ _q_process();
+}
+
+void QStateMachinePrivate::_q_process()
+{
+ Q_Q(QStateMachine);
+ Q_ASSERT(state == Running);
+ Q_ASSERT(!processing);
+ processing = true;
+ processingScheduled = false;
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": starting the event processing loop";
+#endif
+ while (processing) {
+ if (stop) {
+ stop = false;
+ processing = false;
+ stopProcessingReason = Stopped;
+ break;
+ }
+ QSet<QAbstractTransition*> enabledTransitions;
+ QEvent *e = new QEvent(QEvent::None);
+ enabledTransitions = selectTransitions(e);
+ if (enabledTransitions.isEmpty()) {
+ delete e;
+ e = 0;
+ }
+ if (enabledTransitions.isEmpty() && !internalEventQueue.isEmpty()) {
+ e = internalEventQueue.takeFirst();
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": dequeued internal event" << e << "of type" << e->type();
+#endif
+ enabledTransitions = selectTransitions(e);
+ if (enabledTransitions.isEmpty()) {
+ delete e;
+ e = 0;
+ }
+ }
+ if (enabledTransitions.isEmpty()) {
+ if (externalEventQueue.isEmpty()) {
+ if (internalEventQueue.isEmpty()) {
+ processing = false;
+ stopProcessingReason = EventQueueEmpty;
+ }
+ } else {
+ e = externalEventQueue.takeFirst();
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": dequeued external event" << e << "of type" << e->type();
+#endif
+ enabledTransitions = selectTransitions(e);
+ if (enabledTransitions.isEmpty()) {
+ delete e;
+ e = 0;
+ }
+ }
+ }
+ if (!enabledTransitions.isEmpty()) {
+ q->beginMicrostep(e);
+ microstep(e, enabledTransitions.toList());
+ q->endMicrostep(e);
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ else {
+ qDebug() << q << ": no transitions enabled";
+ }
+#endif
+ delete e;
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": finished the event processing loop";
+#endif
+ switch (stopProcessingReason) {
+ case EventQueueEmpty:
+ break;
+ case Finished:
+ state = NotRunning;
+ unregisterAllTransitions();
+ emit q->finished();
+ break;
+ case Stopped:
+ state = NotRunning;
+ unregisterAllTransitions();
+ emit q->stopped();
+ break;
+ }
+}
+
+void QStateMachinePrivate::scheduleProcess()
+{
+ if ((state != Running) || processing || processingScheduled)
+ return;
+ processingScheduled = true;
+ QMetaObject::invokeMethod(q_func(), "_q_process", Qt::QueuedConnection);
+}
+
+namespace {
+
+class GoToStateTransition : public QAbstractTransition
+{
+public:
+ GoToStateTransition(QAbstractState *target)
+ : QAbstractTransition()
+ { setTargetState(target); }
+protected:
+ void onTransition(QEvent *) { deleteLater(); }
+ bool eventTest(QEvent *) { return true; }
+};
+
+} // namespace
+
+/*!
+ \internal
+
+ Causes this state machine to unconditionally transition to the given
+ \a targetState.
+
+ Provides a backdoor for using the state machine "imperatively"; i.e. rather
+ than defining explicit transitions, you drive the machine's execution by
+ calling this function. It breaks the whole integrity of the
+ transition-driven model, but is provided for pragmatic reasons.
+*/
+void QStateMachinePrivate::goToState(QAbstractState *targetState)
+{
+ if (!targetState) {
+ qWarning("QStateMachine::goToState(): cannot go to null state");
+ return;
+ }
+
+ if (configuration.contains(targetState))
+ return;
+
+ QState *sourceState = 0;
+ if (state == Running) {
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ sourceState = qobject_cast<QState*>(*it);
+ if (sourceState != 0)
+ break;
+ }
+ } else {
+ sourceState = startState();
+ }
+
+ Q_ASSERT(sourceState != 0);
+ // Reuse previous GoToStateTransition in case of several calls to
+ // goToState() in a row.
+ GoToStateTransition *trans = qFindChild<GoToStateTransition*>(sourceState);
+ if (!trans) {
+ trans = new GoToStateTransition(targetState);
+ sourceState->addTransition(trans);
+ } else {
+ trans->setTargetState(targetState);
+ }
+
+ scheduleProcess();
+}
+
+void QStateMachinePrivate::registerTransitions(QAbstractState *state)
+{
+ QState *group = qobject_cast<QState*>(state);
+ if (!group)
+ return;
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(group)->transitions();
+ for (int i = 0; i < transitions.size(); ++i) {
+ QAbstractTransition *t = transitions.at(i);
+ if (QSignalTransition *st = qobject_cast<QSignalTransition*>(t)) {
+ registerSignalTransition(st);
+ }
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+ else if (QEventTransition *oet = qobject_cast<QEventTransition*>(t)) {
+ registerEventTransition(oet);
+ }
+#endif
+ }
+}
+
+void QStateMachinePrivate::unregisterTransition(QAbstractTransition *transition)
+{
+ if (QSignalTransition *st = qobject_cast<QSignalTransition*>(transition)) {
+ unregisterSignalTransition(st);
+ }
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+ else if (QEventTransition *oet = qobject_cast<QEventTransition*>(transition)) {
+ unregisterEventTransition(oet);
+ }
+#endif
+}
+
+void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transition)
+{
+ Q_Q(QStateMachine);
+ if (QSignalTransitionPrivate::get(transition)->signalIndex != -1)
+ return; // already registered
+ QObject *sender = QSignalTransitionPrivate::get(transition)->sender;
+ if (!sender)
+ return;
+ QByteArray signal = QSignalTransitionPrivate::get(transition)->signal;
+ if (signal.startsWith('0'+QSIGNAL_CODE))
+ signal.remove(0, 1);
+ const QMetaObject *meta = sender->metaObject();
+ int signalIndex = meta->indexOfSignal(signal);
+ int originalSignalIndex = signalIndex;
+ if (signalIndex == -1) {
+ signalIndex = meta->indexOfSignal(QMetaObject::normalizedSignature(signal));
+ if (signalIndex == -1) {
+ qWarning("QSignalTransition: no such signal: %s::%s",
+ meta->className(), signal.constData());
+ return;
+ }
+ }
+ // The signal index we actually want to connect to is the one
+ // that is going to be sent, i.e. the non-cloned original index.
+ while (meta->method(signalIndex).attributes() & QMetaMethod::Cloned)
+ --signalIndex;
+
+ QVector<int> &connectedSignalIndexes = connections[sender];
+ if (connectedSignalIndexes.size() <= signalIndex)
+ connectedSignalIndexes.resize(signalIndex+1);
+ if (connectedSignalIndexes.at(signalIndex) == 0) {
+ if (!signalEventGenerator)
+ signalEventGenerator = new QSignalEventGenerator(q);
+ bool ok = QMetaObject::connect(sender, signalIndex, signalEventGenerator,
+ signalEventGenerator->metaObject()->methodOffset());
+ if (!ok) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": FAILED to add signal transition from" << transition->sourceState()
+ << ": ( sender =" << sender << ", signal =" << signal
+ << ", targets =" << transition->targetStates() << ')';
+#endif
+ return;
+ }
+ }
+ ++connectedSignalIndexes[signalIndex];
+ QSignalTransitionPrivate::get(transition)->signalIndex = signalIndex;
+ QSignalTransitionPrivate::get(transition)->originalSignalIndex = originalSignalIndex;
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": added signal transition from" << transition->sourceState()
+ << ": ( sender =" << sender << ", signal =" << signal
+ << ", targets =" << transition->targetStates() << ')';
+#endif
+}
+
+void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transition)
+{
+ int signalIndex = QSignalTransitionPrivate::get(transition)->signalIndex;
+ if (signalIndex == -1)
+ return; // not registered
+ QSignalTransitionPrivate::get(transition)->signalIndex = -1;
+ const QObject *sender = QSignalTransitionPrivate::get(transition)->sender;
+ QVector<int> &connectedSignalIndexes = connections[sender];
+ Q_ASSERT(connectedSignalIndexes.size() > signalIndex);
+ Q_ASSERT(connectedSignalIndexes.at(signalIndex) != 0);
+ if (--connectedSignalIndexes[signalIndex] == 0) {
+ Q_ASSERT(signalEventGenerator != 0);
+ QMetaObject::disconnect(sender, signalIndex, signalEventGenerator,
+ signalEventGenerator->metaObject()->methodOffset());
+ int sum = 0;
+ for (int i = 0; i < connectedSignalIndexes.size(); ++i)
+ sum += connectedSignalIndexes.at(i);
+ if (sum == 0)
+ connections.remove(sender);
+ }
+}
+
+void QStateMachinePrivate::unregisterAllTransitions()
+{
+ Q_Q(QStateMachine);
+ {
+ QList<QSignalTransition*> transitions = qFindChildren<QSignalTransition*>(rootState());
+ for (int i = 0; i < transitions.size(); ++i) {
+ QSignalTransition *t = transitions.at(i);
+ if (t->machine() == q)
+ unregisterSignalTransition(t);
+ }
+ }
+ {
+ QList<QEventTransition*> transitions = qFindChildren<QEventTransition*>(rootState());
+ for (int i = 0; i < transitions.size(); ++i) {
+ QEventTransition *t = transitions.at(i);
+ if (t->machine() == q)
+ unregisterEventTransition(t);
+ }
+ }
+}
+
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+void QStateMachinePrivate::registerEventTransition(QEventTransition *transition)
+{
+ Q_Q(QStateMachine);
+ if (QEventTransitionPrivate::get(transition)->registered)
+ return;
+ if (transition->eventType() >= QEvent::User) {
+ qWarning("QObject event transitions are not supported for custom types");
+ return;
+ }
+ QObject *object = QEventTransitionPrivate::get(transition)->object;
+ if (!object)
+ return;
+ QObjectPrivate *od = QObjectPrivate::get(object);
+ if (!od->eventFilters.contains(q))
+ object->installEventFilter(q);
+ ++qobjectEvents[object][transition->eventType()];
+ QEventTransitionPrivate::get(transition)->registered = true;
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": added event transition from" << transition->sourceState()
+ << ": ( object =" << object << ", event =" << transition->eventType()
+ << ", targets =" << transition->targetStates() << ')';
+#endif
+}
+
+void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transition)
+{
+ Q_Q(QStateMachine);
+ if (!QEventTransitionPrivate::get(transition)->registered)
+ return;
+ QObject *object = QEventTransitionPrivate::get(transition)->object;
+ QHash<QEvent::Type, int> &events = qobjectEvents[object];
+ Q_ASSERT(events.value(transition->eventType()) > 0);
+ if (--events[transition->eventType()] == 0) {
+ events.remove(transition->eventType());
+ int sum = 0;
+ QHash<QEvent::Type, int>::const_iterator it;
+ for (it = events.constBegin(); it != events.constEnd(); ++it)
+ sum += it.value();
+ if (sum == 0) {
+ qobjectEvents.remove(object);
+ object->removeEventFilter(q);
+ }
+ }
+ QEventTransitionPrivate::get(transition)->registered = false;
+}
+#endif
+
+void QStateMachinePrivate::handleTransitionSignal(QObject *sender, int signalIndex,
+ void **argv)
+{
+ Q_ASSERT(connections[sender].at(signalIndex) != 0);
+ const QMetaObject *meta = sender->metaObject();
+ QMetaMethod method = meta->method(signalIndex);
+ QList<QByteArray> parameterTypes = method.parameterTypes();
+ int argc = parameterTypes.count();
+ QList<QVariant> vargs;
+ for (int i = 0; i < argc; ++i) {
+ int type = QMetaType::type(parameterTypes.at(i));
+ vargs.append(QVariant(type, argv[i+1]));
+ }
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": sending signal event ( sender =" << sender
+ << ", signal =" << sender->metaObject()->method(signalIndex).signature() << ')';
+#endif
+ internalEventQueue.append(new QSignalEvent(sender, signalIndex, vargs));
+ scheduleProcess();
+}
+
+/*!
+ Constructs a new state machine with the given \a parent.
+*/
+QStateMachine::QStateMachine(QObject *parent)
+ : QState(*new QStateMachinePrivate, /*parentState=*/0)
+{
+ // Can't pass the parent to the QState constructor, as it expects a QState
+ // But this works as expected regardless of whether parent is a QState or not
+ setParent(parent);
+}
+
+/*!
+ \internal
+*/
+QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent)
+ : QState(dd, /*parentState=*/0)
+{
+ setParent(parent);
+}
+
+/*!
+ Destroys this state machine.
+*/
+QStateMachine::~QStateMachine()
+{
+}
+
+/*! \enum QStateMachine::Error
+
+ This enum type defines errors that can occur in the state machine at run time. When the state
+ machine encounters an unrecoverable error at run time, it will set the error code returned
+ by error(), the error message returned by errorString(), and enter an error state based on
+ the context of the error.
+
+ \value NoError No error has occurred.
+ \value NoInitialStateError The machine has entered a QState with children which does not have an
+ initial state set. The context of this error is the state which is missing an initial
+ state.
+ \value NoDefaultStateInHistoryStateError The machine has entered a QHistoryState which does not have
+ a default state set. The context of this error is the QHistoryState which is missing a
+ default state.
+ \value NoCommonAncestorForTransitionError The machine has selected a transition whose source
+ and targets are not part of the same tree of states, and thus are not part of the same
+ state machine. Commonly, this could mean that one of the states has not been given
+ any parent or added to any machine. The context of this error is the source state of
+ the transition.
+
+ \sa setErrorState()
+*/
+
+/*!
+ \enum QStateMachine::RestorePolicy
+
+ This enum specifies the restore policy type. The restore policy
+ takes effect when the machine enters a state which sets one or more
+ properties. If the restore policy is set to RestoreProperties,
+ the state machine will save the original value of the property before the
+ new value is set.
+
+ Later, when the machine either enters a state which does not set
+ a value for the given property, the property will automatically be restored
+ to its initial value.
+
+ Only one initial value will be saved for any given property. If a value for a property has
+ already been saved by the state machine, it will not be overwritten until the property has been
+ successfully restored.
+
+ \value DoNotRestoreProperties The state machine should not save the initial values of properties
+ and restore them later.
+ \value RestoreProperties The state machine should save the initial values of properties
+ and restore them later.
+
+ \sa QStateMachine::globalRestorePolicy QState::assignProperty()
+*/
+
+
+/*!
+ Returns the error code of the last error that occurred in the state machine.
+*/
+QStateMachine::Error QStateMachine::error() const
+{
+ Q_D(const QStateMachine);
+ return d->error;
+}
+
+/*!
+ Returns the error string of the last error that occurred in the state machine.
+*/
+QString QStateMachine::errorString() const
+{
+ Q_D(const QStateMachine);
+ return d->errorString;
+}
+
+/*!
+ Clears the error string and error code of the state machine.
+*/
+void QStateMachine::clearError()
+{
+ Q_D(QStateMachine);
+ d->errorString.clear();
+ d->error = NoError;
+}
+
+/*!
+ Returns the restore policy of the state machine.
+
+ \sa setGlobalRestorePolicy()
+*/
+QStateMachine::RestorePolicy QStateMachine::globalRestorePolicy() const
+{
+ Q_D(const QStateMachine);
+ return d->globalRestorePolicy;
+}
+
+/*!
+ Sets the restore policy of the state machine to \a restorePolicy. The default
+ restore policy is QAbstractState::DoNotRestoreProperties.
+
+ \sa globalRestorePolicy()
+*/
+void QStateMachine::setGlobalRestorePolicy(QStateMachine::RestorePolicy restorePolicy)
+{
+ Q_D(QStateMachine);
+ d->globalRestorePolicy = restorePolicy;
+}
+
+/*!
+ Adds the given \a state to this state machine. The state becomes a top-level
+ state.
+
+ If the state is already in a different machine, it will first be removed
+ from its old machine, and then added to this machine.
+
+ \sa removeState(), setInitialState()
+*/
+void QStateMachine::addState(QAbstractState *state)
+{
+ if (!state) {
+ qWarning("QStateMachine::addState: cannot add null state");
+ return;
+ }
+ if (QAbstractStatePrivate::get(state)->machine() == this) {
+ qWarning("QStateMachine::addState: state has already been added to this machine");
+ return;
+ }
+ state->setParent(this);
+}
+
+/*!
+ Removes the given \a state from this state machine. The state machine
+ releases ownership of the state.
+
+ \sa addState()
+*/
+void QStateMachine::removeState(QAbstractState *state)
+{
+ if (!state) {
+ qWarning("QStateMachine::removeState: cannot remove null state");
+ return;
+ }
+ if (QAbstractStatePrivate::get(state)->machine() != this) {
+ qWarning("QStateMachine::removeState: state %p's machine (%p)"
+ " is different from this machine (%p)",
+ state, QAbstractStatePrivate::get(state)->machine(), this);
+ return;
+ }
+ state->setParent(0);
+}
+
+/*!
+ Returns whether this state machine is running.
+
+ start(), stop()
+*/
+bool QStateMachine::isRunning() const
+{
+ Q_D(const QStateMachine);
+ return (d->state == QStateMachinePrivate::Running);
+}
+
+/*!
+ Starts this state machine. The machine will reset its configuration and
+ transition to the initial state. When a final top-level state (QFinalState)
+ is entered, the machine will emit the finished() signal.
+
+ \sa started(), finished(), stop(), initialState()
+*/
+void QStateMachine::start()
+{
+ Q_D(QStateMachine);
+
+ if (initialState() == 0) {
+ qWarning("QStateMachine::start: No initial state set for machine. Refusing to start.");
+ return;
+ }
+
+ switch (d->state) {
+ case QStateMachinePrivate::NotRunning:
+ d->state = QStateMachinePrivate::Starting;
+ QMetaObject::invokeMethod(this, "_q_start", Qt::QueuedConnection);
+ break;
+ case QStateMachinePrivate::Starting:
+ break;
+ case QStateMachinePrivate::Running:
+ qWarning("QStateMachine::start(): already running");
+ break;
+ }
+}
+
+/*!
+ Stops this state machine. The state machine will stop processing events and
+ then emit the stopped() signal.
+
+ \sa stopped(), start()
+*/
+void QStateMachine::stop()
+{
+ Q_D(QStateMachine);
+ switch (d->state) {
+ case QStateMachinePrivate::NotRunning:
+ break;
+ case QStateMachinePrivate::Starting:
+ // the machine will exit as soon as it enters the event processing loop
+ d->stop = true;
+ break;
+ case QStateMachinePrivate::Running:
+ d->stop = true;
+ d->scheduleProcess();
+ break;
+ }
+}
+
+/*!
+ Posts the given \a event for processing by this state machine, with a delay
+ of \a delay milliseconds.
+
+ This function returns immediately. The event is added to the state machine's
+ event queue. Events are processed in the order posted. The state machine
+ takes ownership of the event and deletes it once it has been processed.
+
+ You can only post events when the state machine is running.
+*/
+void QStateMachine::postEvent(QEvent *event, int delay)
+{
+ Q_D(QStateMachine);
+ if (d->state != QStateMachinePrivate::Running) {
+ qWarning("QStateMachine::postEvent: cannot post event when the state machine is not running");
+ return;
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << this << ": posting external event" << event << "with delay" << delay;
+#endif
+ if (delay) {
+ int tid = startTimer(delay);
+ d->delayedEvents[tid] = event;
+ } else {
+ d->externalEventQueue.append(event);
+ d->scheduleProcess();
+ }
+}
+
+/*!
+ \internal
+
+ Posts the given internal \a event for processing by this state machine.
+*/
+void QStateMachine::postInternalEvent(QEvent *event)
+{
+ Q_D(QStateMachine);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << this << ": posting internal event" << event;
+#endif
+ d->internalEventQueue.append(event);
+ d->scheduleProcess();
+}
+
+/*!
+ \internal
+
+ Returns the maximal consistent set of states (including parallel and final
+ states) that this state machine is currently in. If a state \c s is in the
+ configuration, it is always the case that the parent of \c s is also in
+ c. Note, however, that the machine itself is not an explicit member of the
+ configuration.
+*/
+QSet<QAbstractState*> QStateMachine::configuration() const
+{
+ Q_D(const QStateMachine);
+ return d->configuration;
+}
+
+/*!
+ \fn QStateMachine::started()
+
+ This signal is emitted when the state machine has entered its initial state
+ (QStateMachine::initialState).
+
+ \sa QStateMachine::finished(), QStateMachine::start()
+*/
+
+/*!
+ \fn QStateMachine::stopped()
+
+ This signal is emitted when the state machine has stopped.
+
+ \sa QStateMachine::stop(), QStateMachine::finished()
+*/
+
+/*!
+ \reimp
+*/
+bool QStateMachine::event(QEvent *e)
+{
+ Q_D(QStateMachine);
+ if (e->type() == QEvent::Timer) {
+ QTimerEvent *te = static_cast<QTimerEvent*>(e);
+ int tid = te->timerId();
+ if (d->delayedEvents.contains(tid)) {
+ killTimer(tid);
+ QEvent *ee = d->delayedEvents.take(tid);
+ d->externalEventQueue.append(ee);
+ d->scheduleProcess();
+ return true;
+ }
+ }
+ return QObject::event(e);
+}
+
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+/*!
+ \reimp
+*/
+bool QStateMachine::eventFilter(QObject *watched, QEvent *event)
+{
+ Q_D(QStateMachine);
+ Q_ASSERT(d->qobjectEvents.contains(watched));
+ if (d->qobjectEvents[watched].contains(event->type()))
+ postEvent(new QWrappedEvent(watched, d->handler->cloneEvent(event)));
+ return false;
+}
+#endif
+
+/*!
+ \internal
+
+ This function is called when the state machine is about to select
+ transitions based on the given \a event.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::beginSelectTransitions(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+
+ This function is called when the state machine has finished selecting
+ transitions based on the given \a event.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::endSelectTransitions(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+
+ This function is called when the state machine is about to do a microstep.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::beginMicrostep(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+
+ This function is called when the state machine has finished doing a
+ microstep.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::endMicrostep(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QStateMachine::onEntry(QEvent *event)
+{
+ start();
+ QState::onEntry(event);
+}
+
+/*!
+ \reimp
+*/
+void QStateMachine::onExit(QEvent *event)
+{
+ stop();
+ QState::onExit(event);
+}
+
+#ifndef QT_NO_ANIMATION
+
+/*!
+ Returns whether animations are enabled for this state machine.
+*/
+bool QStateMachine::animationsEnabled() const
+{
+ Q_D(const QStateMachine);
+ return d->animationsEnabled;
+}
+
+/*!
+ Sets whether animations are \a enabled for this state machine.
+*/
+void QStateMachine::setAnimationsEnabled(bool enabled)
+{
+ Q_D(QStateMachine);
+ d->animationsEnabled = enabled;
+}
+
+/*!
+ Adds a default \a animation to be considered for any transition.
+*/
+void QStateMachine::addDefaultAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QStateMachine);
+ d->defaultAnimations.append(animation);
+}
+
+/*!
+ Returns the list of default animations that will be considered for any transition.
+*/
+QList<QAbstractAnimation*> QStateMachine::defaultAnimations() const
+{
+ Q_D(const QStateMachine);
+ return d->defaultAnimations;
+}
+
+/*!
+ Removes \a animation from the list of default animations.
+*/
+void QStateMachine::removeDefaultAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QStateMachine);
+ d->defaultAnimations.removeAll(animation);
+}
+
+#endif // QT_NO_ANIMATION
+
+
+static const uint qt_meta_data_QSignalEventGenerator[] = {
+
+ // content:
+ 2, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 1, 12, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+
+ // slots: signature, parameters, type, tag, flags
+ 23, 22, 22, 22, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_QSignalEventGenerator[] = {
+ "QSignalEventGenerator\0\0execute()\0"
+};
+
+const QMetaObject QSignalEventGenerator::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_QSignalEventGenerator,
+ qt_meta_data_QSignalEventGenerator, 0 }
+};
+
+const QMetaObject *QSignalEventGenerator::metaObject() const
+{
+ return &staticMetaObject;
+}
+
+void *QSignalEventGenerator::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_QSignalEventGenerator))
+ return static_cast<void*>(const_cast< QSignalEventGenerator*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int QSignalEventGenerator::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ switch (_id) {
+ case 0: {
+// ### in Qt 4.6 we can use QObject::senderSignalIndex()
+ QObjectPrivate *d = static_cast<QObjectPrivate *>(d_ptr.data());
+ int signalIndex = -1;
+ QObject *sender = this->sender();
+ if (sender && d->currentSender)
+ signalIndex = d->currentSender->signal;
+
+ Q_ASSERT(signalIndex != -1);
+ QStateMachine *machine = qobject_cast<QStateMachine*>(parent());
+ QStateMachinePrivate::get(machine)->handleTransitionSignal(sender, signalIndex, _a);
+ break;
+ }
+ default: ;
+ }
+ _id -= 1;
+ }
+ return _id;
+}
+
+QSignalEventGenerator::QSignalEventGenerator(QStateMachine *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \class QSignalEvent
+
+ \brief The QSignalEvent class represents a Qt signal event.
+
+ \since 4.6
+ \ingroup statemachine
+
+ A signal event is generated by a QStateMachine in response to a Qt
+ signal. The QSignalTransition class provides a transition associated with a
+ signal event. QSignalEvent is part of \l{The State Machine Framework}.
+
+ The sender() function returns the object that generated the signal. The
+ signalIndex() function returns the index of the signal. The arguments()
+ function returns the arguments of the signal.
+
+ \sa QSignalTransition
+*/
+
+/*!
+ \internal
+
+ Constructs a new QSignalEvent object with the given \a sender, \a
+ signalIndex and \a arguments.
+*/
+QSignalEvent::QSignalEvent(QObject *sender, int signalIndex,
+ const QList<QVariant> &arguments)
+ : QEvent(QEvent::Signal), m_sender(sender),
+ m_signalIndex(signalIndex), m_arguments(arguments)
+{
+}
+
+/*!
+ Destroys this QSignalEvent.
+*/
+QSignalEvent::~QSignalEvent()
+{
+}
+
+/*!
+ \fn QSignalEvent::sender() const
+
+ Returns the object that emitted the signal.
+
+ \sa QObject::sender()
+*/
+
+/*!
+ \fn QSignalEvent::signalIndex() const
+
+ Returns the index of the signal.
+
+ \sa QMetaObject::indexOfSignal(), QMetaObject::method()
+*/
+
+/*!
+ \fn QSignalEvent::arguments() const
+
+ Returns the arguments of the signal.
+*/
+
+
+/*!
+ \class QWrappedEvent
+
+ \brief The QWrappedEvent class holds a clone of an event associated with a QObject.
+
+ \since 4.6
+ \ingroup statemachine
+
+ A wrapped event is generated by a QStateMachine in response to a Qt
+ event. The QEventTransition class provides a transition associated with a
+ such an event. QWrappedEvent is part of \l{The State Machine Framework}.
+
+ The object() function returns the object that generated the event. The
+ event() function returns a clone of the original event.
+
+ \sa QEventTransition
+*/
+
+/*!
+ \internal
+
+ Constructs a new QWrappedEvent object with the given \a object
+ and \a event.
+
+ The QWrappedEvent object takes ownership of \a event.
+*/
+QWrappedEvent::QWrappedEvent(QObject *object, QEvent *event)
+ : QEvent(QEvent::Wrapped), m_object(object), m_event(event)
+{
+}
+
+/*!
+ Destroys this QWrappedEvent.
+*/
+QWrappedEvent::~QWrappedEvent()
+{
+ delete m_event;
+}
+
+/*!
+ \fn QWrappedEvent::object() const
+
+ Returns the object that the event is associated with.
+*/
+
+/*!
+ \fn QWrappedEvent::event() const
+
+ Returns a clone of the original event.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qstatemachine.cpp"
+
+#endif //QT_NO_STATEMACHINE
diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h
new file mode 100644
index 0000000..5f4035e
--- /dev/null
+++ b/src/corelib/statemachine/qstatemachine.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATEMACHINE_H
+#define QSTATEMACHINE_H
+
+#include <QtCore/qstate.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qset.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_STATEMACHINE
+
+class QEvent;
+
+class QStateMachinePrivate;
+class QAbstractAnimation;
+class Q_CORE_EXPORT QStateMachine : public QState
+{
+ Q_OBJECT
+ Q_PROPERTY(QString errorString READ errorString)
+ Q_PROPERTY(RestorePolicy globalRestorePolicy READ globalRestorePolicy WRITE setGlobalRestorePolicy)
+ Q_ENUMS(RestorePolicy)
+#ifndef QT_NO_ANIMATION
+ Q_PROPERTY(bool animationsEnabled READ animationsEnabled WRITE setAnimationsEnabled)
+#endif
+public:
+ enum RestorePolicy {
+ DoNotRestoreProperties,
+ RestoreProperties
+ };
+
+ enum Error {
+ NoError,
+ NoInitialStateError,
+ NoDefaultStateInHistoryStateError,
+ NoCommonAncestorForTransitionError
+ };
+
+ QStateMachine(QObject *parent = 0);
+ ~QStateMachine();
+
+ void addState(QAbstractState *state);
+ void removeState(QAbstractState *state);
+
+ Error error() const;
+ QString errorString() const;
+ void clearError();
+
+ bool isRunning() const;
+
+#ifndef QT_NO_ANIMATION
+ bool animationsEnabled() const;
+ void setAnimationsEnabled(bool enabled);
+
+ void addDefaultAnimation(QAbstractAnimation *animation);
+ QList<QAbstractAnimation *> defaultAnimations() const;
+ void removeDefaultAnimation(QAbstractAnimation *animation);
+#endif // QT_NO_ANIMATION
+
+ QStateMachine::RestorePolicy globalRestorePolicy() const;
+ void setGlobalRestorePolicy(QStateMachine::RestorePolicy restorePolicy);
+
+ void postEvent(QEvent *event, int delay = 0);
+
+ QSet<QAbstractState*> configuration() const;
+
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+ bool eventFilter(QObject *watched, QEvent *event);
+#endif
+
+public Q_SLOTS:
+ void start();
+ void stop();
+
+Q_SIGNALS:
+ void started();
+ void stopped();
+
+protected:
+ void onEntry(QEvent *event);
+ void onExit(QEvent *event);
+
+ void postInternalEvent(QEvent *event);
+
+ virtual void beginSelectTransitions(QEvent *event);
+ virtual void endSelectTransitions(QEvent *event);
+
+ virtual void beginMicrostep(QEvent *event);
+ virtual void endMicrostep(QEvent *event);
+
+ bool event(QEvent *e);
+
+protected:
+ QStateMachine(QStateMachinePrivate &dd, QObject *parent);
+
+private:
+ Q_DISABLE_COPY(QStateMachine)
+ Q_DECLARE_PRIVATE(QStateMachine)
+ Q_PRIVATE_SLOT(d_func(), void _q_start())
+ Q_PRIVATE_SLOT(d_func(), void _q_process())
+#ifndef QT_NO_ANIMATION
+ Q_PRIVATE_SLOT(d_func(), void _q_animationFinished())
+#endif
+};
+
+#endif //QT_NO_STATEMACHINE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h
new file mode 100644
index 0000000..defa7af
--- /dev/null
+++ b/src/corelib/statemachine/qstatemachine_p.h
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATEMACHINE_P_H
+#define QSTATEMACHINE_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 "private/qstate_p.h"
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qset.h>
+#include <QtCore/qvector.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEvent;
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+class QEventTransition;
+#endif
+class QSignalEventGenerator;
+class QSignalTransition;
+class QAbstractState;
+class QAbstractTransition;
+class QState;
+
+#ifndef QT_NO_ANIMATION
+class QAbstractAnimation;
+#endif
+
+class QStateMachine;
+class Q_CORE_EXPORT QStateMachinePrivate : public QStatePrivate
+{
+ Q_DECLARE_PUBLIC(QStateMachine)
+public:
+ enum State {
+ NotRunning,
+ Starting,
+ Running
+ };
+ enum StopProcessingReason {
+ EventQueueEmpty,
+ Finished,
+ Stopped
+ };
+
+ QStateMachinePrivate();
+ ~QStateMachinePrivate();
+
+ static QStateMachinePrivate *get(QStateMachine *q);
+
+ QState *findLCA(const QList<QAbstractState*> &states) const;
+
+ static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2);
+ static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2);
+
+ QAbstractState *findErrorState(QAbstractState *context);
+ void setError(QStateMachine::Error error, QAbstractState *currentContext);
+
+ // private slots
+ void _q_start();
+ void _q_process();
+#ifndef QT_NO_ANIMATION
+ void _q_animationFinished();
+#endif
+
+ QState *rootState() const;
+
+ QState *startState();
+ void removeStartState();
+
+ void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList);
+ bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const;
+ QSet<QAbstractTransition*> selectTransitions(QEvent *event) const;
+ QList<QAbstractState*> exitStates(QEvent *event, const QList<QAbstractTransition*> &transitionList);
+ void executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &transitionList);
+ QList<QAbstractState*> enterStates(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions);
+ void addStatesToEnter(QAbstractState *s, QState *root,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry);
+
+ void applyProperties(const QList<QAbstractTransition*> &transitionList,
+ const QList<QAbstractState*> &exitedStates,
+ const QList<QAbstractState*> &enteredStates);
+
+ bool isInFinalState(QAbstractState *s) const;
+ static bool isFinal(const QAbstractState *s);
+ static bool isParallel(const QAbstractState *s);
+ bool isCompound(const QAbstractState *s) const;
+ bool isAtomic(const QAbstractState *s) const;
+ static bool isDescendantOf(const QAbstractState *s, const QAbstractState *other);
+ static QList<QState*> properAncestors(const QAbstractState *s, const QState *upperBound);
+
+ void goToState(QAbstractState *targetState);
+
+ void registerTransitions(QAbstractState *state);
+ void registerSignalTransition(QSignalTransition *transition);
+ void unregisterSignalTransition(QSignalTransition *transition);
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+ void registerEventTransition(QEventTransition *transition);
+ void unregisterEventTransition(QEventTransition *transition);
+#endif
+ void unregisterTransition(QAbstractTransition *transition);
+ void unregisterAllTransitions();
+ void handleTransitionSignal(QObject *sender, int signalIndex,
+ void **args);
+ void scheduleProcess();
+
+#ifndef QT_NO_PROPERTIES
+ typedef QPair<QObject *, QByteArray> RestorableId;
+ QHash<RestorableId, QVariant> registeredRestorables;
+ void registerRestorable(QObject *object, const QByteArray &propertyName);
+ void unregisterRestorable(QObject *object, const QByteArray &propertyName);
+ bool hasRestorable(QObject *object, const QByteArray &propertyName) const;
+ QVariant restorableValue(QObject *object, const QByteArray &propertyName) const;
+ QList<QPropertyAssignment> restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const;
+#endif
+
+ State state;
+ QState *_startState;
+ bool processing;
+ bool processingScheduled;
+ bool stop;
+ StopProcessingReason stopProcessingReason;
+ QSet<QAbstractState*> configuration;
+ QList<QEvent*> internalEventQueue;
+ QList<QEvent*> externalEventQueue;
+
+ QStateMachine::Error error;
+ QStateMachine::RestorePolicy globalRestorePolicy;
+
+ QString errorString;
+ QSet<QAbstractState *> pendingErrorStates;
+ QSet<QAbstractState *> pendingErrorStatesForDefaultEntry;
+
+#ifndef QT_NO_ANIMATION
+ bool animationsEnabled;
+
+ QPair<QList<QAbstractAnimation*>, QList<QAbstractAnimation*> >
+ initializeAnimation(QAbstractAnimation *abstractAnimation,
+ const QPropertyAssignment &prop);
+
+ QHash<QAbstractState*, QList<QAbstractAnimation*> > animationsForState;
+ QHash<QAbstractAnimation*, QPropertyAssignment> propertyForAnimation;
+ QHash<QAbstractAnimation*, QAbstractState*> stateForAnimation;
+ QSet<QAbstractAnimation*> resetAnimationEndValues;
+
+ QList<QAbstractAnimation *> defaultAnimations;
+ QMultiHash<QAbstractState *, QAbstractAnimation *> defaultAnimationsForSource;
+ QMultiHash<QAbstractState *, QAbstractAnimation *> defaultAnimationsForTarget;
+
+#endif // QT_NO_ANIMATION
+
+ QSignalEventGenerator *signalEventGenerator;
+
+ QHash<const QObject*, QVector<int> > connections;
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+ QHash<QObject*, QHash<QEvent::Type, int> > qobjectEvents;
+#endif
+ QHash<int, QEvent*> delayedEvents;
+
+ typedef QEvent* (*f_cloneEvent)(QEvent*);
+ struct Handler {
+ f_cloneEvent cloneEvent;
+ };
+
+ static const Handler *handler;
+};
+
+Q_CORE_EXPORT const QStateMachinePrivate::Handler *qcoreStateMachineHandler();
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qwrappedevent.h b/src/corelib/statemachine/qwrappedevent.h
new file mode 100644
index 0000000..bde4d57
--- /dev/null
+++ b/src/corelib/statemachine/qwrappedevent.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWRAPPEDEVENT_H
+#define QWRAPPEDEVENT_H
+
+#include <QtCore/qcoreevent.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_STATEMACHINE
+
+class QObject;
+
+class Q_CORE_EXPORT QWrappedEvent : public QEvent
+{
+public:
+ QWrappedEvent(QObject *object, QEvent *event);
+ ~QWrappedEvent();
+
+ inline QObject *object() const { return m_object; }
+ inline QEvent *event() const { return m_event; }
+
+private:
+ QObject *m_object;
+ QEvent *m_event;
+
+private:
+ Q_DISABLE_COPY(QWrappedEvent)
+};
+
+#endif //QT_NO_STATEMACHINE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/statemachine.pri b/src/corelib/statemachine/statemachine.pri
new file mode 100644
index 0000000..5b19bc1
--- /dev/null
+++ b/src/corelib/statemachine/statemachine.pri
@@ -0,0 +1,30 @@
+HEADERS += $$PWD/qstatemachine.h \
+ $$PWD/qstatemachine_p.h \
+ $$PWD/qsignaleventgenerator_p.h \
+ $$PWD/qabstractstate.h \
+ $$PWD/qabstractstate_p.h \
+ $$PWD/qstate.h \
+ $$PWD/qstate_p.h \
+ $$PWD/qfinalstate.h \
+ $$PWD/qhistorystate.h \
+ $$PWD/qhistorystate_p.h \
+ $$PWD/qabstracttransition.h \
+ $$PWD/qabstracttransition_p.h \
+ $$PWD/qsignalevent.h \
+ $$PWD/qsignaltransition.h \
+ $$PWD/qsignaltransition_p.h
+
+SOURCES += $$PWD/qstatemachine.cpp \
+ $$PWD/qabstractstate.cpp \
+ $$PWD/qstate.cpp \
+ $$PWD/qfinalstate.cpp \
+ $$PWD/qhistorystate.cpp \
+ $$PWD/qabstracttransition.cpp \
+ $$PWD/qsignaltransition.cpp
+
+!contains(DEFINES, QT_NO_STATEMACHINE_EVENTFILTER) {
+HEADERS += $$PWD/qwrappedevent.h \
+ $$PWD/qeventtransition.h \
+ $$PWD/qeventtransition_p.h
+SOURCES += $$PWD/qeventtransition.cpp
+}
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp
index 4c0247c..e0fcc5f 100644
--- a/src/corelib/thread/qmutex.cpp
+++ b/src/corelib/thread/qmutex.cpp
@@ -56,8 +56,6 @@ QT_BEGIN_NAMESPACE
\threadsafe
\ingroup thread
- \ingroup environment
- \mainclass
The purpose of a QMutex is to protect an object, data structure or
section of code so that only one thread can access it at a time
@@ -416,7 +414,6 @@ void QMutex::unlock()
\threadsafe
\ingroup thread
- \ingroup environment
Locking and unlocking a QMutex in complex functions and
statements or in exception handling code is error-prone and
diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp
index e23d8a7..5b45dd0 100644
--- a/src/corelib/thread/qmutex_unix.cpp
+++ b/src/corelib/thread/qmutex_unix.cpp
@@ -49,6 +49,10 @@
#include <errno.h>
+#if defined(Q_OS_VXWORKS) && defined(wakeup)
+#undef wakeup
+#endif
+
QT_BEGIN_NAMESPACE
static void report_error(int code, const char *where, const char *what)
diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp
index cc21448..b82a75e 100644
--- a/src/corelib/thread/qmutex_win.cpp
+++ b/src/corelib/thread/qmutex_win.cpp
@@ -39,7 +39,7 @@
**
****************************************************************************/
-#include <windows.h>
+#include <qt_windows.h>
#include "qmutex.h"
#include <qatomic.h>
@@ -50,19 +50,7 @@ QT_BEGIN_NAMESPACE
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
: recursive(mode == QMutex::Recursive), contenders(0), lastSpinCount(0), owner(0), count(0)
{
- if (QSysInfo::WindowsVersion == 0) {
- // mutex was created before initializing WindowsVersion. this
- // can happen when creating the resource file engine handler,
- // for example. try again with just the A version
-#ifdef Q_OS_WINCE
- event = CreateEventW(0, FALSE, FALSE, 0);
-#else
- event = CreateEventA(0, FALSE, FALSE, 0);
-#endif
- } else {
- event = QT_WA_INLINE(CreateEventW(0, FALSE, FALSE, 0),
- CreateEventA(0, FALSE, FALSE, 0));
- }
+ event = CreateEvent(0, FALSE, FALSE, 0);
if (!event)
qWarning("QMutexPrivate::QMutexPrivate: Cannot create event");
}
diff --git a/src/corelib/thread/qmutexpool.cpp b/src/corelib/thread/qmutexpool.cpp
index ebba033..dfb4d6c 100644
--- a/src/corelib/thread/qmutexpool.cpp
+++ b/src/corelib/thread/qmutexpool.cpp
@@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE
// qt_global_mutexpool is here for backwards compatability only,
// use QMutexpool::instance() in new clode.
Q_CORE_EXPORT QMutexPool *qt_global_mutexpool = 0;
-Q_GLOBAL_STATIC_WITH_ARGS(QMutexPool, globalMutexPool, (true))
+Q_GLOBAL_STATIC_WITH_ARGS(QMutexPool, globalMutexPool, (QMutex::Recursive))
/*!
\class QMutexPool
@@ -88,17 +88,17 @@ Q_GLOBAL_STATIC_WITH_ARGS(QMutexPool, globalMutexPool, (true))
*/
/*!
- Constructs a QMutexPool, reserving space for \a size QMutexes. If
- \a recursive is true, all QMutexes in the pool will be recursive
- mutexes; otherwise they will all be non-recursive (the default).
+ Constructs a QMutexPool, reserving space for \a size QMutexes. All
+ mutexes in the pool are created with \a recursionMode. By default,
+ all mutexes are non-recursive.
The QMutexes are created when needed, and deleted when the
QMutexPool is destructed.
*/
-QMutexPool::QMutexPool(bool recursive, int size)
- : mutexes(size), count(size), recurs(recursive)
+QMutexPool::QMutexPool(QMutex::RecursionMode recursionMode, int size)
+ : mutexes(size), recursionMode(recursionMode)
{
- for (int index = 0; index < count; ++index) {
+ for (int index = 0; index < mutexes.count(); ++index) {
mutexes[index] = 0;
}
}
@@ -109,7 +109,7 @@ QMutexPool::QMutexPool(bool recursive, int size)
*/
QMutexPool::~QMutexPool()
{
- for (int index = 0; index < count; ++index) {
+ for (int index = 0; index < mutexes.count(); ++index) {
delete mutexes[index];
mutexes[index] = 0;
}
@@ -130,11 +130,11 @@ QMutexPool *QMutexPool::instance()
QMutex *QMutexPool::get(const void *address)
{
Q_ASSERT_X(address != 0, "QMutexPool::get()", "'address' argument cannot be zero");
- int index = int((quintptr(address) >> (sizeof(address) >> 1)) % count);
+ int index = int((quintptr(address) >> (sizeof(address) >> 1)) % mutexes.count());
if (!mutexes[index]) {
// mutex not created, create one
- QMutex *newMutex = new QMutex(recurs ? QMutex::Recursive : QMutex::NonRecursive);
+ QMutex *newMutex = new QMutex(recursionMode);
if (!mutexes[index].testAndSetOrdered(0, newMutex))
delete newMutex;
}
diff --git a/src/corelib/thread/qmutexpool_p.h b/src/corelib/thread/qmutexpool_p.h
index ea16b72..d5d4b9e 100644
--- a/src/corelib/thread/qmutexpool_p.h
+++ b/src/corelib/thread/qmutexpool_p.h
@@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QMutexPool
{
public:
- explicit QMutexPool(bool recursive = false, int size = 128);
+ explicit QMutexPool(QMutex::RecursionMode recursionMode = QMutex::NonRecursive, int size = 131);
~QMutexPool();
QMutex *get(const void *address);
@@ -72,9 +72,8 @@ public:
static QMutex *globalInstanceGet(const void *address);
private:
- QVarLengthArray<QAtomicPointer<QMutex>, 128> mutexes;
- int count;
- bool recurs;
+ QVarLengthArray<QAtomicPointer<QMutex>, 131> mutexes;
+ QMutex::RecursionMode recursionMode;
};
extern Q_CORE_EXPORT QMutexPool *qt_global_mutexpool;
diff --git a/src/corelib/thread/qreadwritelock.cpp b/src/corelib/thread/qreadwritelock.cpp
index 2c28353..0923c41 100644
--- a/src/corelib/thread/qreadwritelock.cpp
+++ b/src/corelib/thread/qreadwritelock.cpp
@@ -57,7 +57,6 @@ QT_BEGIN_NAMESPACE
\threadsafe
\ingroup thread
- \ingroup environment
A read-write lock is a synchronization tool for protecting
resources that can be accessed for reading and writing. This type
@@ -441,7 +440,6 @@ void QReadWriteLock::unlock()
\threadsafe
\ingroup thread
- \ingroup environment
The purpose of QReadLocker (and QWriteLocker) is to simplify
QReadWriteLock locking and unlocking. Locking and unlocking
@@ -514,7 +512,6 @@ void QReadWriteLock::unlock()
\threadsafe
\ingroup thread
- \ingroup environment
The purpose of QWriteLocker (and QReadLocker is to simplify
QReadWriteLock locking and unlocking. Locking and unlocking
diff --git a/src/corelib/thread/qreadwritelock.h b/src/corelib/thread/qreadwritelock.h
index ea97f541..bd07df6 100644
--- a/src/corelib/thread/qreadwritelock.h
+++ b/src/corelib/thread/qreadwritelock.h
@@ -190,7 +190,8 @@ inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock)
class Q_CORE_EXPORT QReadWriteLock
{
public:
- inline explicit QReadWriteLock() { }
+ enum RecursionMode { NonRecursive, Recursive };
+ inline explicit QReadWriteLock(RecursionMode = NonRecursive) { }
inline ~QReadWriteLock() { }
static inline void lockForRead() { }
diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp
index dd055f7..ecf91c7 100644
--- a/src/corelib/thread/qsemaphore.cpp
+++ b/src/corelib/thread/qsemaphore.cpp
@@ -54,7 +54,6 @@ QT_BEGIN_NAMESPACE
\threadsafe
\ingroup thread
- \ingroup environment
A semaphore is a generalization of a mutex. While a mutex can
only be locked once, it's possible to acquire a semaphore
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index fdd73d0..bac4e44 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -113,12 +113,6 @@ QThreadData::~QThreadData()
// fprintf(stderr, "QThreadData %p destroyed\n", this);
}
-QThreadData *QThreadData::get2(QThread *thread)
-{
- Q_ASSERT_X(thread != 0, "QThread", "internal error");
- return thread->d_func()->data;
-}
-
void QThreadData::ref()
{
#ifndef QT_NO_THREAD
@@ -135,35 +129,6 @@ void QThreadData::deref()
#endif
}
-
-#ifndef QT_NO_THREAD
-/*
- QThreadPrivate
-*/
-
-QThreadPrivate::QThreadPrivate(QThreadData *d)
- : QObjectPrivate(), running(false), finished(false), terminated(false),
- stackSize(0), priority(QThread::InheritPriority), data(d)
-{
-#if defined (Q_OS_UNIX)
- thread_id = 0;
-#elif defined (Q_WS_WIN)
- handle = 0;
- id = 0;
- waiters = 0;
- terminationEnabled = true;
- terminatePending = false;
-#endif
-
- if (!data)
- data = new QThreadData;
-}
-
-QThreadPrivate::~QThreadPrivate()
-{
- data->deref();
-}
-
/*
QAdoptedThread
*/
@@ -173,25 +138,28 @@ QAdoptedThread::QAdoptedThread(QThreadData *data)
{
// thread should be running and not finished for the lifetime
// of the application (even if QCoreApplication goes away)
+#ifndef QT_NO_THREAD
d_func()->running = true;
d_func()->finished = false;
init();
+#endif
// fprintf(stderr, "new QAdoptedThread = %p\n", this);
}
QAdoptedThread::~QAdoptedThread()
{
+#ifndef QT_NO_THREAD
QThreadPrivate::finish(this);
-
+#endif
// fprintf(stderr, "~QAdoptedThread = %p\n", this);
}
QThread *QAdoptedThread::createThreadForAdoption()
{
- QThread *t = new QAdoptedThread(0);
- t->moveToThread(t);
- return t;
+ QScopedPointer<QThread> t(new QAdoptedThread(0));
+ t->moveToThread(t.data());
+ return t.take();
}
void QAdoptedThread::run()
@@ -199,14 +167,41 @@ void QAdoptedThread::run()
// this function should never be called
qFatal("QAdoptedThread::run(): Internal error, this implementation should never be called.");
}
+#ifndef QT_NO_THREAD
+/*
+ QThreadPrivate
+*/
+
+QThreadPrivate::QThreadPrivate(QThreadData *d)
+ : QObjectPrivate(), running(false), finished(false), terminated(false),
+ stackSize(0), priority(QThread::InheritPriority), data(d)
+{
+#if defined (Q_OS_UNIX)
+ thread_id = 0;
+#elif defined (Q_WS_WIN)
+ handle = 0;
+ id = 0;
+ waiters = 0;
+#endif
+#if defined (Q_WS_WIN) || defined (Q_OS_SYMBIAN)
+ terminationEnabled = true;
+ terminatePending = false;
+#endif
+
+ if (!data)
+ data = new QThreadData;
+}
+
+QThreadPrivate::~QThreadPrivate()
+{
+ data->deref();
+}
/*!
\class QThread
\brief The QThread class provides platform-independent threads.
\ingroup thread
- \ingroup environment
- \mainclass
A QThread represents a separate thread of control within the
program; it shares data with all the other threads within the
@@ -267,9 +262,14 @@ void QAdoptedThread::run()
Returns the thread handle of the currently executing thread.
\warning The handle returned by this function is used for internal
- purposes and should not be used in any application code. On
- Windows, the returned value is a pseudo-handle for the current
- thread that cannot be used for numerical comparison.
+ purposes and should not be used in any application code.
+
+ \warning On Windows, the returned value is a pseudo-handle for the
+ current thread. It can't be used for numerical comparison. i.e.,
+ this function returns the DWORD (Windows-Thread ID) returned by
+ the Win32 function getCurrentThreadId(), not the HANDLE
+ (Windows-Thread HANDLE) returned by the Win32 function
+ getCurrentThread().
*/
/*!
@@ -480,10 +480,10 @@ uint QThread::stackSize() const
int QThread::exec()
{
Q_D(QThread);
- d->mutex.lock();
+ QMutexLocker locker(&d->mutex);
d->data->quitNow = false;
QEventLoop eventLoop;
- d->mutex.unlock();
+ locker.unlock();
int returnCode = eventLoop.exec();
return returnCode;
}
@@ -716,25 +716,37 @@ QThread::Priority QThread::priority() const
#else // QT_NO_THREAD
-QT_BEGIN_INCLUDE_NAMESPACE
-#include <private/qcoreapplication_p.h>
-QT_END_INCLUDE_NAMESPACE
-
-Q_GLOBAL_STATIC_WITH_ARGS(QThreadData, staticThreadData, (0));
-QThread* QThread::instance = 0;
-
-QThread::QThread() : QObject(*new QThreadPrivate, (QObject*)0)
-{
+QThread::QThread(QObject *parent)
+ : QObject(*(new QThreadPrivate), (QObject*)0){
Q_D(QThread);
d->data->thread = this;
- QCoreApplicationPrivate::theMainThread = this;
+}
+
+QThread *QThread::currentThread()
+{
+ return QThreadData::current()->thread;
}
QThreadData* QThreadData::current()
{
- if (QThread::instance)
- return QThread::instance->d_func()->data;
- return staticThreadData();
+ static QThreadData *data = 0; // reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key));
+ if (!data) {
+ QScopedPointer<QThreadData> newdata(new QThreadData);
+ newdata->thread = new QAdoptedThread(newdata.data());
+ data = newdata.take();
+ data->deref();
+ }
+ return data;
+}
+
+/*! \internal
+ */
+QThread::QThread(QThreadPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+ Q_D(QThread);
+ // fprintf(stderr, "QThreadData %p taken from private data for thread %p\n", d->data, this);
+ d->data->thread = this;
}
#endif // QT_NO_THREAD
diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h
index d0c6ea3..17beec3 100644
--- a/src/corelib/thread/qthread.h
+++ b/src/corelib/thread/qthread.h
@@ -142,15 +142,18 @@ class Q_CORE_EXPORT QThread : public QObject
{
public:
static Qt::HANDLE currentThreadId() { return Qt::HANDLE(currentThread()); }
- static QThread* currentThread()
- { if (!instance) instance = new QThread(); return instance; }
+ static QThread* currentThread();
+
+protected:
+ QThread(QThreadPrivate &dd, QObject *parent = 0);
private:
- QThread();
+ explicit QThread(QObject *parent = 0);
static QThread *instance;
friend class QCoreApplication;
friend class QThreadData;
+ friend class QAdoptedThread;
Q_DECLARE_PRIVATE(QThread)
};
diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h
index d8627e4..4ba137e 100644
--- a/src/corelib/thread/qthread_p.h
+++ b/src/corelib/thread/qthread_p.h
@@ -62,6 +62,10 @@
#include "QtCore/qmap.h"
#include "private/qobject_p.h"
+#ifdef Q_OS_SYMBIAN
+#include <e32base.h>
+#endif
+
QT_BEGIN_NAMESPACE
class QAbstractEventDispatcher;
@@ -107,32 +111,6 @@ public:
{ }
};
-class Q_CORE_EXPORT QThreadData
-{
- QAtomicInt _ref;
-
-public:
- QThreadData(int initialRefCount = 1);
- ~QThreadData();
-
- static QThreadData *current();
- static QThreadData *get2(QThread *thread);
-
- void ref();
- void deref();
-
- QThread *thread;
- bool quitNow;
- int loopLevel;
- QAbstractEventDispatcher *eventDispatcher;
- QStack<QEventLoop *> eventLoops;
- QPostEventList postEventList;
- bool canWait;
- QMap<int, void *> tls;
-
- QMutex mutex;
-};
-
#ifndef QT_NO_THREAD
class QThreadPrivate : public QObjectPrivate
{
@@ -158,46 +136,37 @@ public:
QWaitCondition thread_done;
static void *start(void *arg);
- static void finish(void *arg);
+#if defined(Q_OS_SYMBIAN)
+ static void finish(void *arg, bool lockAnyway=true, bool closeNativeHandle=true);
+#else
+ static void finish(void *);
#endif
+#endif // Q_OS_UNIX
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
HANDLE handle;
unsigned int id;
int waiters;
- bool terminationEnabled, terminatePending;
static unsigned int __stdcall start(void *);
static void finish(void *, bool lockAnyway=true);
#endif // Q_OS_WIN32
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN)
+ bool terminationEnabled, terminatePending;
+# endif
QThreadData *data;
static void createEventDispatcher(QThreadData *data);
};
-// thread wrapper for the main() thread
-class QAdoptedThread : public QThread
-{
- Q_DECLARE_PRIVATE(QThread)
-
-public:
- QAdoptedThread(QThreadData *data = 0);
- ~QAdoptedThread();
- void init();
-
- static QThread *createThreadForAdoption();
-private:
- void run();
-};
-
#else // QT_NO_THREAD
class QThreadPrivate : public QObjectPrivate
{
public:
- QThreadPrivate() : data(QThreadData::current()) {}
- ~QThreadPrivate() { }
+ QThreadPrivate(QThreadData *d = 0) : data(d ? d : new QThreadData) {}
+ ~QThreadPrivate() { delete data; }
QThreadData *data;
@@ -210,6 +179,53 @@ public:
#endif // QT_NO_THREAD
+class QThreadData
+{
+ QAtomicInt _ref;
+
+public:
+ QThreadData(int initialRefCount = 1);
+ ~QThreadData();
+
+ static QThreadData *current();
+ static QThreadData *get2(QThread *thread)
+ { Q_ASSERT_X(thread != 0, "QThread", "internal error"); return thread->d_func()->data; }
+
+
+ void ref();
+ void deref();
+
+ QThread *thread;
+ bool quitNow;
+ int loopLevel;
+ QAbstractEventDispatcher *eventDispatcher;
+ QStack<QEventLoop *> eventLoops;
+ QPostEventList postEventList;
+ bool canWait;
+ QMap<int, void *> tls;
+
+ QMutex mutex;
+
+# ifdef Q_OS_SYMBIAN
+ RThread symbian_thread_handle;
+# endif
+};
+
+// thread wrapper for the main() thread
+class QAdoptedThread : public QThread
+{
+ Q_DECLARE_PRIVATE(QThread)
+
+public:
+ QAdoptedThread(QThreadData *data = 0);
+ ~QAdoptedThread();
+ void init();
+
+ static QThread *createThreadForAdoption();
+private:
+ void run();
+};
+
QT_END_NAMESPACE
#endif // QTHREAD_P_H
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp
index 91fdb51..6fe00a5 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -47,7 +47,12 @@
#if !defined(QT_NO_GLIB)
# include "../kernel/qeventdispatcher_glib_p.h"
#endif
+
+#ifdef Q_OS_SYMBIAN
+#include <private/qeventdispatcher_symbian_p.h>
+#else
#include <private/qeventdispatcher_unix_p.h>
+#endif
#include "qthreadstorage.h"
@@ -61,6 +66,13 @@
#ifdef Q_OS_BSD4
#include <sys/sysctl.h>
#endif
+#ifdef Q_OS_VXWORKS
+# if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
+# include <vxCpuLib.h>
+# include <cpuset.h>
+# define QT_VXWORKS_HAS_CPUSET
+# endif
+#endif
#if defined(Q_OS_MAC)
# ifdef qDebug
@@ -85,6 +97,13 @@ static pthread_key_t current_thread_data_key;
static void destroy_current_thread_data(void *p)
{
+#if defined(Q_OS_VXWORKS)
+ // Calling setspecific(..., 0) sets the value to 0 for ALL threads.
+ // The 'set to 1' workaround adds a bit of an overhead though,
+ // since this function is called twice now.
+ if (p == (void *)1)
+ return;
+#endif
// POSIX says the value in our key is set to zero before calling
// this destructor function, so we need to set it back to the
// right value...
@@ -93,7 +112,12 @@ static void destroy_current_thread_data(void *p)
// ... but we must reset it to zero before returning so we aren't
// called again (POSIX allows implementations to call destructor
// functions repeatedly until all values are zero)
- pthread_setspecific(current_thread_data_key, 0);
+ pthread_setspecific(current_thread_data_key,
+#if defined(Q_OS_VXWORKS)
+ (void *)1);
+#else
+ 0);
+#endif
}
static void create_current_thread_data_key()
@@ -119,7 +143,14 @@ QThreadData *QThreadData::current()
} else {
data = new QThreadData;
pthread_setspecific(current_thread_data_key, data);
- data->thread = new QAdoptedThread(data);
+ QT_TRY {
+ data->thread = new QAdoptedThread(data);
+ } QT_CATCH(...) {
+ pthread_setspecific(current_thread_data_key, 0);
+ data->deref();
+ data = 0;
+ QT_RETHROW;
+ }
data->deref();
}
if (!QCoreApplicationPrivate::theMainThread)
@@ -131,7 +162,13 @@ QThreadData *QThreadData::current()
void QAdoptedThread::init()
{
- d_func()->thread_id = pthread_self();
+ Q_D(QThread);
+ d->thread_id = pthread_self();
+#ifdef Q_OS_SYMBIAN
+ d->data->symbian_thread_handle = RThread();
+ TThreadId threadId = d->data->symbian_thread_handle.Id();
+ d->data->symbian_thread_handle.Open(threadId);
+#endif
}
/*
@@ -159,7 +196,11 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data)
data->eventDispatcher = new QEventDispatcherGlib;
else
#endif
+#ifdef Q_OS_SYMBIAN
+ data->eventDispatcher = new QEventDispatcherSymbian;
+#else
data->eventDispatcher = new QEventDispatcherUNIX;
+#endif
data->eventDispatcher->startingUp();
}
@@ -167,12 +208,25 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data)
void *QThreadPrivate::start(void *arg)
{
+ // Symbian Open C supports neither thread cancellation nor cleanup_push.
+#ifndef Q_OS_SYMBIAN
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
pthread_cleanup_push(QThreadPrivate::finish, arg);
+#endif
QThread *thr = reinterpret_cast<QThread *>(arg);
QThreadData *data = QThreadData::get2(thr);
+#ifdef Q_OS_SYMBIAN
+ // Because Symbian Open C does not provide a way to convert between
+ // RThread and pthread_t, we must delay initialization of the RThread
+ // handle when creating a thread, until we are running in the new thread.
+ // Here, we pick up the current thread and assign that to the handle.
+ data->symbian_thread_handle = RThread();
+ TThreadId threadId = data->symbian_thread_handle.Id();
+ data->symbian_thread_handle.Open(threadId);
+#endif
+
pthread_once(&current_thread_data_once, create_current_thread_data_key);
pthread_setspecific(current_thread_data_key, data);
@@ -183,19 +237,33 @@ void *QThreadPrivate::start(void *arg)
createEventDispatcher(data);
emit thr->started();
+#ifndef Q_OS_SYMBIAN
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_testcancel();
+#endif
thr->run();
+#ifdef Q_OS_SYMBIAN
+ QThreadPrivate::finish(arg);
+#else
pthread_cleanup_pop(1);
+#endif
+
return 0;
}
+#ifdef Q_OS_SYMBIAN
+void QThreadPrivate::finish(void *arg, bool lockAnyway, bool closeNativeHandle)
+#else
void QThreadPrivate::finish(void *arg)
+#endif
{
QThread *thr = reinterpret_cast<QThread *>(arg);
QThreadPrivate *d = thr->d_func();
- QMutexLocker locker(&d->mutex);
+#ifdef Q_OS_SYMBIAN
+ if (lockAnyway)
+#endif
+ d->mutex.lock();
d->priority = QThread::InheritPriority;
d->running = false;
@@ -216,7 +284,15 @@ void QThreadPrivate::finish(void *arg)
QThreadStorageData::finish((void **)data);
d->thread_id = 0;
+#ifdef Q_OS_SYMBIAN
+ if (closeNativeHandle)
+ d->data->symbian_thread_handle.Close();
+#endif
d->thread_done.wakeAll();
+#ifdef Q_OS_SYMBIAN
+ if (lockAnyway)
+#endif
+ d->mutex.unlock();
}
@@ -267,7 +343,28 @@ int QThread::idealThreadCount()
// IRIX
cores = (int)sysconf(_SC_NPROC_ONLN);
#elif defined(Q_OS_INTEGRITY)
- // ### TODO - how to get the amound of CPUs on INTEGRITY?
+ // as of aug 2008 Integrity only supports one single core CPU
+ cores = 1;
+#elif defined(Q_OS_SYMBIAN)
+ // ### TODO - Get the number of cores from HAL? when multicore architectures (SMP) are supported
+ cores = 1;
+#elif defined(Q_OS_VXWORKS)
+ // VxWorks
+# if defined(QT_VXWORKS_HAS_CPUSET)
+ cpuset_t cpus = vxCpuEnabledGet();
+ cores = 0;
+
+ // 128 cores should be enough for everyone ;)
+ for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
+ if (CPUSET_ISSET(cpus, i)) {
+ CPUSET_CLR(cpus, i);
+ cores++;
+ }
+ }
+# else
+ // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
+ cores = 1;
+# endif
#else
// the rest: Linux, Solaris, AIX, Tru64
cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
@@ -352,7 +449,8 @@ void QThread::start(Priority priority)
d->priority = priority;
-#if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
+#if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && !defined(Q_OS_SYMBIAN) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
+// ### Need to implement thread sheduling and priorities for symbian os. Implementation removed for now
switch (priority) {
case InheritPriority:
{
@@ -410,6 +508,13 @@ void QThread::start(Priority priority)
}
#endif // _POSIX_THREAD_PRIORITY_SCHEDULING
+#ifdef Q_OS_SYMBIAN
+ if (d->stackSize == 0)
+ // The default stack size on Symbian is very small, making even basic
+ // operations like file I/O fail, so we increase it by default.
+ d->stackSize = 0x14000; // Maximum stack size on Symbian.
+#endif
+
if (d->stackSize > 0) {
#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
int code = pthread_attr_setstacksize(&attr, d->stackSize);
@@ -434,7 +539,9 @@ void QThread::start(Priority priority)
if (code == EPERM) {
// caller does not have permission to set the scheduling
// parameters/policy
+#ifndef Q_OS_SYMBIAN
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
+#endif
code =
pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
}
@@ -447,6 +554,9 @@ void QThread::start(Priority priority)
d->running = false;
d->finished = false;
d->thread_id = 0;
+#ifdef Q_OS_SYMBIAN
+ d->data->symbian_thread_handle.Close();
+#endif
}
}
@@ -458,6 +568,7 @@ void QThread::terminate()
if (!d->thread_id)
return;
+#ifndef Q_OS_SYMBIAN
int code = pthread_cancel(d->thread_id);
if (code) {
qWarning("QThread::start: Thread termination error: %s",
@@ -465,6 +576,26 @@ void QThread::terminate()
} else {
d->terminated = true;
}
+#else
+ if (!d->running)
+ return;
+ if (!d->terminationEnabled) {
+ d->terminatePending = true;
+ return;
+ }
+
+ d->terminated = true;
+ // "false, false" meaning:
+ // 1. lockAnyway = false. Don't lock the mutex because it's already locked
+ // (see above).
+ // 2. closeNativeSymbianHandle = false. We don't want to close the thread handle,
+ // because we need it here to terminate the thread.
+ QThreadPrivate::finish(this, false, false);
+ d->data->symbian_thread_handle.Terminate(KErrNone);
+ d->data->symbian_thread_handle.Close();
+#endif
+
+
}
bool QThread::wait(unsigned long time)
@@ -489,11 +620,27 @@ bool QThread::wait(unsigned long time)
void QThread::setTerminationEnabled(bool enabled)
{
- Q_ASSERT_X(currentThread() != 0, "QThread::setTerminationEnabled()",
+ QThread *thr = currentThread();
+ Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()",
"Current thread was not started with QThread.");
+#ifndef Q_OS_SYMBIAN
pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);
if (enabled)
pthread_testcancel();
+#else
+ QThreadPrivate *d = thr->d_func();
+ QMutexLocker locker(&d->mutex);
+ d->terminationEnabled = enabled;
+ if (enabled && d->terminatePending) {
+ d->terminated = true;
+ // "false" meaning:
+ // - lockAnyway = false. Don't lock the mutex because it's already locked
+ // (see above).
+ QThreadPrivate::finish(thr, false);
+ locker.unlock(); // don't leave the mutex locked!
+ pthread_exit(NULL);
+ }
+#endif
}
void QThread::setPriority(Priority priority)
diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp
index ba20687..cd3c723 100644
--- a/src/corelib/thread/qthread_win.cpp
+++ b/src/corelib/thread/qthread_win.cpp
@@ -54,7 +54,7 @@
#include <private/qcoreapplication_p.h>
#include <private/qeventdispatcher_win_p.h>
-#include <windows.h>
+#include <qt_windows.h>
#ifndef Q_OS_WINCE
@@ -112,7 +112,14 @@ QThreadData *QThreadData::current()
// This needs to be called prior to new AdoptedThread() to
// avoid recursion.
TlsSetValue(qt_current_thread_data_tls_index, threadData);
- threadData->thread = new QAdoptedThread(threadData);
+ QT_TRY {
+ threadData->thread = new QAdoptedThread(threadData);
+ } QT_CATCH(...) {
+ TlsSetValue(qt_current_thread_data_tls_index, 0);
+ threadData->deref();
+ threadData = 0;
+ QT_RETHROW;
+ }
threadData->deref();
}
@@ -163,8 +170,7 @@ void qt_watch_adopted_thread(const HANDLE adoptedThreadHandle, QThread *qthread)
// Start watcher thread if it is not already running.
if (qt_adopted_thread_watcher_handle == 0) {
if (qt_adopted_thread_wakeup == 0) {
- qt_adopted_thread_wakeup = QT_WA_INLINE(CreateEventW(0, false, false, 0),
- CreateEventA(0, false, false, 0));
+ qt_adopted_thread_wakeup = CreateEvent(0, false, false, 0);
qt_adopted_thread_handles.prepend(qt_adopted_thread_wakeup);
}
@@ -364,11 +370,10 @@ int QThread::idealThreadCount()
void QThread::yieldCurrentThread()
{
#ifndef Q_OS_WINCE
- if (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)
- SwitchToThread();
- else
+ SwitchToThread();
+#else
+ ::Sleep(0);
#endif
- ::Sleep(0);
}
void QThread::sleep(unsigned long secs)
@@ -419,17 +424,11 @@ void QThread::start(Priority priority)
return;
}
- // Since Win 9x will have problems if the priority is idle or time critical
- // we have to use the closest one instead
int prio;
d->priority = priority;
switch (d->priority) {
case IdlePriority:
- if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) {
- prio = THREAD_PRIORITY_LOWEST;
- } else {
- prio = THREAD_PRIORITY_IDLE;
- }
+ prio = THREAD_PRIORITY_IDLE;
break;
case LowestPriority:
@@ -453,11 +452,7 @@ void QThread::start(Priority priority)
break;
case TimeCriticalPriority:
- if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) {
- prio = THREAD_PRIORITY_HIGHEST;
- } else {
- prio = THREAD_PRIORITY_TIME_CRITICAL;
- }
+ prio = THREAD_PRIORITY_TIME_CRITICAL;
break;
case InheritPriority:
@@ -563,17 +558,11 @@ void QThread::setPriority(Priority priority)
// copied from start() with a few modifications:
- // Since Win 9x will have problems if the priority is idle or time critical
- // we have to use the closest one instead
int prio;
d->priority = priority;
switch (d->priority) {
case IdlePriority:
- if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) {
- prio = THREAD_PRIORITY_LOWEST;
- } else {
- prio = THREAD_PRIORITY_IDLE;
- }
+ prio = THREAD_PRIORITY_IDLE;
break;
case LowestPriority:
@@ -597,11 +586,7 @@ void QThread::setPriority(Priority priority)
break;
case TimeCriticalPriority:
- if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) {
- prio = THREAD_PRIORITY_HIGHEST;
- } else {
- prio = THREAD_PRIORITY_TIME_CRITICAL;
- }
+ prio = THREAD_PRIORITY_TIME_CRITICAL;
break;
case InheritPriority:
diff --git a/src/corelib/thread/qthreadstorage.cpp b/src/corelib/thread/qthreadstorage.cpp
index b072d81..a5a42e3 100644
--- a/src/corelib/thread/qthreadstorage.cpp
+++ b/src/corelib/thread/qthreadstorage.cpp
@@ -101,12 +101,14 @@ void **QThreadStorageData::get() const
qWarning("QThreadStorage::get: QThreadStorage can only be used with threads started with QThread");
return 0;
}
- QMap<int, void *>::iterator it = data->tls.find(id);
+ QMap<int, void *>::const_iterator it = data->tls.constFind(id);
DEBUG_MSG("QThreadStorageData: Returning storage %d, data %p, for thread %p",
id,
it != data->tls.end() ? it.value() : 0,
data->thread);
- return it != data->tls.end() && it.value() != 0 ? &it.value() : 0;
+ // const_cast below is a bit evil - but we have to make sure not to detach here
+ // otherwise we'll go bonkers in oom situations
+ return it != data->tls.constEnd() && it.value() != 0 ? const_cast<void **>(&it.value()) : 0;
}
void **QThreadStorageData::set(void *p)
@@ -129,9 +131,9 @@ void **QThreadStorageData::set(void *p)
void *q = it.value();
it.value() = 0;
- mutex()->lock();
+ QMutexLocker locker(mutex());
void (*destructor)(void *) = destructors()->value(id);
- mutex()->unlock();
+ locker.unlock();
destructor(q);
}
@@ -167,9 +169,9 @@ void QThreadStorageData::finish(void **p)
continue;
}
- mutex()->lock();
+ QMutexLocker locker(mutex());
void (*destructor)(void *) = destructors()->value(id);
- mutex()->unlock();
+ locker.unlock();
if (!destructor) {
if (QThread::currentThread())
@@ -189,8 +191,6 @@ void QThreadStorageData::finish(void **p)
\threadsafe
\ingroup thread
- \ingroup environment
- \mainclass
QThreadStorage is a template class that provides per-thread data
storage.
diff --git a/src/corelib/thread/qwaitcondition.qdoc b/src/corelib/thread/qwaitcondition.qdoc
new file mode 100644
index 0000000..4352cc7
--- /dev/null
+++ b/src/corelib/thread/qwaitcondition.qdoc
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QWaitCondition
+ \brief The QWaitCondition class provides a condition variable for
+ synchronizing threads.
+
+ \threadsafe
+
+ \ingroup thread
+
+ QWaitCondition allows a thread to tell other threads that some
+ sort of condition has been met. One or many threads can block
+ waiting for a QWaitCondition to set a condition with wakeOne() or
+ wakeAll(). Use wakeOne() to wake one randomly selected condition or
+ wakeAll() to wake them all.
+
+ For example, let's suppose that we have three tasks that should
+ be performed whenever the user presses a key. Each task could be
+ split into a thread, each of which would have a
+ \l{QThread::run()}{run()} body like this:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qwaitcondition_unix.cpp 0
+
+ Here, the \c keyPressed variable is a global variable of type
+ QWaitCondition.
+
+ A fourth thread would read key presses and wake the other three
+ threads up every time it receives one, like this:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qwaitcondition_unix.cpp 1
+
+ The order in which the three threads are woken up is undefined.
+ Also, if some of the threads are still in \c do_something() when
+ the key is pressed, they won't be woken up (since they're not
+ waiting on the condition variable) and so the task will not be
+ performed for that key press. This issue can be solved using a
+ counter and a QMutex to guard it. For example, here's the new
+ code for the worker threads:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qwaitcondition_unix.cpp 2
+
+ Here's the code for the fourth thread:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qwaitcondition_unix.cpp 3
+
+ The mutex is necessary because the results of two threads
+ attempting to change the value of the same variable
+ simultaneously are unpredictable.
+
+ Wait conditions are a powerful thread synchronization primitive.
+ The \l{threads/waitconditions}{Wait Conditions} example shows how
+ to use QWaitCondition as an alternative to QSemaphore for
+ controlling access to a circular buffer shared by a producer
+ thread and a consumer thread.
+
+ \sa QMutex, QSemaphore, QThread, {Wait Conditions Example}
+*/
+
+/*!
+ \fn QWaitCondition::QWaitCondition()
+
+ Constructs a new wait condition object.
+*/
+
+/*!
+ \fn QWaitCondition::~QWaitCondition()
+
+ Destroys the wait condition object.
+*/
+
+/*!
+ \fn void QWaitCondition::wakeOne()
+
+ Wakes one thread waiting on the wait condition. The thread that
+ is woken up depends on the operating system's scheduling
+ policies, and cannot be controlled or predicted.
+
+ If you want to wake up a specific thread, the solution is
+ typically to use different wait conditions and have different
+ threads wait on different conditions.
+
+ \sa wakeAll()
+*/
+
+/*!
+ \fn void QWaitCondition::wakeAll()
+
+ Wakes all threads waiting on the wait condition. The order in
+ which the threads are woken up depends on the operating system's
+ scheduling policies and cannot be controlled or predicted.
+
+ \sa wakeOne()
+*/
+
+/*!
+ \fn bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
+
+ Releases the locked \a mutex and waits on the wait condition. The
+ \a mutex must be initially locked by the calling thread. If \a
+ mutex is not in a locked state, this function returns
+ immediately. If \a mutex is a recursive mutex, this function
+ returns immediately. The \a mutex will be unlocked, and the
+ calling thread will block until either of these conditions is met:
+
+ \list
+ \o Another thread signals it using wakeOne() or wakeAll(). This
+ function will return true in this case.
+ \o \a time milliseconds has elapsed. If \a time is \c ULONG_MAX
+ (the default), then the wait will never timeout (the event
+ must be signalled). This function will return false if the
+ wait timed out.
+ \endlist
+
+ The mutex will be returned to the same locked state. This
+ function is provided to allow the atomic transition from the
+ locked state to the wait state.
+
+ \sa wakeOne(), wakeAll()
+*/
+
+/*!
+ \fn bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
+ \since 4.4
+
+ Releases the locked \a readWriteLock and waits on the wait
+ condition. The \a readWriteLock must be initially locked by the
+ calling thread. If \a readWriteLock is not in a locked state, this
+ function returns immediately. The \a readWriteLock must not be
+ locked recursively, otherwise this function will not release the
+ lock properly. The \a readWriteLock will be unlocked, and the
+ calling thread will block until either of these conditions is met:
+
+ \list
+ \o Another thread signals it using wakeOne() or wakeAll(). This
+ function will return true in this case.
+ \o \a time milliseconds has elapsed. If \a time is \c ULONG_MAX
+ (the default), then the wait will never timeout (the event
+ must be signalled). This function will return false if the
+ wait timed out.
+ \endlist
+
+ The \a readWriteLock will be returned to the same locked
+ state. This function is provided to allow the atomic transition
+ from the locked state to the wait state.
+
+ \sa wakeOne(), wakeAll()
+*/
diff --git a/src/corelib/thread/qwaitcondition_win.cpp b/src/corelib/thread/qwaitcondition_win.cpp
index 138cfcd..38f2aec 100644
--- a/src/corelib/thread/qwaitcondition_win.cpp
+++ b/src/corelib/thread/qwaitcondition_win.cpp
@@ -64,11 +64,7 @@ class QWaitConditionEvent
public:
inline QWaitConditionEvent() : priority(0), wokenUp(false)
{
- QT_WA ({
- event = CreateEvent(NULL, TRUE, FALSE, NULL);
- }, {
- event = CreateEventA(NULL, TRUE, FALSE, NULL);
- });
+ event = CreateEvent(NULL, TRUE, FALSE, NULL);
}
inline ~QWaitConditionEvent() { CloseHandle(event); }
int priority;
diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h
index 649ed19..4a8107d 100644
--- a/src/corelib/tools/qalgorithms.h
+++ b/src/corelib/tools/qalgorithms.h
@@ -141,23 +141,6 @@ inline void qCount(const Container &container, const T &value, Size &n)
qCount(container.constBegin(), container.constEnd(), value, n);
}
-
-#if defined Q_CC_MSVC && _MSC_VER < 1300
-template <typename T>
-inline void qSwap(T &value1, T &value2)
-{
- qSwap_helper<T>(value1, value2, (T *)0);
-}
-#else
-template <typename T>
-inline void qSwap(T &value1, T &value2)
-{
- T t = value1;
- value1 = value2;
- value2 = t;
-}
-#endif
-
#ifdef qdoc
template <typename T>
LessThan qLess()
diff --git a/src/corelib/tools/qalgorithms.qdoc b/src/corelib/tools/qalgorithms.qdoc
new file mode 100644
index 0000000..3b43b4e
--- /dev/null
+++ b/src/corelib/tools/qalgorithms.qdoc
@@ -0,0 +1,651 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \headerfile <QtAlgorithms>
+ \title Generic Algorithms
+ \ingroup funclists
+
+ \brief The <QtAlgorithms> header includes the generic, template-based algorithms.
+
+ Qt provides a number of global template functions in \c
+ <QtAlgorithms> that work on containers and perform well-know
+ algorithms. You can use these algorithms with any \l {container
+ class} that provides STL-style iterators, including Qt's QList,
+ QLinkedList, QVector, QMap, and QHash classes.
+
+ These functions have taken their inspiration from similar
+ functions available in the STL \c <algorithm> header. Most of them
+ have a direct STL equivalent; for example, qCopyBackward() is the
+ same as STL's copy_backward() algorithm.
+
+ If STL is available on all your target platforms, you can use the
+ STL algorithms instead of their Qt counterparts. One reason why
+ you might want to use the STL algorithms is that STL provides
+ dozens and dozens of algorithms, whereas Qt only provides the most
+ important ones, making no attempt to duplicate functionality that
+ is already provided by the C++ standard.
+
+ Most algorithms take \l {STL-style iterators} as parameters. The
+ algorithms are generic in the sense that they aren't bound to a
+ specific iterator class; you can use them with any iterators that
+ meet a certain set of requirements.
+
+ Let's take the qFill() algorithm as an example. Unlike QVector,
+ QList has no fill() function that can be used to fill a list with
+ a particular value. If you need that functionality, you can use
+ qFill():
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 0
+
+ qFill() takes a begin iterator, an end iterator, and a value.
+ In the example above, we pass \c list.begin() and \c list.end()
+ as the begin and end iterators, but this doesn't have to be
+ the case:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 1
+
+ Different algorithms can have different requirements for the
+ iterators they accept. For example, qFill() accepts two
+ \l {forward iterators}. The iterator types required are specified
+ for each algorithm. If an iterator of the wrong type is passed (for
+ example, if QList::ConstIterator is passed as an \l {output
+ iterator}), you will always get a compiler error, although not
+ necessarily a very informative one.
+
+ Some algorithms have special requirements on the value type
+ stored in the containers. For example, qEqual() requires that the
+ value type supports operator==(), which it uses to compare items.
+ Similarly, qDeleteAll() requires that the value type is a
+ non-const pointer type (for example, QWidget *). The value type
+ requirements are specified for each algorithm, and the compiler
+ will produce an error if a requirement isn't met.
+
+ \target binaryFind example
+
+ The generic algorithms can be used on other container classes
+ than those provided by Qt and STL. The syntax of STL-style
+ iterators is modeled after C++ pointers, so it's possible to use
+ plain arrays as containers and plain pointers as iterators. A
+ common idiom is to use qBinaryFind() together with two static
+ arrays: one that contains a list of keys, and another that
+ contains a list of associated values. For example, the following
+ code will look up an HTML entity (e.g., \c &amp;) in the \c
+ name_table array and return the corresponding Unicode value from
+ the \c value_table if the entity is recognized:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 2
+
+ This kind of code is for advanced users only; for most
+ applications, a QMap- or QHash-based approach would work just as
+ well:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 3
+
+ \section1 Types of Iterators
+
+ The algorithms have certain requirements on the iterator types
+ they accept, and these are specified individually for each
+ function. The compiler will produce an error if a requirement
+ isn't met.
+
+ \section2 Input Iterators
+
+ An \e{input iterator} is an iterator that can be used for reading
+ data sequentially from a container. It must provide the following
+ operators: \c{==} and \c{!=} for comparing two iterators, unary
+ \c{*} for retrieving the value stored in the item, and prefix
+ \c{++} for advancing to the next item.
+
+ The Qt containers' iterator types (const and non-const) are all
+ input iterators.
+
+ \section2 Output Iterators
+
+ An \e{output iterator} is an iterator that can be used for
+ writing data sequentially to a container or to some output
+ stream. It must provide the following operators: unary \c{*} for
+ writing a value (i.e., \c{*it = val}) and prefix \c{++} for
+ advancing to the next item.
+
+ The Qt containers' non-const iterator types are all output
+ iterators.
+
+ \section2 Forward Iterators
+
+ A \e{forward iterator} is an iterator that meets the requirements
+ of both input iterators and output iterators.
+
+ The Qt containers' non-const iterator types are all forward
+ iterators.
+
+ \section2 Bidirectional Iterators
+
+ A \e{bidirectional iterator} is an iterator that meets the
+ requirements of forward iterators but that in addition supports
+ prefix \c{--} for iterating backward.
+
+ The Qt containers' non-const iterator types are all bidirectional
+ iterators.
+
+ \section2 Random Access Iterators
+
+ The last category, \e{random access iterators}, is the most
+ powerful type of iterator. It supports all the requirements of a
+ bidirectional iterator, and supports the following operations:
+
+ \table
+ \row \i \c{i += n} \i advances iterator \c i by \c n positions
+ \row \i \c{i -= n} \i moves iterator \c i back by \c n positions
+ \row \i \c{i + n} or \c{n + i} \i returns the iterator for the item \c
+ n positions ahead of iterator \c i
+ \row \i \c{i - n} \i returns the iterator for the item \c n positions behind of iterator \c i
+ \row \i \c{i - j} \i returns the number of items between iterators \c i and \c j
+ \row \i \c{i[n]} \i same as \c{*(i + n)}
+ \row \i \c{i < j} \i returns true if iterator \c j comes after iterator \c i
+ \endtable
+
+ QList and QVector's non-const iterator types are random access iterators.
+
+ \sa {container classes}, <QtGlobal>
+*/
+
+/*! \fn OutputIterator qCopy(InputIterator begin1, InputIterator end1, OutputIterator begin2)
+ \relates <QtAlgorithms>
+
+ Copies the items from range [\a begin1, \a end1) to range [\a
+ begin2, ...), in the order in which they appear.
+
+ The item at position \a begin1 is assigned to that at position \a
+ begin2; the item at position \a begin1 + 1 is assigned to that at
+ position \a begin2 + 1; and so on.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 4
+
+ \sa qCopyBackward(), {input iterators}, {output iterators}
+*/
+
+/*! \fn BiIterator2 qCopyBackward(BiIterator1 begin1, BiIterator1 end1, BiIterator2 end2)
+ \relates <QtAlgorithms>
+
+ Copies the items from range [\a begin1, \a end1) to range [...,
+ \a end2).
+
+ The item at position \a end1 - 1 is assigned to that at position
+ \a end2 - 1; the item at position \a end1 - 2 is assigned to that
+ at position \a end2 - 2; and so on.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 5
+
+ \sa qCopy(), {bidirectional iterators}
+*/
+
+/*! \fn bool qEqual(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2)
+ \relates <QtAlgorithms>
+
+ Compares the items in the range [\a begin1, \a end1) with the
+ items in the range [\a begin2, ...). Returns true if all the
+ items compare equal; otherwise returns false.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 6
+
+ This function requires the item type (in the example above,
+ QString) to implement \c operator==().
+
+ \sa {input iterators}
+*/
+
+/*! \fn void qFill(ForwardIterator begin, ForwardIterator end, const T &value)
+ \relates <QtAlgorithms>
+
+ Fills the range [\a begin, \a end) with \a value.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 7
+
+ \sa qCopy(), {forward iterators}
+*/
+
+/*! \fn void qFill(Container &container, const T &value)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ This is the same as qFill(\a{container}.begin(), \a{container}.end(), \a value);
+*/
+
+/*! \fn InputIterator qFind(InputIterator begin, InputIterator end, const T &value)
+ \relates <QtAlgorithms>
+
+ Returns an iterator to the first occurrence of \a value in a
+ container in the range [\a begin, \a end). Returns \a end if \a
+ value isn't found.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 8
+
+ This function requires the item type (in the example above,
+ QString) to implement \c operator==().
+
+ If the items in the range are in ascending order, you can get
+ faster results by using qLowerBound() or qBinaryFind() instead of
+ qFind().
+
+ \sa qBinaryFind(), {input iterators}
+*/
+
+/*! \fn void qFind(const Container &container, const T &value)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ This is the same as qFind(\a{container}.begin(), \a{container}.end(), value);
+*/
+
+/*! \fn void qCount(InputIterator begin, InputIterator end, const T &value, Size &n)
+ \relates <QtAlgorithms>
+
+ Returns the number of occurrences of \a value in the range [\a begin, \a end),
+ which is returned in \a n. \a n is never initialized, the count is added to \a n.
+ It is the caller's responsibility to initialize \a n.
+
+ Example:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 9
+
+ This function requires the item type (in the example above,
+ \c int) to implement \c operator==().
+
+ \sa {input iterators}
+*/
+
+/*! \fn void qCount(const Container &container, const T &value, Size &n)
+\relates <QtAlgorithms>
+
+\overload
+
+Instead of operating on iterators, as in the other overload, this function
+operates on the specified \a container to obtain the number of instances
+of \a value in the variable passed as a reference in argument \a n.
+*/
+
+/*! \fn void qSwap(T &var1, T &var2)
+ \relates <QtAlgorithms>
+
+ Exchanges the values of variables \a var1 and \a var2.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 10
+*/
+
+/*! \fn void qSort(RandomAccessIterator begin, RandomAccessIterator end)
+ \relates <QtAlgorithms>
+
+ Sorts the items in range [\a begin, \a end) in ascending order
+ using the quicksort algorithm.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 11
+
+ The sort algorithm is efficient on large data sets. It operates
+ in \l {linear-logarithmic time}, O(\e{n} log \e{n}).
+
+ This function requires the item type (in the example above,
+ \c{int}) to implement \c operator<().
+
+ If neither of the two items is "less than" the other, the items are
+ taken to be equal. It is then undefined which one of the two
+ items will appear before the other after the sort.
+
+ \sa qStableSort(), {random access iterators}
+*/
+
+/*! \fn void qSort(RandomAccessIterator begin, RandomAccessIterator end, LessThan lessThan)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ Uses the \a lessThan function instead of \c operator<() to
+ compare the items.
+
+ For example, here's how to sort the strings in a QStringList
+ in case-insensitive alphabetical order:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 12
+
+ To sort values in reverse order, pass
+ \l{qGreater()}{qGreater<T>()} as the \a lessThan parameter. For
+ example:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 13
+
+ If neither of the two items is "less than" the other, the items are
+ taken to be equal. It is then undefined which one of the two
+ items will appear before the other after the sort.
+
+ An alternative to using qSort() is to put the items to sort in a
+ QMap, using the sort key as the QMap key. This is often more
+ convenient than defining a \a lessThan function. For example, the
+ following code shows how to sort a list of strings case
+ insensitively using QMap:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 14
+
+ \sa QMap
+*/
+
+/*! \fn void qSort(Container &container)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ This is the same as qSort(\a{container}.begin(), \a{container}.end());
+*/
+
+/*!
+ \fn void qStableSort(RandomAccessIterator begin, RandomAccessIterator end)
+ \relates <QtAlgorithms>
+
+ Sorts the items in range [\a begin, \a end) in ascending order
+ using a stable sorting algorithm.
+
+ If neither of the two items is "less than" the other, the items are
+ taken to be equal. The item that appeared before the other in the
+ original container will still appear first after the sort. This
+ property is often useful when sorting user-visible data.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 15
+
+ The sort algorithm is efficient on large data sets. It operates
+ in \l {linear-logarithmic time}, O(\e{n} log \e{n}).
+
+ This function requires the item type (in the example above,
+ \c{int}) to implement \c operator<().
+
+ \sa qSort(), {random access iterators}
+*/
+
+/*!
+ \fn void qStableSort(RandomAccessIterator begin, RandomAccessIterator end, LessThan lessThan)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ Uses the \a lessThan function instead of \c operator<() to
+ compare the items.
+
+ For example, here's how to sort the strings in a QStringList
+ in case-insensitive alphabetical order:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 16
+
+ Note that earlier versions of Qt allowed using a lessThan function that took its
+ arguments by non-const reference. From 4.3 and on this is no longer possible,
+ the arguments has to be passed by const reference or value.
+
+ To sort values in reverse order, pass
+ \l{qGreater()}{qGreater<T>()} as the \a lessThan parameter. For
+ example:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 17
+
+ If neither of the two items is "less than" the other, the items are
+ taken to be equal. The item that appeared before the other in the
+ original container will still appear first after the sort. This
+ property is often useful when sorting user-visible data.
+*/
+
+/*!
+ \fn void qStableSort(Container &container)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ This is the same as qStableSort(\a{container}.begin(), \a{container}.end());
+*/
+
+/*! \fn RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value)
+ \relates <QtAlgorithms>
+
+ Performs a binary search of the range [\a begin, \a end) and
+ returns the position of the first ocurrence of \a value. If no
+ such item is found, returns the position where it should be
+ inserted.
+
+ The items in the range [\a begin, \e end) must be sorted in
+ ascending order; see qSort().
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 18
+
+ This function requires the item type (in the example above,
+ \c{int}) to implement \c operator<().
+
+ qLowerBound() can be used in conjunction with qUpperBound() to
+ iterate over all occurrences of the same value:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 19
+
+ \sa qUpperBound(), qBinaryFind()
+*/
+
+/*!
+ \fn RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ Uses the \a lessThan function instead of \c operator<() to
+ compare the items.
+
+ Note that the items in the range must be sorted according to the order
+ specified by the \a lessThan object.
+*/
+
+/*!
+ \fn void qLowerBound(const Container &container, const T &value)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ For read-only iteration over containers, this function is broadly equivalent to
+ qLowerBound(\a{container}.begin(), \a{container}.end(), value). However, since it
+ returns a const iterator, you cannot use it to modify the container; for example,
+ to insert items.
+*/
+
+/*! \fn RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value)
+ \relates <QtAlgorithms>
+
+ Performs a binary search of the range [\a begin, \a end) and
+ returns the position of the one-past-the-last occurrence of \a
+ value. If no such item is found, returns the position where the
+ item should be inserted.
+
+ The items in the range [\a begin, \e end) must be sorted in
+ ascending order; see qSort().
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 20
+
+ This function requires the item type (in the example above,
+ \c{int}) to implement \c operator<().
+
+ qUpperBound() can be used in conjunction with qLowerBound() to
+ iterate over all occurrences of the same value:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 21
+
+ \sa qLowerBound(), qBinaryFind()
+*/
+
+/*!
+ \fn RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ Uses the \a lessThan function instead of \c operator<() to
+ compare the items.
+
+ Note that the items in the range must be sorted according to the order
+ specified by the \a lessThan object.
+*/
+
+/*!
+ \fn void qUpperBound(const Container &container, const T &value)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ This is the same as qUpperBound(\a{container}.begin(), \a{container}.end(), value);
+*/
+
+
+/*! \fn RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value)
+ \relates <QtAlgorithms>
+
+ Performs a binary search of the range [\a begin, \a end) and
+ returns the position of an occurrence of \a value. If there are
+ no occurrences of \a value, returns \a end.
+
+ The items in the range [\a begin, \a end) must be sorted in
+ ascending order; see qSort().
+
+ If there are many occurrences of the same value, any one of them
+ could be returned. Use qLowerBound() or qUpperBound() if you need
+ finer control.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 22
+
+ This function requires the item type (in the example above,
+ QString) to implement \c operator<().
+
+ See the \l{<QtAlgorithms>#binaryFind example}{detailed
+ description} for an example usage.
+
+ \sa qLowerBound(), qUpperBound(), {random access iterators}
+*/
+
+/*! \fn RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ Uses the \a lessThan function instead of \c operator<() to
+ compare the items.
+
+ Note that the items in the range must be sorted according to the order
+ specified by the \a lessThan object.
+*/
+
+/*!
+ \fn void qBinaryFind(const Container &container, const T &value)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ This is the same as qBinaryFind(\a{container}.begin(), \a{container}.end(), value);
+*/
+
+
+/*!
+ \fn void qDeleteAll(ForwardIterator begin, ForwardIterator end)
+ \relates <QtAlgorithms>
+
+ Deletes all the items in the range [\a begin, \a end) using the
+ C++ \c delete operator. The item type must be a pointer type (for
+ example, \c{QWidget *}).
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 23
+
+ Notice that qDeleteAll() doesn't remove the items from the
+ container; it merely calls \c delete on them. In the example
+ above, we call clear() on the container to remove the items.
+
+ This function can also be used to delete items stored in
+ associative containers, such as QMap and QHash. Only the objects
+ stored in each container will be deleted by this function; objects
+ used as keys will not be deleted.
+
+ \sa {forward iterators}
+*/
+
+/*!
+ \fn void qDeleteAll(const Container &c)
+ \relates <QtAlgorithms>
+
+ \overload
+
+ This is the same as qDeleteAll(\a{c}.begin(), \a{c}.end()).
+*/
+
+/*! \fn LessThan qLess()
+ \relates <QtAlgorithms>
+
+ Returns a functional object, or functor, that can be passed to qSort()
+ or qStableSort().
+
+ Example:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 24
+
+ \sa {qGreater()}{qGreater<T>()}
+*/
+
+/*! \fn LessThan qGreater()
+ \relates <QtAlgorithms>
+
+ Returns a functional object, or functor, that can be passed to qSort()
+ or qStableSort().
+
+ Example:
+
+ \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 25
+
+ \sa {qLess()}{qLess<T>()}
+*/
diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp
index c429a9f..19ac8dc 100644
--- a/src/corelib/tools/qbitarray.cpp
+++ b/src/corelib/tools/qbitarray.cpp
@@ -209,6 +209,8 @@ void QBitArray::resize(int size)
uchar* c = reinterpret_cast<uchar*>(d.data());
if (size > (s << 3))
memset(c + s, 0, d.size() - s);
+ else if ( size % 8)
+ *(c+1+size/8) &= (1 << (size%8)) - 1;
*c = d.size()*8 - size;
}
}
@@ -653,6 +655,7 @@ QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
QBitArray stream functions
*****************************************************************************/
+#ifndef QT_NO_DATASTREAM
/*!
\relates QBitArray
@@ -660,7 +663,7 @@ QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
\sa \link datastreamformat.html Format of the QDataStream operators \endlink
*/
-#ifndef QT_NO_DATASTREAM
+
QDataStream &operator<<(QDataStream &out, const QBitArray &ba)
{
quint32 len = ba.size();
@@ -713,7 +716,7 @@ QDataStream &operator>>(QDataStream &in, QBitArray &ba)
*ba.d.data() = ba.d.size() * 8 - len;
return in;
}
-#endif
+#endif // QT_NO_DATASTREAM
/*!
\fn DataPtr &QBitArray::data_ptr()
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index 4f77633..840f6a5 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -538,9 +538,13 @@ QByteArray qUncompress(const uchar* data, int nbytes)
QByteArray baunzip;
int res;
do {
- baunzip.resize(len);
- res = ::uncompress((uchar*)baunzip.data(), &len,
- (uchar*)data+4, nbytes-4);
+ QT_TRY {
+ baunzip.resize(len);
+ res = ::uncompress((uchar*)baunzip.data(), &len,
+ (uchar*)data+4, nbytes-4);
+ } QT_CATCH (const std::bad_alloc &) {
+ res = Z_MEM_ERROR;
+ }
switch (res) {
case Z_OK:
@@ -579,7 +583,7 @@ static inline char qToLower(char c)
return c;
}
-Q_CORE_EXPORT QByteArray::Data QByteArray::shared_null = {Q_BASIC_ATOMIC_INITIALIZER(1),
+QByteArray::Data QByteArray::shared_null = {Q_BASIC_ATOMIC_INITIALIZER(1),
0, 0, shared_null.array, {0} };
QByteArray::Data QByteArray::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1),
0, 0, shared_empty.array, {0} };
@@ -590,8 +594,8 @@ QByteArray::Data QByteArray::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1),
\ingroup tools
\ingroup shared
- \ingroup text
- \mainclass
+ \ingroup string-processing
+
\reentrant
QByteArray can be used to store both raw bytes (including '\\0's)
@@ -1233,14 +1237,11 @@ QByteArray::QByteArray(const char *str)
} else {
int len = qstrlen(str);
d = static_cast<Data *>(qMalloc(sizeof(Data)+len));
- if (!d) {
- d = &shared_null;
- } else {
- d->ref = 0;;
- d->alloc = d->size = len;
- d->data = d->array;
- memcpy(d->array, str, len+1); // include null terminator
- }
+ Q_CHECK_PTR(d);
+ d->ref = 0;;
+ d->alloc = d->size = len;
+ d->data = d->array;
+ memcpy(d->array, str, len+1); // include null terminator
}
d->ref.ref();
}
@@ -1264,15 +1265,12 @@ QByteArray::QByteArray(const char *data, int size)
d = &shared_empty;
} else {
d = static_cast<Data *>(qMalloc(sizeof(Data) + size));
- if (!d) {
- d = &shared_null;
- } else {
- d->ref = 0;
- d->alloc = d->size = size;
- d->data = d->array;
- memcpy(d->array, data, size);
- d->array[size] = '\0';
- }
+ Q_CHECK_PTR(d);
+ d->ref = 0;
+ d->alloc = d->size = size;
+ d->data = d->array;
+ memcpy(d->array, data, size);
+ d->array[size] = '\0';
}
d->ref.ref();
}
@@ -1290,20 +1288,33 @@ QByteArray::QByteArray(int size, char ch)
d = &shared_null;
} else {
d = static_cast<Data *>(qMalloc(sizeof(Data)+size));
- if (!d) {
- d = &shared_null;
- } else {
- d->ref = 0;
- d->alloc = d->size = size;
- d->data = d->array;
- d->array[size] = '\0';
- memset(d->array, ch, size);
- }
+ Q_CHECK_PTR(d);
+ d->ref = 0;
+ d->alloc = d->size = size;
+ d->data = d->array;
+ d->array[size] = '\0';
+ memset(d->array, ch, size);
}
d->ref.ref();
}
/*!
+ \internal
+
+ Constructs a byte array of size \a size with uninitialized contents.
+*/
+
+QByteArray::QByteArray(int size, Qt::Initialization)
+{
+ d = static_cast<Data *>(qMalloc(sizeof(Data)+size));
+ Q_CHECK_PTR(d);
+ d->ref = 1;
+ d->alloc = d->size = size;
+ d->data = d->array;
+ d->array[size] = '\0';
+}
+
+/*!
Sets the size of the byte array to \a size bytes.
If \a size is greater than the current size, the byte array is
@@ -1334,8 +1345,7 @@ void QByteArray::resize(int size)
// QByteArray a(sz);
//
Data *x = static_cast<Data *>(qMalloc(sizeof(Data)+size));
- if (!x)
- return;
+ Q_CHECK_PTR(x);
x->ref = 1;
x->alloc = x->size = size;
x->data = x->array;
@@ -1377,8 +1387,7 @@ void QByteArray::realloc(int alloc)
{
if (d->ref != 1 || d->data != d->array) {
Data *x = static_cast<Data *>(qMalloc(sizeof(Data) + alloc));
- if (!x)
- return;
+ Q_CHECK_PTR(x);
x->size = qMin(alloc, d->size);
::memcpy(x->array, d->data, x->size);
x->array[x->size] = '\0';
@@ -1390,8 +1399,7 @@ void QByteArray::realloc(int alloc)
d = x;
} else {
Data *x = static_cast<Data *>(qRealloc(d, sizeof(Data) + alloc));
- if (!x)
- return;
+ Q_CHECK_PTR(x);
x->alloc = alloc;
x->data = x->array;
d = x;
@@ -1812,11 +1820,13 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after
const char *b = before;
if (after >= d->data && after < d->data + d->size) {
char *copy = (char *)malloc(asize);
+ Q_CHECK_PTR(copy);
memcpy(copy, after, asize);
a = copy;
}
if (before >= d->data && before < d->data + d->size) {
char *copy = (char *)malloc(bsize);
+ Q_CHECK_PTR(copy);
memcpy(copy, before, bsize);
b = copy;
}
@@ -2591,6 +2601,8 @@ void QByteArray::clear()
d->ref.ref();
}
+#ifndef QT_NO_DATASTREAM
+
/*! \relates QByteArray
Writes byte array \a ba to the stream \a out and returns a reference
@@ -2598,7 +2610,6 @@ void QByteArray::clear()
\sa {Format of the QDataStream operators}
*/
-#ifndef QT_NO_DATASTREAM
QDataStream &operator<<(QDataStream &out, const QByteArray &ba)
{
@@ -2641,7 +2652,7 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
return in;
}
-#endif //QT_NO_DATASTREAM
+#endif // QT_NO_DATASTREAM
/*! \fn bool QByteArray::operator==(const QString &str) const
@@ -2976,8 +2987,7 @@ QByteArray QByteArray::simplified() const
{
if (d->size == 0)
return *this;
- QByteArray result;
- result.resize(d->size);
+ QByteArray result(d->size, Qt::Uninitialized);
const char *from = d->data;
const char *fromend = from + d->size;
int outc=0;
@@ -3428,8 +3438,7 @@ QByteArray QByteArray::toBase64() const
const char padchar = '=';
int padlen = 0;
- QByteArray tmp;
- tmp.resize(((d->size * 4) / 3) + 3);
+ QByteArray tmp((d->size * 4) / 3 + 3, Qt::Uninitialized);
int i = 0;
char *out = tmp.data();
@@ -3738,6 +3747,7 @@ QByteArray QByteArray::number(double n, char f, int prec)
QByteArray QByteArray::fromRawData(const char *data, int size)
{
Data *x = static_cast<Data *>(qMalloc(sizeof(Data)));
+ Q_CHECK_PTR(x);
if (data) {
x->data = const_cast<char *>(data);
} else {
@@ -3767,8 +3777,7 @@ QByteArray QByteArray::fromBase64(const QByteArray &base64)
{
unsigned int buf = 0;
int nbits = 0;
- QByteArray tmp;
- tmp.resize((base64.size() * 3) / 4);
+ QByteArray tmp((base64.size() * 3) / 4, Qt::Uninitialized);
int offset = 0;
for (int i = 0; i < base64.size(); ++i) {
@@ -3816,8 +3825,7 @@ QByteArray QByteArray::fromBase64(const QByteArray &base64)
*/
QByteArray QByteArray::fromHex(const QByteArray &hexEncoded)
{
- QByteArray res;
- res.resize((hexEncoded.size() + 1)/ 2);
+ QByteArray res((hexEncoded.size() + 1)/ 2, Qt::Uninitialized);
uchar *result = (uchar *)res.data() + res.size();
bool odd_digit = true;
@@ -3854,8 +3862,7 @@ QByteArray QByteArray::fromHex(const QByteArray &hexEncoded)
*/
QByteArray QByteArray::toHex() const
{
- QByteArray hex;
- hex.resize(d->size*2);
+ QByteArray hex(d->size * 2, Qt::Uninitialized);
char *hexData = hex.data();
const uchar *data = (const uchar *)d->data;
for (int i = 0; i < d->size; ++i) {
diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h
index 86ba397..f7e790d 100644
--- a/src/corelib/tools/qbytearray.h
+++ b/src/corelib/tools/qbytearray.h
@@ -42,8 +42,8 @@
#ifndef QBYTEARRAY_H
#define QBYTEARRAY_H
-#include <QtCore/qglobal.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qnamespace.h>
#include <string.h>
#include <stdarg.h>
@@ -122,11 +122,23 @@ template <typename T> class QList;
class Q_CORE_EXPORT QByteArray
{
+private:
+ struct Data {
+ QBasicAtomicInt ref;
+ int alloc, size;
+ // ### Qt 5.0: We need to add the missing capacity bit
+ // (like other tool classes have), to maintain the
+ // reserved memory on resize.
+ char *data;
+ char array[1];
+ };
+
public:
inline QByteArray();
QByteArray(const char *);
QByteArray(const char *, int size);
QByteArray(int size, char c);
+ QByteArray(int size, Qt::Initialization);
inline QByteArray(const QByteArray &);
inline ~QByteArray();
@@ -309,6 +321,7 @@ public:
// stl compatibility
typedef const char & const_reference;
typedef char & reference;
+ typedef char value_type;
void push_back(char c);
void push_back(const char *c);
void push_back(const QByteArray &a);
@@ -347,15 +360,6 @@ public:
private:
operator QNoImplicitBoolCast() const;
- struct Data {
- QBasicAtomicInt ref;
- int alloc, size;
- // ### Qt 5.0: We need to add the missing capacity bit
- // (like other tool classes have), to maintain the
- // reserved memory on resize.
- char *data;
- char array[1];
- };
static Data shared_null;
static Data shared_empty;
Data *d;
diff --git a/src/corelib/tools/qbytearraymatcher.cpp b/src/corelib/tools/qbytearraymatcher.cpp
index 7fb60c2..fb21212 100644
--- a/src/corelib/tools/qbytearraymatcher.cpp
+++ b/src/corelib/tools/qbytearraymatcher.cpp
@@ -94,7 +94,7 @@ static inline int bm_find(const uchar *cc, int l, int index, const uchar *puc, u
can be quickly matched in a byte array.
\ingroup tools
- \ingroup text
+ \ingroup string-processing
This class is useful when you have a sequence of bytes that you
want to repeatedly match against some byte arrays (perhaps in a
diff --git a/src/corelib/tools/qbytearraymatcher.h b/src/corelib/tools/qbytearraymatcher.h
index 291c6d6..c0d669d 100644
--- a/src/corelib/tools/qbytearraymatcher.h
+++ b/src/corelib/tools/qbytearraymatcher.h
@@ -81,13 +81,14 @@ private:
// explicitely allow anonymous unions for RVCT to prevent compiler warnings
#pragma anon_unions
#endif
+ struct Data {
+ uchar q_skiptable[256];
+ const uchar *p;
+ int l;
+ };
union {
uint dummy[256];
- struct {
- uchar q_skiptable[256];
- const uchar *p;
- int l;
- } p;
+ Data p;
};
};
diff --git a/src/corelib/tools/qbytedata_p.h b/src/corelib/tools/qbytedata_p.h
new file mode 100644
index 0000000..c3275c7
--- /dev/null
+++ b/src/corelib/tools/qbytedata_p.h
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBYTEDATA_H
+#define QBYTEDATA_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 <qbytearray.h>
+
+QT_BEGIN_NAMESPACE
+
+// this class handles a list of QByteArrays. It is a variant of QRingBuffer
+// that avoid malloc/realloc/memcpy.
+class QByteDataBuffer
+{
+private:
+ QList<QByteArray> buffers;
+ qint64 bufferCompleteSize;
+public:
+ QByteDataBuffer() : bufferCompleteSize(0)
+ {
+ }
+
+ ~QByteDataBuffer()
+ {
+ clear();
+ }
+
+ inline void append(QByteDataBuffer& other)
+ {
+ if (other.isEmpty())
+ return;
+
+ buffers.append(other.buffers);
+ bufferCompleteSize += other.byteAmount();
+ }
+
+
+ inline void append(QByteArray& bd)
+ {
+ if (bd.isEmpty())
+ return;
+
+ buffers.append(bd);
+ bufferCompleteSize += bd.size();
+ }
+
+ inline void prepend(QByteArray& bd)
+ {
+ if (bd.isEmpty())
+ return;
+
+ buffers.prepend(bd);
+ bufferCompleteSize += bd.size();
+ }
+
+ // return the first QByteData. User of this function has to qFree() its .data!
+ // preferably use this function to read data.
+ inline QByteArray read()
+ {
+ bufferCompleteSize -= buffers.first().size();
+ return buffers.takeFirst();
+ }
+
+ // return everything. User of this function has to qFree() its .data!
+ // avoid to use this, it might malloc and memcpy.
+ inline QByteArray readAll()
+ {
+ return read(byteAmount());
+ }
+
+ // return amount. User of this function has to qFree() its .data!
+ // avoid to use this, it might malloc and memcpy.
+ inline QByteArray read(qint64 amount)
+ {
+ amount = qMin(byteAmount(), amount);
+ QByteArray byteData;
+ byteData.resize(amount);
+ read(byteData.data(), byteData.size());
+ return byteData;
+ }
+
+ // return amount bytes. User of this function has to qFree() its .data!
+ // avoid to use this, it will memcpy.
+ qint64 read(char* dst, qint64 amount)
+ {
+ amount = qMin(amount, byteAmount());
+ qint64 originalAmount = amount;
+ char *writeDst = dst;
+
+ while (amount > 0) {
+ QByteArray first = buffers.takeFirst();
+ if (amount >= first.size()) {
+ // take it completely
+ bufferCompleteSize -= first.size();
+ amount -= first.size();
+ memcpy(writeDst, first.constData(), first.size());
+ writeDst += first.size();
+ first.clear();
+ } else {
+ // take a part of it & it is the last one to take
+ bufferCompleteSize -= amount;
+ memcpy(writeDst, first.constData(), amount);
+
+ qint64 newFirstSize = first.size() - amount;
+ QByteArray newFirstData;
+ newFirstData.resize(newFirstSize);
+ memcpy(newFirstData.data(), first.constData() + amount, newFirstSize);
+ buffers.prepend(newFirstData);
+
+ amount = 0;
+ first.clear();
+ }
+ }
+
+ return originalAmount;
+ }
+
+ inline char getChar()
+ {
+ char c;
+ read(&c, 1);
+ return c;
+ }
+
+ inline void clear()
+ {
+ buffers.clear();
+ bufferCompleteSize = 0;
+ }
+
+ // The byte count of all QByteArrays
+ inline qint64 byteAmount() const
+ {
+ return bufferCompleteSize;
+ }
+
+ // the number of QByteArrays
+ inline qint64 bufferCount() const
+ {
+ return buffers.length();
+ }
+
+ inline bool isEmpty() const
+ {
+ return byteAmount() == 0;
+ }
+
+ inline qint64 sizeNextBlock() const
+ {
+ if(buffers.isEmpty())
+ return 0;
+ else
+ return buffers.first().size();
+ }
+
+ inline QByteArray& operator[](int i)
+ {
+ return buffers[i];
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QBYTEDATA_H
diff --git a/src/corelib/tools/qcache.qdoc b/src/corelib/tools/qcache.qdoc
new file mode 100644
index 0000000..d443c93
--- /dev/null
+++ b/src/corelib/tools/qcache.qdoc
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QCache
+ \brief The QCache class is a template class that provides a cache.
+
+ \ingroup tools
+ \ingroup shared
+
+ \reentrant
+
+ QCache\<Key, T\> defines a cache that stores objects of type T
+ associated with keys of type Key. For example, here's the
+ definition of a cache that stores objects of type Employee
+ associated with an integer key:
+
+ \snippet doc/src/snippets/code/doc_src_qcache.qdoc 0
+
+ Here's how to insert an object in the cache:
+
+ \snippet doc/src/snippets/code/doc_src_qcache.qdoc 1
+
+ The advantage of using QCache over some other key-based data
+ structure (such as QMap or QHash) is that QCache automatically
+ takes ownership of the objects that are inserted into the cache and
+ deletes them to make room for new objects, if necessary. When
+ inserting an object into the cache, you can specify a \e{cost},
+ which should bear some approximate relationship to the amount of
+ memory taken by the object. When the sum of all objects' costs
+ (totalCost()) exceeds the cache's limit (maxCost()), QCache starts
+ deleting objects in the cache to keep under the limit, starting with
+ less recently accessed objects.
+
+ By default, QCache's maxCost() is 100. You can specify a
+ different value in the QCache constructor:
+
+ \snippet doc/src/snippets/code/doc_src_qcache.qdoc 2
+
+ Each time you call insert(), you can specify a cost as third
+ argument (after the key and a pointer to the object to insert).
+ After the call, the inserted object is owned by the QCache, which
+ may delete it at any time to make room for other objects.
+
+ To look up objects in the cache, use object() or
+ operator[](). This function looks up an object by its key, and
+ returns either a pointer to the cached object (which is owned by
+ the cache) or 0.
+
+ If you want to remove an object from the cache for a particular key,
+ call remove(). This will also delete the object. If you want to
+ remove an object from the cache without the QCache deleting it, use
+ take().
+
+ \sa QPixmapCache, QHash, QMap
+*/
+
+/*! \fn QCache::QCache(int maxCost = 100)
+
+ Constructs a cache whose contents will never have a total cost
+ greater than \a maxCost.
+*/
+
+/*! \fn QCache::~QCache()
+
+ Destroys the cache. Deletes all the objects in the cache.
+*/
+
+/*! \fn int QCache::maxCost() const
+
+ Returns the maximum allowed total cost of the cache.
+
+ \sa setMaxCost(), totalCost()
+*/
+
+/*! \fn void QCache::setMaxCost(int cost)
+
+ Sets the maximum allowed total cost of the cache to \a cost. If
+ the current total cost is greater than \a cost, some objects are
+ deleted immediately.
+
+ \sa maxCost(), totalCost()
+*/
+
+/*! \fn int QCache::totalCost() const
+
+ Returns the total cost of the objects in the cache.
+
+ This value is normally below maxCost(), but QCache makes an
+ exception for Qt's \l{implicitly shared} classes. If a cached
+ object shares its internal data with another instance, QCache may
+ keep the object lying around, possibly contributing to making
+ totalCost() larger than maxCost().
+
+ \sa setMaxCost()
+*/
+
+/*! \fn int QCache::size() const
+
+ Returns the number of objects in the cache.
+
+ \sa isEmpty()
+*/
+
+/*! \fn int QCache::count() const
+
+ Same as size().
+*/
+
+/*! \fn bool QCache::isEmpty() const
+
+ Returns true if the cache contains no objects; otherwise
+ returns false.
+
+ \sa size()
+*/
+
+/*! \fn QList<Key> QCache::keys() const
+
+ Returns a list of the keys in the cache.
+*/
+
+/*! \fn void QCache::clear();
+
+ Deletes all the objects in the cache.
+
+ \sa remove(), take()
+*/
+
+
+/*! \fn bool QCache::insert(const Key &key, T *object, int cost = 1)
+
+ Inserts \a object into the cache with key \a key and
+ associated cost \a cost. Any object with the same key already in
+ the cache will be removed.
+
+ After this call, \a object is owned by the QCache and may be
+ deleted at any time. In particular, if \a cost is greater than
+ maxCost(), the object will be deleted immediately.
+
+ The function returns true if the object was inserted into the
+ cache; otherwise it returns false.
+
+ \sa take(), remove()
+*/
+
+/*! \fn T *QCache::object(const Key &key) const
+
+ Returns the object associated with key \a key, or 0 if the key does
+ not exist in the cache.
+
+ \warning The returned object is owned by QCache and may be
+ deleted at any time.
+
+ \sa take(), remove()
+*/
+
+/*! \fn bool QCache::contains(const Key &key) const
+
+ Returns true if the cache contains an object associated with key \a
+ key; otherwise returns false.
+
+ \sa take(), remove()
+*/
+
+/*! \fn T *QCache::operator[](const Key &key) const
+
+ Returns the object associated with key \a key, or 0 if the key does
+ not exist in the cache.
+
+ This is the same as object().
+
+ \warning The returned object is owned by QCache and may be
+ deleted at any time.
+*/
+
+/*! \fn bool QCache::remove(const Key &key)
+
+ Deletes the object associated with key \a key. Returns true if the
+ object was found in the cache; otherwise returns false.
+
+ \sa take(), clear()
+*/
+
+/*! \fn T *QCache::take(const Key &key)
+
+ Takes the object associated with key \a key out of the cache
+ without deleting it. Returns a pointer to the object taken out, or
+ 0 if the key does not exist in the cache.
+
+ The ownership of the returned object is passed to the caller.
+
+ \sa remove()
+*/
+
+/*!
+ \fn QCache::QCache(int maxCost, int dummy)
+
+ Use QCache(int) instead.
+*/
+
+/*!
+ \fn T *QCache::find(const Key &key) const
+
+ Use object() instead.
+*/
diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp
index 8f115d5..f20d61f 100644
--- a/src/corelib/tools/qchar.cpp
+++ b/src/corelib/tools/qchar.cpp
@@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE
/*! \class QLatin1Char
\brief The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
- \ingroup text
+ \ingroup string-processing
This class is only useful to avoid the codec for C strings business
in the QChar(ch) constructor. You can avoid it by writing
@@ -104,7 +104,7 @@ QT_BEGIN_NAMESPACE
\class QChar
\brief The QChar class provides a 16-bit Unicode character.
- \ingroup text
+ \ingroup string-processing
\reentrant
In Qt, Unicode characters are 16-bit entities without any markup
@@ -1321,7 +1321,7 @@ QDataStream &operator>>(QDataStream &in, QChar &chr)
chr.unicode() = ushort(u);
return in;
}
-#endif
+#endif // QT_NO_DATASTREAM
/*!
\fn ushort & QChar::unicode()
@@ -1421,16 +1421,15 @@ QDataStream &operator>>(QDataStream &in, QChar &chr)
// ---------------------------------------------------------------------------
-static QString decomposeHelper
- (const QString &str, bool canonical, QChar::UnicodeVersion version)
+static void decomposeHelper(QString *str, bool canonical, QChar::UnicodeVersion version, int from)
{
unsigned short buffer[3];
- QString s = str;
+ QString &s = *str;
- const unsigned short *utf16 = s.utf16();
+ const unsigned short *utf16 = reinterpret_cast<unsigned short *>(s.data());
const unsigned short *uc = utf16 + s.length();
- while (uc != utf16) {
+ while (uc != utf16 + from) {
uint ucs4 = *(--uc);
if (QChar(ucs4).isLowSurrogate() && uc != utf16) {
ushort high = *(uc - 1);
@@ -1450,11 +1449,9 @@ static QString decomposeHelper
s.replace(uc - utf16, ucs4 > 0x10000 ? 2 : 1, (const QChar *)d, length);
// since the insert invalidates the pointers and we do decomposition recursive
int pos = uc - utf16;
- utf16 = s.utf16();
+ utf16 = reinterpret_cast<unsigned short *>(s.data());
uc = utf16 + pos + length;
}
-
- return s;
}
@@ -1489,21 +1486,21 @@ static ushort ligatureHelper(ushort u1, ushort u2)
return 0;
}
-static QString composeHelper(const QString &str)
+static void composeHelper(QString *str, int from)
{
- QString s = str;
+ QString &s = *str;
- if (s.length() < 2)
- return s;
+ if (s.length() - from < 2)
+ return;
// the loop can partly ignore high Unicode as all ligatures are in the BMP
int starter = 0;
int lastCombining = 0;
- int pos = 0;
+ int pos = from;
while (pos < s.length()) {
- uint uc = s.utf16()[pos];
+ uint uc = s.at(pos).unicode();
if (QChar(uc).isHighSurrogate() && pos < s.length()-1) {
- ushort low = s.utf16()[pos+1];
+ ushort low = s.at(pos+1).unicode();
if (QChar(low).isLowSurrogate()) {
uc = QChar::surrogateToUcs4(uc, low);
++pos;
@@ -1512,7 +1509,7 @@ static QString composeHelper(const QString &str)
int combining = QChar::combiningClass(uc);
if (starter == pos - 1 || combining > lastCombining) {
// allowed to form ligature with S
- QChar ligature = ligatureHelper(s.utf16()[starter], uc);
+ QChar ligature = ligatureHelper(s.at(starter).unicode(), uc);
if (ligature.unicode()) {
s[starter] = ligature;
s.remove(pos, 1);
@@ -1524,16 +1521,14 @@ static QString composeHelper(const QString &str)
lastCombining = combining;
++pos;
}
- return s;
}
-static QString canonicalOrderHelper
- (const QString &str, QChar::UnicodeVersion version)
+static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, int from)
{
- QString s = str;
+ QString &s = *str;
const int l = s.length()-1;
- int pos = 0;
+ int pos = from;
while (pos < l) {
int p2 = pos+1;
uint u1 = s.at(pos).unicode();
@@ -1593,7 +1588,6 @@ static QString canonicalOrderHelper
++pos;
}
}
- return s;
}
int QT_FASTCALL QUnicodeTables::script(unsigned int uc)
diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp
new file mode 100644
index 0000000..7a46d83
--- /dev/null
+++ b/src/corelib/tools/qcontiguouscache.cpp
@@ -0,0 +1,432 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcontiguouscache.h"
+#ifdef QT_QCONTIGUOUSCACHE_DEBUG
+#include <QDebug>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef QT_QCONTIGUOUSCACHE_DEBUG
+void QContiguousCacheData::dump() const
+{
+ qDebug() << "capacity:" << alloc;
+ qDebug() << "count:" << count;
+ qDebug() << "start:" << start;
+ qDebug() << "offset:" << offset;
+}
+#endif
+
+/*! \class QContiguousCache
+ \brief The QContiguousCache class is a template class that provides a contiguous cache.
+ \ingroup tools
+ \ingroup shared
+ \reentrant
+ \since 4.6
+
+ The QContiguousCache class provides an efficient way of caching items for
+ display in a user interface view. Unlike QCache, it adds a restriction
+ that elements within the cache are contiguous. This has the advantage
+ of matching how user interface views most commonly request data, as
+ a set of rows localized around the current scrolled position. This
+ restriction allows the cache to consume less memory and processor
+ cycles than QCache. The QContiguousCache class also can provide
+ an upper bound on memory usage via setCapacity().
+
+ The simplest way of using a contiguous cache is to use the append()
+ and prepend().
+
+\code
+MyRecord record(int row) const
+{
+ Q_ASSERT(row >= 0 && row < count());
+
+ while(row > cache.lastIndex())
+ cache.append(slowFetchRecord(cache.lastIndex()+1));
+ while(row < cache.firstIndex())
+ cache.prepend(slowFetchRecord(cache.firstIndex()-1));
+
+ return cache.at(row);
+}
+\endcode
+
+ If the cache is full then the item at the opposite end of the cache from
+ where the new item is appended or prepended will be removed.
+
+ This usage can be further optimized by using the insert() function
+ in the case where the requested row is a long way from the currently cached
+ items. If there is a gap between where the new item is inserted and the currently
+ cached items then the existing cached items are first removed to retain
+ the contiguous nature of the cache. Hence it is important to take some care then
+ when using insert() in order to avoid unwanted clearing of the cache.
+
+ The range of valid indexes for the QContiguousCache class are from
+ 0 to INT_MAX. Calling prepend() such that the first index would become less
+ than 0 or append() such that the last index would become greater
+ than INT_MAX can result in the indexes of the cache being invalid.
+ When the cache indexes are invalid it is important to call
+ normalizeIndexes() before calling any of containsIndex(), firstIndex(),
+ lastIndex(), at() or \l{QContiguousCache::operator[]()}{operator[]()}.
+ Calling these functions when the cache has invalid indexes will result in
+ undefined behavior. The indexes can be checked by using areIndexesValid()
+
+ In most cases the indexes will not exceed 0 to INT_MAX, and
+ normalizeIndexes() will not need to be used.
+
+ See the \l{Contiguous Cache Example}{Contiguous Cache} example.
+*/
+
+/*! \fn QContiguousCache::QContiguousCache(int capacity)
+
+ Constructs a cache with the given \a capacity.
+
+ \sa setCapacity()
+*/
+
+/*! \fn QContiguousCache::QContiguousCache(const QContiguousCache<T> &other)
+
+ Constructs a copy of \a other.
+
+ This operation takes \l{constant time}, because QContiguousCache is
+ \l{implicitly shared}. This makes returning a QContiguousCache from a
+ function very fast. If a shared instance is modified, it will be
+ copied (copy-on-write), and that takes \l{linear time}.
+
+ \sa operator=()
+*/
+
+/*! \fn QContiguousCache::~QContiguousCache()
+
+ Destroys the cache.
+*/
+
+/*! \fn void QContiguousCache::detach()
+
+ \internal
+*/
+
+/*! \fn bool QContiguousCache::isDetached() const
+
+ \internal
+*/
+
+/*! \fn void QContiguousCache::setSharable(bool sharable)
+
+ \internal
+*/
+
+/*! \fn QContiguousCache<T> &QContiguousCache::operator=(const QContiguousCache<T> &other)
+
+ Assigns \a other to this cache and returns a reference to this cache.
+*/
+
+/*! \fn bool QContiguousCache::operator==(const QContiguousCache<T> &other) const
+
+ Returns true if \a other is equal to this cache; otherwise returns false.
+
+ Two caches are considered equal if they contain the same values at the same
+ indexes. This function requires the value type to implement the \c operator==().
+
+ \sa operator!=()
+*/
+
+/*! \fn bool QContiguousCache::operator!=(const QContiguousCache<T> &other) const
+
+ Returns true if \a other is not equal to this cache; otherwise
+ returns false.
+
+ Two caches are considered equal if they contain the same values at the same
+ indexes. This function requires the value type to implement the \c operator==().
+
+ \sa operator==()
+*/
+
+/*! \fn int QContiguousCache::capacity() const
+
+ Returns the number of items the cache can store before it is full.
+ When a cache contains a number of items equal to its capacity, adding new
+ items will cause items farthest from the added item to be removed.
+
+ \sa setCapacity(), size()
+*/
+
+/*! \fn int QContiguousCache::count() const
+
+ Same as size().
+*/
+
+/*! \fn int QContiguousCache::size() const
+
+ Returns the number of items contained within the cache.
+
+ \sa capacity()
+*/
+
+/*! \fn bool QContiguousCache::isEmpty() const
+
+ Returns true if no items are stored within the cache.
+
+ \sa size(), capacity()
+*/
+
+/*! \fn bool QContiguousCache::isFull() const
+
+ Returns true if the number of items stored within the cache is equal
+ to the capacity of the cache.
+
+ \sa size(), capacity()
+*/
+
+/*! \fn int QContiguousCache::available() const
+
+ Returns the number of items that can be added to the cache before it becomes full.
+
+ \sa size(), capacity(), isFull()
+*/
+
+/*! \fn void QContiguousCache::clear()
+
+ Removes all items from the cache. The capacity is unchanged.
+*/
+
+/*! \fn void QContiguousCache::setCapacity(int size)
+
+ Sets the capacity of the cache to the given \a size. A cache can hold a
+ number of items equal to its capacity. When inserting, appending or prepending
+ items to the cache, if the cache is already full then the item farthest from
+ the added item will be removed.
+
+ If the given \a size is smaller than the current count of items in the cache
+ then only the last \a size items from the cache will remain.
+
+ \sa capacity(), isFull()
+*/
+
+/*! \fn const T &QContiguousCache::at(int i) const
+
+ Returns the item at index position \a i in the cache. \a i must
+ be a valid index position in the cache (i.e, firstIndex() <= \a i <= lastIndex()).
+
+ The indexes in the cache refer to the number of positions the item is from the
+ first item appended into the cache. That is to say a cache with a capacity of
+ 100, that has had 150 items appended will have a valid index range of
+ 50 to 149. This allows inserting and retrieving items into the cache based
+ on a theoretical infinite list
+
+ \sa firstIndex(), lastIndex(), insert(), operator[]()
+*/
+
+/*! \fn T &QContiguousCache::operator[](int i)
+
+ Returns the item at index position \a i as a modifiable reference. If
+ the cache does not contain an item at the given index position \a i
+ then it will first insert an empty item at that position.
+
+ In most cases it is better to use either at() or insert().
+
+ \note This non-const overload of operator[] requires QContiguousCache
+ to make a deep copy. Use at() for read-only access to a non-const
+ QContiguousCache.
+
+ \sa insert(), at()
+*/
+
+/*! \fn const T &QContiguousCache::operator[](int i) const
+
+ \overload
+
+ Same as at(\a i).
+*/
+
+/*! \fn void QContiguousCache::append(const T &value)
+
+ Inserts \a value at the end of the cache. If the cache is already full
+ the item at the start of the cache will be removed.
+
+ \sa prepend(), insert(), isFull()
+*/
+
+/*! \fn void QContiguousCache::prepend(const T &value)
+
+ Inserts \a value at the start of the cache. If the cache is already full
+ the item at the end of the cache will be removed.
+
+ \sa append(), insert(), isFull()
+*/
+
+/*! \fn void QContiguousCache::insert(int i, const T &value)
+
+ Inserts the \a value at the index position \a i. If the cache already contains
+ an item at \a i then that value is replaced. If \a i is either one more than
+ lastIndex() or one less than firstIndex() it is the equivalent to an append()
+ or a prepend().
+
+ If the given index \a i is not within the current range of the cache nor adjacent
+ to the bounds of the cache's index range, the cache is first cleared before
+ inserting the item. At this point the cache will have a size of 1. It is
+ worthwhile taking effort to insert items in an order that starts adjacent
+ to the current index range for the cache.
+
+ The range of valid indexes for the QContiguousCache class are from
+ 0 to INT_MAX. Inserting outside of this range has undefined behavior.
+
+
+ \sa prepend(), append(), isFull(), firstIndex(), lastIndex()
+*/
+
+/*! \fn bool QContiguousCache::containsIndex(int i) const
+
+ Returns true if the cache's index range includes the given index \a i.
+
+ \sa firstIndex(), lastIndex()
+*/
+
+/*! \fn int QContiguousCache::firstIndex() const
+
+ Returns the first valid index in the cache. The index will be invalid if the
+ cache is empty.
+
+ \sa capacity(), size(), lastIndex()
+*/
+
+/*! \fn int QContiguousCache::lastIndex() const
+
+ Returns the last valid index in the cache. The index will be invalid if the cache is empty.
+
+ \sa capacity(), size(), firstIndex()
+*/
+
+
+/*! \fn T &QContiguousCache::first()
+
+ Returns a reference to the first item in the cache. This function
+ assumes that the cache isn't empty.
+
+ \sa last(), isEmpty()
+*/
+
+/*! \fn T &QContiguousCache::last()
+
+ Returns a reference to the last item in the cache. This function
+ assumes that the cache isn't empty.
+
+ \sa first(), isEmpty()
+*/
+
+/*! \fn const T& QContiguousCache::first() const
+
+ \overload
+*/
+
+/*! \fn const T& QContiguousCache::last() const
+
+ \overload
+*/
+
+/*! \fn void QContiguousCache::removeFirst()
+
+ Removes the first item from the cache. This function assumes that
+ the cache isn't empty.
+
+ \sa removeLast()
+*/
+
+/*! \fn void QContiguousCache::removeLast()
+
+ Removes the last item from the cache. This function assumes that
+ the cache isn't empty.
+
+ \sa removeFirst()
+*/
+
+/*! \fn T QContiguousCache::takeFirst()
+
+ Removes the first item in the cache and returns it. This function
+ assumes that the cache isn't empty.
+
+ If you don't use the return value, removeFirst() is more efficient.
+
+ \sa takeLast(), removeFirst()
+*/
+
+/*! \fn T QContiguousCache::takeLast()
+
+ Removes the last item in the cache and returns it. This function
+ assumes that the cache isn't empty.
+
+ If you don't use the return value, removeLast() is more efficient.
+
+ \sa takeFirst(), removeLast()
+*/
+
+/*! \fn void QContiguousCache::normalizeIndexes()
+
+ Moves the first index and last index of the cache
+ such that they point to valid indexes. The function does not modify
+ the contents of the cache or the ordering of elements within the cache.
+
+ It is provided so that index overflows can be corrected when using the
+ cache as a circular buffer.
+
+ \code
+ QContiguousCache<int> cache(10);
+ cache.insert(INT_MAX, 1); // cache contains one value and has valid indexes, INT_MAX to INT_MAX
+ cache.append(2); // cache contains two values but does not have valid indexes.
+ cache.normalizeIndexes(); // cache has two values, 1 and 2. New first index will be in the range of 0 to capacity().
+ \endcode
+
+ \sa areIndexesValid(), append(), prepend()
+*/
+
+/*! \fn bool QContiguousCache::areIndexesValid() const
+
+ Returns whether the indexes for items stored in the cache are valid.
+ Indexes can become invalid if items are appended after the index position
+ INT_MAX or prepended before the index position 0. This is only expected
+ to occur in very long lived circular buffer style usage of the
+ contiguous cache. Indexes can be made valid again by calling
+ normalizeIndexs().
+
+ \sa normalizeIndexes(), append(), prepend()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h
new file mode 100644
index 0000000..8d44fc4
--- /dev/null
+++ b/src/corelib/tools/qcontiguouscache.h
@@ -0,0 +1,437 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTIGUOUSCACHE_H
+#define QCONTIGUOUSCACHE_H
+
+#include <QtCore/qatomic.h>
+#include <limits.h>
+#include <new>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+#undef QT_QCONTIGUOUSCACHE_DEBUG
+QT_MODULE(Core)
+
+
+struct Q_CORE_EXPORT QContiguousCacheData
+{
+ QBasicAtomicInt ref;
+ int alloc;
+ int count;
+ int start;
+ int offset;
+ uint sharable : 1;
+
+#ifdef QT_QCONTIGUOUSCACHE_DEBUG
+ void dump() const;
+#endif
+};
+
+template <typename T>
+struct QContiguousCacheTypedData
+{
+ QBasicAtomicInt ref;
+ int alloc;
+ int count;
+ int start;
+ int offset;
+ uint sharable : 1;
+ // uint unused : 31;
+
+ // total is 24 bytes (HP-UX aCC: 40 bytes)
+ // the next entry is already aligned to 8 bytes
+ // there will be an 8 byte gap here if T requires 16-byte alignment
+ // (such as long double on 64-bit platforms, __int128, __float128)
+
+ T array[1];
+};
+
+template<typename T>
+class QContiguousCache {
+ typedef QContiguousCacheTypedData<T> Data;
+ union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; };
+public:
+ explicit QContiguousCache(int capacity = 0);
+ QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); }
+
+ inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) free(d); }
+
+ inline void detach() { if (d->ref != 1) detach_helper(); }
+ inline bool isDetached() const { return d->ref == 1; }
+ inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; }
+
+ QContiguousCache<T> &operator=(const QContiguousCache<T> &other);
+ bool operator==(const QContiguousCache<T> &other) const;
+ inline bool operator!=(const QContiguousCache<T> &other) const { return !(*this == other); }
+
+ inline int capacity() const {return d->alloc; }
+ inline int count() const { return d->count; }
+ inline int size() const { return d->count; }
+
+ inline bool isEmpty() const { return d->count == 0; }
+ inline bool isFull() const { return d->count == d->alloc; }
+ inline int available() const { return d->alloc - d->count; }
+
+ void clear();
+ void setCapacity(int size);
+
+ const T &at(int pos) const;
+ T &operator[](int i);
+ const T &operator[](int i) const;
+
+ void append(const T &value);
+ void prepend(const T &value);
+ void insert(int pos, const T &value);
+
+ inline bool containsIndex(int pos) const { return pos >= d->offset && pos - d->offset < d->count; }
+ inline int firstIndex() const { return d->offset; }
+ inline int lastIndex() const { return d->offset + d->count - 1; }
+
+ inline const T &first() const { Q_ASSERT(!isEmpty()); return d->array[d->start]; }
+ inline const T &last() const { Q_ASSERT(!isEmpty()); return d->array[(d->start + d->count -1) % d->alloc]; }
+ inline T &first() { Q_ASSERT(!isEmpty()); detach(); return d->array[d->start]; }
+ inline T &last() { Q_ASSERT(!isEmpty()); detach(); return d->array[(d->start + d->count -1) % d->alloc]; }
+
+ void removeFirst();
+ T takeFirst();
+ void removeLast();
+ T takeLast();
+
+ inline bool areIndexesValid() const
+ { return d->offset >= 0 && d->offset < INT_MAX - d->count && (d->offset % d->alloc) == d->start; }
+
+ inline void normalizeIndexes() { d->offset = d->start; }
+
+#ifdef QT_QCONTIGUOUSCACHE_DEBUG
+ void dump() const { p->dump(); }
+#endif
+private:
+ void detach_helper();
+
+ QContiguousCacheData *malloc(int aalloc);
+ void free(Data *x);
+ int sizeOfTypedData() {
+ // this is more or less the same as sizeof(Data), except that it doesn't
+ // count the padding at the end
+ return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this);
+ }
+};
+
+template <typename T>
+void QContiguousCache<T>::detach_helper()
+{
+ union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x;
+
+ x.p = malloc(d->alloc);
+ x.d->ref = 1;
+ x.d->count = d->count;
+ x.d->start = d->start;
+ x.d->offset = d->offset;
+ x.d->alloc = d->alloc;
+ x.d->sharable = true;
+
+ T *dest = x.d->array + x.d->start;
+ T *src = d->array + d->start;
+ int oldcount = x.d->count;
+ while (oldcount--) {
+ if (QTypeInfo<T>::isComplex) {
+ new (dest) T(*src);
+ } else {
+ *dest = *src;
+ }
+ dest++;
+ if (dest == x.d->array + x.d->alloc)
+ dest = x.d->array;
+ src++;
+ if (src == d->array + d->alloc)
+ src = d->array;
+ }
+
+ if (!d->ref.deref())
+ free(d);
+ d = x.d;
+}
+
+template <typename T>
+void QContiguousCache<T>::setCapacity(int asize)
+{
+ if (asize == d->alloc)
+ return;
+ detach();
+ union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x;
+ x.p = malloc(asize);
+ x.d->alloc = asize;
+ x.d->count = qMin(d->count, asize);
+ x.d->offset = d->offset + d->count - x.d->count;
+ x.d->start = x.d->offset % x.d->alloc;
+ T *dest = x.d->array + (x.d->start + x.d->count-1) % x.d->alloc;
+ T *src = d->array + (d->start + d->count-1) % d->alloc;
+ int oldcount = x.d->count;
+ while (oldcount--) {
+ if (QTypeInfo<T>::isComplex) {
+ new (dest) T(*src);
+ } else {
+ *dest = *src;
+ }
+ if (dest == x.d->array)
+ dest = x.d->array + x.d->alloc;
+ dest--;
+ if (src == d->array)
+ src = d->array + d->alloc;
+ src--;
+ }
+ /* free old */
+ free(d);
+ d = x.d;
+}
+
+template <typename T>
+void QContiguousCache<T>::clear()
+{
+ if (d->ref == 1) {
+ if (QTypeInfo<T>::isComplex) {
+ int oldcount = d->count;
+ T * i = d->array + d->start;
+ T * e = d->array + d->alloc;
+ while (oldcount--) {
+ i->~T();
+ i++;
+ if (i == e)
+ i = d->array;
+ }
+ }
+ d->count = d->start = d->offset = 0;
+ } else {
+ union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x;
+ x.p = malloc(d->alloc);
+ x.d->ref = 1;
+ x.d->alloc = d->alloc;
+ x.d->count = x.d->start = x.d->offset = 0;
+ x.d->sharable = true;
+ if (!d->ref.deref()) free(d);
+ d = x.d;
+ }
+}
+
+template <typename T>
+inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc)
+{
+ return static_cast<QContiguousCacheData *>(qMalloc(sizeOfTypedData() + (aalloc - 1) * sizeof(T)));
+}
+
+template <typename T>
+QContiguousCache<T>::QContiguousCache(int cap)
+{
+ p = malloc(cap);
+ d->ref = 1;
+ d->alloc = cap;
+ d->count = d->start = d->offset = 0;
+ d->sharable = true;
+}
+
+template <typename T>
+QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &other)
+{
+ other.d->ref.ref();
+ if (!d->ref.deref())
+ free(d);
+ d = other.d;
+ if (!d->sharable)
+ detach_helper();
+ return *this;
+}
+
+template <typename T>
+bool QContiguousCache<T>::operator==(const QContiguousCache<T> &other) const
+{
+ if (other.d == d)
+ return true;
+ if (other.d->start != d->start
+ || other.d->count != d->count
+ || other.d->offset != d->offset
+ || other.d->alloc != d->alloc)
+ return false;
+ for (int i = firstIndex(); i <= lastIndex(); ++i)
+ if (!(at(i) == other.at(i)))
+ return false;
+ return true;
+}
+
+template <typename T>
+void QContiguousCache<T>::free(Data *x)
+{
+ if (QTypeInfo<T>::isComplex) {
+ int oldcount = d->count;
+ T * i = d->array + d->start;
+ T * e = d->array + d->alloc;
+ while (oldcount--) {
+ i->~T();
+ i++;
+ if (i == e)
+ i = d->array;
+ }
+ }
+ qFree(x);
+}
+template <typename T>
+void QContiguousCache<T>::append(const T &value)
+{
+ detach();
+ if (QTypeInfo<T>::isComplex) {
+ if (d->count == d->alloc)
+ (d->array + (d->start+d->count) % d->alloc)->~T();
+ new (d->array + (d->start+d->count) % d->alloc) T(value);
+ } else {
+ d->array[(d->start+d->count) % d->alloc] = value;
+ }
+
+ if (d->count == d->alloc) {
+ d->start++;
+ d->start %= d->alloc;
+ d->offset++;
+ } else {
+ d->count++;
+ }
+}
+
+template<typename T>
+void QContiguousCache<T>::prepend(const T &value)
+{
+ detach();
+ if (d->start)
+ d->start--;
+ else
+ d->start = d->alloc-1;
+ d->offset--;
+
+ if (d->count != d->alloc)
+ d->count++;
+ else
+ if (d->count == d->alloc)
+ (d->array + d->start)->~T();
+
+ if (QTypeInfo<T>::isComplex)
+ new (d->array + d->start) T(value);
+ else
+ d->array[d->start] = value;
+}
+
+template<typename T>
+void QContiguousCache<T>::insert(int pos, const T &value)
+{
+ Q_ASSERT_X(pos >= 0 && pos < INT_MAX, "QContiguousCache<T>::insert", "index out of range");
+ detach();
+ if (containsIndex(pos)) {
+ if(QTypeInfo<T>::isComplex)
+ new (d->array + pos % d->alloc) T(value);
+ else
+ d->array[pos % d->alloc] = value;
+ } else if (pos == d->offset-1)
+ prepend(value);
+ else if (pos == d->offset+d->count)
+ append(value);
+ else {
+ // we don't leave gaps.
+ clear();
+ d->offset = pos;
+ d->start = pos % d->alloc;
+ d->count = 1;
+ if (QTypeInfo<T>::isComplex)
+ new (d->array + d->start) T(value);
+ else
+ d->array[d->start] = value;
+ }
+}
+
+template <typename T>
+inline const T &QContiguousCache<T>::at(int pos) const
+{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; }
+template <typename T>
+inline const T &QContiguousCache<T>::operator[](int pos) const
+{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; }
+
+template <typename T>
+inline T &QContiguousCache<T>::operator[](int pos)
+{
+ detach();
+ if (!containsIndex(pos))
+ insert(pos, T());
+ return d->array[pos % d->alloc];
+}
+
+template <typename T>
+inline void QContiguousCache<T>::removeFirst()
+{
+ Q_ASSERT(d->count > 0);
+ detach();
+ d->count--;
+ if (QTypeInfo<T>::isComplex)
+ (d->array + d->start)->~T();
+ d->start = (d->start + 1) % d->alloc;
+ d->offset++;
+}
+
+template <typename T>
+inline void QContiguousCache<T>::removeLast()
+{
+ Q_ASSERT(d->count > 0);
+ detach();
+ d->count--;
+ if (QTypeInfo<T>::isComplex)
+ (d->array + (d->start + d->count) % d->alloc)->~T();
+}
+
+template <typename T>
+inline T QContiguousCache<T>::takeFirst()
+{ T t = first(); removeFirst(); return t; }
+
+template <typename T>
+inline T QContiguousCache<T>::takeLast()
+{ T t = last(); removeLast(); return t; }
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp
index 3cc5fba..b37d61c 100644
--- a/src/corelib/tools/qcryptographichash.cpp
+++ b/src/corelib/tools/qcryptographichash.cpp
@@ -41,6 +41,10 @@
#include <qcryptographichash.h>
+#ifdef Q_OS_SYMBIAN
+#define _MD5_H_ // Needed to disable system header
+#endif
+
#include "../../3rdparty/md5/md5.h"
#include "../../3rdparty/md5/md5.cpp"
#include "../../3rdparty/md4/md4.h"
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index 47b7a0a..d2b7135 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -49,7 +49,7 @@
#include "qregexp.h"
#include "qdebug.h"
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
-#include <windows.h>
+#include <qt_windows.h>
#endif
#ifndef Q_WS_WIN
#include <locale.h>
@@ -193,8 +193,6 @@ static QString fmtDateTime(const QString& f, const QTime* dt = 0, const QDate* d
\reentrant
\brief The QDate class provides date functions.
- \ingroup time
- \mainclass
A QDate object contains a calendar date, i.e. year, month, and day
numbers, in the Gregorian calendar. (see \l{QDate G and J} {Use of
@@ -1411,8 +1409,6 @@ void QDate::julianToGregorian(uint jd, int &y, int &m, int &d)
\brief The QTime class provides clock time functions.
- \ingroup time
- \mainclass
A QTime object contains a clock time, i.e. the number of hours,
minutes, seconds, and milliseconds since midnight. It can read the
@@ -1842,14 +1838,14 @@ QTime QTime::currentTime()
#else
t = localtime(&ltime);
#endif
-
+ Q_CHECK_PTR(t);
+
ct.mds = MSECS_PER_HOUR * t->tm_hour + MSECS_PER_MIN * t->tm_min + 1000 * t->tm_sec
+ tv.tv_usec / 1000;
#else
time_t ltime; // no millisecond resolution
::time(&ltime);
- tm *t = 0;
- localtime(&ltime);
+ const tm *const t = localtime(&ltime);
ct.mds = MSECS_PER_HOUR * t->tm_hour + MSECS_PER_MIN * t->tm_min + 1000 * t->tm_sec;
#endif
return ct;
@@ -2075,8 +2071,6 @@ int QTime::elapsed() const
\reentrant
\brief The QDateTime class provides date and time functions.
- \ingroup time
- \mainclass
A QDateTime object contains a calendar date and a clock time (a
"datetime"). It is a combination of the QDate and QTime classes.
@@ -2200,8 +2194,8 @@ int QTime::elapsed() const
\sa isValid()
*/
QDateTime::QDateTime()
+ : d(new QDateTimePrivate)
{
- d = new QDateTimePrivate;
}
@@ -2211,8 +2205,8 @@ QDateTime::QDateTime()
*/
QDateTime::QDateTime(const QDate &date)
+ : d(new QDateTimePrivate)
{
- d = new QDateTimePrivate;
d->date = date;
d->time = QTime(0, 0, 0);
}
@@ -2225,8 +2219,8 @@ QDateTime::QDateTime(const QDate &date)
*/
QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec)
+ : d(new QDateTimePrivate)
{
- d = new QDateTimePrivate;
d->date = date;
d->time = date.isValid() && !time.isValid() ? QTime(0, 0, 0) : time;
d->spec = (spec == Qt::UTC) ? QDateTimePrivate::UTC : QDateTimePrivate::LocalUnknown;
@@ -2237,9 +2231,8 @@ QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec)
*/
QDateTime::QDateTime(const QDateTime &other)
+ : d(other.d)
{
- d = other.d;
- d->ref.ref();
}
/*!
@@ -2247,8 +2240,6 @@ QDateTime::QDateTime(const QDateTime &other)
*/
QDateTime::~QDateTime()
{
- if (!d->ref.deref())
- delete d;
}
/*!
@@ -2258,7 +2249,7 @@ QDateTime::~QDateTime()
QDateTime &QDateTime::operator=(const QDateTime &other)
{
- qAtomicAssign(d, other.d);
+ d = other.d;
return *this;
}
@@ -2504,16 +2495,9 @@ QString QDateTime::toString(Qt::DateFormat f) const
buf += QLatin1Char(' ');
buf += QString::number(d->date.day());
#else
- QString winstr;
- QT_WA({
- TCHAR out[255];
- GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILDATE, out, 255);
- winstr = QString::fromUtf16((ushort*)out);
- } , {
- char out[255];
- GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILDATE, (char*)&out, 255);
- winstr = QString::fromLocal8Bit(out);
- });
+ wchar_t out[255];
+ GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILDATE, out, 255);
+ QString winstr = QString::fromWCharArray(out);
switch (winstr.toInt()) {
case 1:
buf = d->date.shortDayName(d->date.dayOfWeek());
@@ -3298,7 +3282,7 @@ QDateTime QDateTime::fromString(const QString &string, const QString &format)
*/
void QDateTime::detach()
{
- qAtomicDetach(d);
+ d.detach();
}
/*****************************************************************************
@@ -3833,19 +3817,19 @@ void QDateTimePrivate::getUTC(QDate &outDate, QTime &outTime) const
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_NO_DATESTRING)
QDebug operator<<(QDebug dbg, const QDate &date)
{
- dbg.nospace() << "QDate(" << date.toString() << ")";
+ dbg.nospace() << "QDate(" << date.toString() << ')';
return dbg.space();
}
QDebug operator<<(QDebug dbg, const QTime &time)
{
- dbg.nospace() << "QTime(" << time.toString() << ")";
+ dbg.nospace() << "QTime(" << time.toString() << ')';
return dbg.space();
}
QDebug operator<<(QDebug dbg, const QDateTime &date)
{
- dbg.nospace() << "QDateTime(" << date.toString() << ")";
+ dbg.nospace() << "QDateTime(" << date.toString() << ')';
return dbg.space();
}
#endif
@@ -4398,6 +4382,13 @@ int QDateTimeParser::sectionMaxSize(Section s, int count) const
case DateSectionMask:
qWarning("QDateTimeParser::sectionMaxSize: Invalid section %s",
sectionName(s).toLatin1().constData());
+
+ case NoSectionIndex:
+ case FirstSectionIndex:
+ case LastSectionIndex:
+ case CalendarPopupIndex:
+ // these cases can't happen
+ break;
}
return -1;
}
@@ -4688,7 +4679,7 @@ QDateTimeParser::StateNode QDateTimeParser::parse(QString &input, int &cursorPos
if (fixup && tmpstate == Intermediate && used < sn.count) {
const FieldInfo fi = fieldInfo(index);
if ((fi & (Numeric|FixedWidth)) == (Numeric|FixedWidth)) {
- const QString newText = QString(QLatin1String("%1")).arg(num, sn.count, 10, QLatin1Char('0'));
+ const QString newText = QString::fromLatin1("%1").arg(num, sn.count, 10, QLatin1Char('0'));
input.replace(pos, used, newText);
used = sn.count;
}
diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h
index a1279db..1af3132 100644
--- a/src/corelib/tools/qdatetime.h
+++ b/src/corelib/tools/qdatetime.h
@@ -44,6 +44,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qnamespace.h>
+#include <QtCore/qsharedpointer.h>
QT_BEGIN_HEADER
@@ -284,7 +285,7 @@ public:
private:
friend class QDateTimePrivate;
void detach();
- QDateTimePrivate *d;
+ QExplicitlySharedDataPointer<QDateTimePrivate> d;
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QDateTime &);
diff --git a/src/corelib/tools/qdatetime_p.h b/src/corelib/tools/qdatetime_p.h
index a8ab8bf..7f9c3bd 100644
--- a/src/corelib/tools/qdatetime_p.h
+++ b/src/corelib/tools/qdatetime_p.h
@@ -81,9 +81,9 @@ class QDateTimePrivate
public:
enum Spec { LocalUnknown = -1, LocalStandard = 0, LocalDST = 1, UTC = 2, OffsetFromUTC = 3};
- QDateTimePrivate() : ref(1), spec(LocalUnknown), utcOffset(0) {}
+ QDateTimePrivate() : spec(LocalUnknown), utcOffset(0) {}
QDateTimePrivate(const QDateTimePrivate &other)
- : ref(1), date(other.date), time(other.time), spec(other.spec), utcOffset(other.utcOffset)
+ : date(other.date), time(other.time), spec(other.spec), utcOffset(other.utcOffset)
{}
QAtomicInt ref;
@@ -138,13 +138,6 @@ public:
PossibleBoth = 4
};
- enum {
- NoSectionIndex = -1,
- FirstSectionIndex = -2,
- LastSectionIndex = -3,
- CalendarPopupIndex = -4
- };
-
enum Section {
NoSection = 0x00000,
AmPmSection = 0x00001,
@@ -163,7 +156,12 @@ public:
DateSectionMask = (DaySection|MonthSection|YearSection|YearSection2Digits|DayOfWeekSection),
FirstSection = 0x02000|Internal,
LastSection = 0x04000|Internal,
- CalendarPopupSection = 0x08000|Internal
+ CalendarPopupSection = 0x08000|Internal,
+
+ NoSectionIndex = -1,
+ FirstSectionIndex = -2,
+ LastSectionIndex = -3,
+ CalendarPopupIndex = -4
}; // duplicated from qdatetimeedit.h
Q_DECLARE_FLAGS(Sections, Section)
diff --git a/src/corelib/tools/qdumper.cpp b/src/corelib/tools/qdumper.cpp
deleted file mode 100644
index 7c88f39..0000000
--- a/src/corelib/tools/qdumper.cpp
+++ /dev/null
@@ -1,1157 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain
-** additional rights. These rights are described in the Nokia Qt LGPL
-** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
-** package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <qdatetime.h>
-#include <qdebug.h>
-#include <qdir.h>
-#include <qfileinfo.h>
-#include <qhash.h>
-#include <qmap.h>
-#include <qmetaobject.h>
-#include <qobject.h>
-#include <qstring.h>
-#include <qvariant.h>
-#include <qvector.h>
-
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_DUMPER)
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifdef Q_OS_WIN
-# include <windows.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-namespace {
-
-// This is used to abort evaluation of custom data dumpers in a "coordinated"
-// way. Abortion will happen anyway when we try to access a non-initialized
-// non-trivial object, so there is no way to prevent this from occuring at all
-// conceptionally. Gdb will catch SIGSEGV and return to the calling frame.
-// This is just fine provided we only _read_ memory in the custom handlers
-// below.
-
-volatile int qProvokeSegFaultHelper;
-
-static void qCheckAccess(const void *d)
-{
- // provoke segfault when address is not readable
- qProvokeSegFaultHelper = *(char*)d;
-}
-
-static void qCheckPointer(const void *d)
-{
- if (!d)
- return;
- qProvokeSegFaultHelper = *(char*)d;
-}
-
-static void qProvokeSegFault()
-{
- // provoke segfault unconditionally
- qCheckAccess(0);
-}
-
-static char qDumpInBuffer[100];
-static char qDumpBuffer[1000];
-#ifdef Q_OS_WIN
-static char qDumpBuffer2[sizeof(qDumpBuffer) + 100];
-#endif
-
-static char toHex(int n)
-{
- return n < 10 ? '0' + n : 'a' - 10 + n;
-}
-
-
-struct QDumper
-{
- explicit QDumper();
- ~QDumper();
- void flush();
- QDumper &operator<<(long c);
- QDumper &operator<<(int i);
- QDumper &operator<<(unsigned long c);
- QDumper &operator<<(unsigned int i);
- QDumper &operator<<(const void *p);
- void put(char c);
- void addCommaIfNeeded();
- void putEncoded(unsigned c);
- QDumper &operator<<(const char *str);
- QDumper &operator<<(const QString &str);
- void disarm();
-
- void beginHash(); // start of data hash output
- void endHash(); // start of data hash output
-
- // the dumper arguments
- int protocolVersion; // dumper protocol version
- int token; // some token to show on success
- const char *outertype; // object type
- const char *iname; // object name used for display
- const char *exp; // object expression
- const char *innertype; // 'inner type' for class templates
- const void *data; // pointer to raw data
- bool dumpChildren; // do we want to see children?
-
- // handling of nested templates
- void setupTemplateParameters();
- enum { maxTemplateParameters = 10 };
- const char *templateParameters[maxTemplateParameters + 1];
- int templateParametersCount;
-
- // internal state
- bool success; // are we finished?
- size_t pos;
-};
-
-
-QDumper::QDumper()
-{
- success = false;
- pos = 0;
-}
-
-QDumper::~QDumper()
-{
- flush();
- put(0); // our end marker
-#ifdef Q_OS_WIN
- sprintf(qDumpBuffer2, "@@CDD/%d/done\n", token);
- OutputDebugStringA(qDumpBuffer2);
-#else
- fprintf(stderr, "%d/done\n", token);
-#endif
- qDumpInBuffer[0] = 0;
-}
-
-void QDumper::flush()
-{
- qDumpBuffer[pos++] = 0;
-#ifdef Q_OS_WIN
- sprintf(qDumpBuffer2, "@@CDD#%d#%d,%s\n", token, int(pos - 1), qDumpBuffer);
- OutputDebugStringA(qDumpBuffer2);
-#else
- fprintf(stderr, "%d#%d,%s\n", token, int(pos - 1), qDumpBuffer);
-#endif
- pos = 0;
-}
-
-void QDumper::setupTemplateParameters()
-{
- char *s = const_cast<char *>(innertype);
-
- templateParametersCount = 1;
- templateParameters[0] = s;
- for (int i = 1; i != maxTemplateParameters + 1; ++i)
- templateParameters[i] = 0;
-
- while (*s) {
- while (*s && *s != '@')
- ++s;
- if (*s) {
- *s = '\0';
- ++s;
- templateParameters[templateParametersCount++] = s;
- }
- }
-}
-
-QDumper &QDumper::operator<<(unsigned long c)
-{
- static char buf[100];
- sprintf(buf, "%lu", c);
- return (*this) << buf;
-}
-
-QDumper &QDumper::operator<<(unsigned int i)
-{
- static char buf[100];
- sprintf(buf, "%u", i);
- return (*this) << buf;
-}
-
-QDumper &QDumper::operator<<(long c)
-{
- static char buf[100];
- sprintf(buf, "%ld", c);
- return (*this) << buf;
-}
-
-QDumper &QDumper::operator<<(int i)
-{
- static char buf[100];
- sprintf(buf, "%d", i);
- return (*this) << buf;
-}
-
-QDumper &QDumper::operator<<(const void *p)
-{
- static char buf[100];
- sprintf(buf, "%p", p);
- // we get a '0x' prefix only on some implementations.
- // if it isn't there, write it out manually.
- if (buf[1] != 'x') {
- put('0');
- put('x');
- }
- return (*this) << buf;
-}
-
-void QDumper::put(char c)
-{
- if (pos >= sizeof(qDumpBuffer) - 100)
- flush();
- qDumpBuffer[pos++] = c;
-}
-
-void QDumper::addCommaIfNeeded()
-{
- if (pos == 0)
- return;
- if (qDumpBuffer[pos - 1] == '}' || qDumpBuffer[pos - 1] == '"')
- put(',');
-}
-
-void QDumper::putEncoded(unsigned c)
-{
- if (c >= 32 && c <= 126 && c != '"' && c != '\\') {
- put(c);
- } else {
- put('\\');
- put('u');
- put(toHex((c >> 12) & 0xf));
- put(toHex((c >> 8) & 0xf));
- put(toHex((c >> 4) & 0xf));
- put(toHex( c & 0xf));
- }
-}
-
-QDumper &QDumper::operator<<(const char *str)
-{
- while (*str)
- put(*(str++));
- return *this;
-}
-
-QDumper &QDumper::operator<<(const QString &str)
-{
- int n = str.size();
- if (n < 0) {
- qProvokeSegFault();
- } else {
- //(*this) << "[" << n << "]";
- if (n > 1000000)
- n = 1000000;
- //put(' ');
- put('\\');
- put('"');
- for (int i = 0; i != n; ++i)
- putEncoded(str[i].unicode());
- put('\\');
- put('"');
- if (n < str.size())
- (*this) << "<incomplete string>";
- }
- return *this;
-}
-
-void QDumper::disarm()
-{
- flush();
- success = true;
-}
-
-void QDumper::beginHash()
-{
- addCommaIfNeeded();
- put('{');
-}
-
-void QDumper::endHash()
-{
- put('}');
-}
-
-
-//
-// Some helpers to keep the dumper code short
-//
-
-// dump property=value pair
-#undef P
-#define P(dumper,name,value) \
- do { \
- dumper.addCommaIfNeeded(); \
- dumper << (name) << "=\"" << value << "\""; \
- } while (0)
-
-// simple string property
-#undef S
-#define S(dumper, name, value) \
- dumper.beginHash(); \
- P(dumper, "name", name); \
- P(dumper, "value", value); \
- P(dumper, "type", "QString"); \
- P(dumper, "numchild", "0"); \
- dumper.endHash();
-
-// simple integer property
-#undef I
-#define I(dumper, name, value) \
- dumper.beginHash(); \
- P(dumper, "name", name); \
- P(dumper, "value", value); \
- P(dumper, "type", "int"); \
- P(dumper, "numchild", "0"); \
- dumper.endHash();
-
-// simple boolean property
-#undef BL
-#define BL(dumper, name, value) \
- dumper.beginHash(); \
- P(dumper, "name", name); \
- P(dumper, "value", (value ? "true" : "false")); \
- P(dumper, "type", "bool"); \
- P(dumper, "numchild", "0"); \
- dumper.endHash();
-
-#undef TT
-#define TT(type, value) \
- "<tr><td>" << type << "</td><td> : </td><td>" << value << "</td></tr>"
-
-static void qDumpUnknown(QDumper &d)
-{
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", "<internal error>");
- P(d, "type", d.outertype);
- P(d, "numchild", "0");
- d.disarm();
-}
-
-static void qDumpQPropertyList(QDumper &d)
-{
- const QObject *ob = (const QObject *)d.data;
- const QMetaObject *mo = ob->metaObject();
- P(d, "iname", d.iname);
- P(d, "addr", "<synthetic>");
- P(d, "type", "QObject");
- P(d, "numchild", mo->propertyCount());
- if (d.dumpChildren) {
- d << ",children=[";
- for (int i = mo->propertyCount(); --i >= 0; ) {
- const QMetaProperty & prop = mo->property(i);
- d.beginHash();
- P(d, "name", prop.name());
- if (QLatin1String(prop.typeName()) == QLatin1String("QString")) {
- P(d, "value", prop.read(ob).toString());
- P(d, "numchild", "0");
- } else if (QLatin1String(prop.typeName()) == QLatin1String("bool")) {
- P(d, "value", (prop.read(ob).toBool() ? "true" : "false"));
- P(d, "numchild", "0");
- } else if (QLatin1String(prop.typeName()) == QLatin1String("int")) {
- P(d, "value", prop.read(ob).toInt());
- P(d, "numchild", "0");
- } else {
- P(d, "exp", "((" << mo->className() << "*)" << ob
- << ")->" << prop.name() << "()");
- }
- P(d, "type", prop.typeName());
- P(d, "numchild", "1");
- d.endHash();
- }
- d << "]";
- }
- d.disarm();
-}
-
-static void qDumpQObject(QDumper &d)
-{
- const QObject *ob = reinterpret_cast<const QObject *>(d.data);
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", (void*)d.data);
- P(d, "type", "QObject");
- P(d, "numchild", 4);
- if (d.dumpChildren) {
- const QMetaObject *mo = ob->metaObject();
- const QObjectList &children = ob->children();
- d << ",children=[";
- S(d, "objectName", ob->objectName());
- d.beginHash();
- P(d, "name", "properties");
- // FIXME: Note that when simply using '(QObject*)'
- // in the cast below, Gdb/MI _sometimes misparses
- // expressions further down in the tree.
- P(d, "exp", "*(class QObject*)" << d.data);
- P(d, "type", "QPropertyList");
- P(d, "value", "<" << mo->propertyCount() << " items>");
- P(d, "numchild", mo->propertyCount());
- d.endHash();
- d.beginHash();
- P(d, "name", "children");
- P(d, "exp", "((class QObject*)" << d.data << ")->children()");
- P(d, "type", "QList<QObject *>");
- P(d, "value", "<" << children.size() << " items>");
- P(d, "numchild", children.size());
- d.endHash();
- d.beginHash();
- P(d, "name", "parent");
- P(d, "exp", "((class QObject*)" << d.data << ")->parent()");
- P(d, "type", "QObject *");
- P(d, "numchild", (ob->parent() ? "1" : "0"));
- d.endHash();
- d << "]";
- }
- d.disarm();
-}
-
-static void qDumpQDir(QDumper &d)
-{
- const QDir &dir = *reinterpret_cast<const QDir *>(d.data);
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", dir.path());
- P(d, "type", "QDir");
- P(d, "numchild", "3");
- if (d.dumpChildren) {
- d << ",children=[";
- S(d, "absolutePath", dir.absolutePath());
- S(d, "canonicalPath", dir.canonicalPath());
- d << "]";
- }
- d.disarm();
-}
-
-static void qDumpQFileInfo(QDumper &d)
-{
- const QFileInfo &info = *reinterpret_cast<const QFileInfo *>(d.data);
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", info.filePath());
- P(d, "type", "QDir");
- P(d, "numchild", "3");
- if (d.dumpChildren) {
- d << ",children=[";
- S(d, "absolutePath", info.absolutePath());
- S(d, "absoluteFilePath", info.absoluteFilePath());
- S(d, "canonicalPath", info.canonicalPath());
- S(d, "canonicalFilePath", info.canonicalFilePath());
- S(d, "completeBaseName", info.completeBaseName());
- S(d, "completeSuffix", info.completeSuffix());
- S(d, "baseName", info.baseName());
-#ifdef Q_OS_MACX
- BL(d, "isBundle", info.isBundle());
- S(d, "bundleName", info.bundleName());
-#endif
- S(d, "completeSuffix", info.completeSuffix());
- S(d, "fileName", info.fileName());
- S(d, "filePath", info.filePath());
- S(d, "group", info.group());
- S(d, "owner", info.owner());
- S(d, "path", info.path());
-
- I(d, "groupid", (long)info.groupId());
- I(d, "ownerid", (long)info.ownerId());
- //QFile::Permissions permissions () const
- I(d, "permissions", info.permissions());
-
- //QDir absoluteDir () const
- //QDir dir () const
-
- BL(d, "caching", info.caching());
- BL(d, "exists", info.exists());
- BL(d, "isAbsolute", info.isAbsolute());
- BL(d, "isDir", info.isDir());
- BL(d, "isExecutable", info.isExecutable());
- BL(d, "isFile", info.isFile());
- BL(d, "isHidden", info.isHidden());
- BL(d, "isReadable", info.isReadable());
- BL(d, "isRelative", info.isRelative());
- BL(d, "isRoot", info.isRoot());
- BL(d, "isSymLink", info.isSymLink());
- BL(d, "isWritable", info.isWritable());
-
-#ifndef QT_NO_DATESTRING
- d.beginHash();
- P(d, "name", "created");
- P(d, "value", info.created().toString());
- P(d, "exp", "((QFileInfo*)" << d.data << ")->created()");
- P(d, "type", "QDateTime");
- P(d, "numchild", "1");
- d.endHash();
-
- d.beginHash();
- P(d, "name", "lastModified");
- P(d, "value", info.lastModified().toString());
- P(d, "exp", "((QFileInfo*)" << d.data << ")->lastModified()");
- P(d, "type", "QDateTime");
- P(d, "numchild", "1");
- d.endHash();
-
- d.beginHash();
- P(d, "name", "lastRead");
- P(d, "value", info.lastRead().toString());
- P(d, "exp", "((QFileInfo*)" << d.data << ")->lastRead()");
- P(d, "type", "QDateTime");
- P(d, "numchild", "1");
- d.endHash();
-#endif
-
- d << "]";
- }
- d.disarm();
-}
-
-static void qDumpQDateTime(QDumper &d)
-{
-#ifdef QT_NO_DATESTRING
- qDumpUnknown(d);
-#else
- const QDateTime &date = *reinterpret_cast<const QDateTime *>(d.data);
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", date.toString());
- P(d, "type", "QDateTime");
- P(d, "numchild", "3");
- if (d.dumpChildren) {
- d << ",children=[";
- BL(d, "isNull", date.isNull());
- I(d, "toTime_t", (long)date.toTime_t());
- S(d, "toString", date.toString());
- S(d, "toString_(ISO)", date.toString(Qt::ISODate));
- S(d, "toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
- S(d, "toString_(Locale)", date.toString(Qt::LocaleDate));
- S(d, "toString", date.toString());
-
- d.beginHash();
- P(d, "name", "toUTC");
- P(d, "exp", "((QDateTime*)" << d.data << ")->toTimeSpec(Qt::UTC)");
- P(d, "type", "QDateTime");
- P(d, "numchild", "1");
- d.endHash();
-
- d.beginHash();
- P(d, "name", "toLocalTime");
- P(d, "exp", "((QDateTime*)" << d.data << ")->toTimeSpec(Qt::LocalTime)");
- P(d, "type", "QDateTime");
- P(d, "numchild", "1");
- d.endHash();
-
- d << "]";
- }
- d.disarm();
-#endif // ifdef QT_NO_DATESTRING
-}
-
-static void qDumpQString(QDumper &d)
-{
- const QString &str = *reinterpret_cast<const QString *>(d.data);
-
- // Try to provoke segfaults early to prevent the frontend
- // from asking for unavailable child details
- if (!str.isEmpty()) {
- volatile ushort dummy = 0;
- dummy += str.at(0).unicode();
- dummy += str.at(str.size() - 1).unicode();
- }
-
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", str);
- P(d, "type", "QString");
- P(d, "numchild", "0");
- d.disarm();
-}
-
-static void qDumpQStringList(QDumper &d)
-{
- const QStringList &list = *reinterpret_cast<const QStringList *>(d.data);
- int n = list.size();
- if (n < 0)
- qProvokeSegFault();
- if (n > 0) {
- qCheckAccess(&list.front());
- qCheckAccess(&list.back());
- }
-
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", "<" << n << " items>");
- P(d, "valuedisabled", "true");
- P(d, "numchild", n);
- if (d.dumpChildren) {
- if (n > 100)
- n = 100;
- d << ",children=[";
- for (int i = 0; i != n; ++i) {
- S(d, "[" << i << "]", list[i]);
- }
- if (n < list.size()) {
- d.beginHash();
- P(d, "value", "<incomplete>");
- P(d, "type", " ");
- P(d, "numchild", "0");
- d.endHash();
- }
- d << "]";
- }
- d.disarm();
-}
-
-static void qDumpQVariantHelper(const void *data, QString *value,
- QString *exp, int *numchild)
-{
- const QVariant &v = *reinterpret_cast<const QVariant *>(data);
- switch (v.type()) {
- case QVariant::Invalid:
- *value = QLatin1String("<invalid>");
- *numchild = 0;
- break;
- case QVariant::String:
- *value = QLatin1Char('"') + v.toString() + QLatin1Char('"');
- *numchild = 0;
- break;
- case QVariant::StringList:
- *exp = QString(QLatin1String("((QVariant*)%1)->d.data.c"))
- .arg((qulonglong)data);
- *numchild = v.toStringList().size();
- break;
- case QVariant::Int:
- *value = QString::number(v.toInt());
- *numchild= 0;
- break;
- case QVariant::Double:
- *value = QString::number(v.toDouble());
- *numchild = 0;
- break;
- default:
- // FIXME
- //*exp = QString("qVariantValue<" << v.typeName() << ">"
- // << "(*(QVariant*)" << data << ")");
- break;
- }
-}
-
-static void qDumpQVariant(QDumper &d)
-{
- const QVariant &v = *reinterpret_cast<const QVariant *>(d.data);
- QString value;
- QString exp;
- int numchild = 0;
- qDumpQVariantHelper(d.data, &value, &exp, &numchild);
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", "(" << v.typeName() << ") " << qPrintable(value));
- P(d, "type", "QVariant");
- P(d, "numchild", 1);
- if (d.dumpChildren) {
- d << ",children=[";
- d.beginHash();
- P(d, "name", "value");
- if (!exp.isEmpty())
- P(d, "exp", qPrintable(exp));
- if (!value.isEmpty())
- P(d, "value", qPrintable(value));
- P(d, "type", v.typeName());
- P(d, "numchild", numchild);
- d.endHash();
- d << "]";
- }
- d.disarm();
-}
-
-static void qDumpQList(QDumper &d)
-{
- // This uses the knowledge that QList<T> has only a single member
- // of type union { QListData p; QListData::Data *d; };
- const QListData &ldata = *reinterpret_cast<const QListData*>(d.data);
- const QListData::Data *pdata = *reinterpret_cast<const QListData::Data* const*>(d.data);
- int nn = ldata.size();
- if (nn < 0)
- qProvokeSegFault();
- if (nn > 0) {
- qCheckAccess(ldata.d->array);
- //qCheckAccess(ldata.d->array[0]);
- //qCheckAccess(ldata.d->array[nn - 1]);
- }
-
- int n = nn;
- P(d, "iname", d.iname);
- P(d, "value", "<" << n << " items>");
- P(d, "valuedisabled", "true");
- P(d, "numchild", n);
- if (d.dumpChildren) {
- if (n > 100)
- n = 100;
- d << ",children=[";
- for (int i = 0; i != n; ++i) {
- d.beginHash();
- P(d, "name", "[" << i << "]");
- // The exact condition here is:
- // QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
- // but this data is not available in the compiled binary.
- // So as first approximation only do the 'isLarge' check:
- void *p = &(ldata.d->array[i + pdata->begin]);
- unsigned long voidpsize = sizeof(void*);
- P(d, "exp", "(sizeof(" << d.innertype << ")>" << voidpsize <<
- "?(**(" << d.innertype << "**)(" << p << "))"
- ":(*(" << d.innertype << "*)(" << p << ")))");
- P(d, "type", d.innertype);
- d.endHash();
- }
- if (n < nn) {
- d << ",{";
- P(d, "value", "<incomplete>");
- d.endHash();
- }
- d << "]";
- }
- d.disarm();
-}
-
-static void qDumpQVector(QDumper &d)
-{
- // Use 'int' as representative value. No way (and no need)
- // to deduce proper type here.
- const QVector<int> &vec = *reinterpret_cast<const QVector<int> *>(d.data);
- const int nn = vec.size();
-
- // Try to provoke segfaults early to prevent the frontend
- // from asking for unavailable child details
- if (nn < 0)
- qProvokeSegFault();
- if (nn > 0) {
- qCheckAccess(&vec.front());
- qCheckAccess(&vec.back());
- }
-
- //int innersize = 0;
- //scanf(qDumpInBuffer, "%d", &innersize);
-
- int n = nn;
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", "<" << n << " items>");
- P(d, "valuedisabled", "true");
- P(d, "numchild", n);
- if (d.dumpChildren) {
- if (n > 100)
- n = 100;
- d << ",children=[";
- for (int i = 0; i != n; ++i) {
- if (i)
- d << ",";
- d.beginHash();
- P(d, "name", "[" << i << "]");
- P(d, "exp", "(" << d.exp << ".d->array[" << i << "])");
- P(d, "type", d.innertype);
- d.endHash();
- }
- if (n < nn) {
- d << ",{";
- P(d, "value", "<incomplete>");
- d.endHash();
- }
- d << "]";
- }
- d.disarm();
-}
-
-static void qDumpQHashNode(QDumper &d)
-{
- struct NodeOS { void *next; uint k; uint v; } nodeOS; // int-key optimization, small value
- struct NodeOL { void *next; uint k; void *v; } nodeOL; // int-key optimiatzion, large value
- struct NodeNS { void *next; uint h; uint k; uint v; } nodeNS; // no optimization, small value
- struct NodeNL { void *next; uint h; uint k; void *v; } nodeNL; // no optimization, large value
- struct NodeL { void *next; uint h; void *k; void *v; } nodeL; // complex key
-
- // offsetof(...,...) not yet in Standard C++
- const ulong nodeOSk ( (char *)&nodeOS.k - (char *)&nodeOS );
- const ulong nodeOSv ( (char *)&nodeOS.v - (char *)&nodeOS );
- const ulong nodeOLk ( (char *)&nodeOL.k - (char *)&nodeOL );
- const ulong nodeOLv ( (char *)&nodeOL.v - (char *)&nodeOL );
- const ulong nodeNSk ( (char *)&nodeNS.k - (char *)&nodeNS );
- const ulong nodeNSv ( (char *)&nodeNS.v - (char *)&nodeNS );
- const ulong nodeNLk ( (char *)&nodeNL.k - (char *)&nodeNL );
- const ulong nodeNLv ( (char *)&nodeNL.v - (char *)&nodeNL );
- const ulong nodeLk ( (char *)&nodeL.k - (char *)&nodeL );
- const ulong nodeLv ( (char *)&nodeL.v - (char *)&nodeL );
-
- const QHashData *h = reinterpret_cast<const QHashData *>(d.data);
- const char *keyType = d.templateParameters[0];
- const char *valueType = d.templateParameters[1];
-
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", "");
- P(d, "numchild", 2);
- if (d.dumpChildren) {
- // there is a hash specialization in cast the key are integers or shorts
- bool isOptimizedIntKey = qstrcmp(keyType, "int") == 0
-#if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- || qstrcmp(keyType, "short") == 0
- || qstrcmp(keyType, "ushort") == 0
-#endif
- || qstrcmp(keyType, "uint") == 0;
-
- d << ",children=[";
- d.beginHash();
- P(d, "name", "key");
- P(d, "type", keyType);
- unsigned long intsize = sizeof(int);
- if (isOptimizedIntKey) {
- P(d, "exp", "*(" << keyType << "*)"
- "(((sizeof(" << valueType << ")>" << intsize << ")?"
- << nodeOLk << ":" << nodeOSk <<
- ")+(char*)" << h << ")");
- } else {
- P(d, "exp", "*(" << keyType << "*)"
- "(((sizeof(" << keyType << ")>" << intsize << ")?"
- << nodeLk << ":"
- "((sizeof(" << valueType << ")>" << intsize << ")?"
- << nodeNLk << ":" << nodeNSk << "))+(char*)" << h << ")");
- }
- d.endHash();
- d.beginHash();
- P(d, "name", "value");
- P(d, "type", valueType);
- if (isOptimizedIntKey) {
- P(d, "exp", "*(" << valueType << "*)"
- "(((sizeof(" << valueType << ")>" << intsize << ")?"
- << nodeOLv << ":" << nodeOSv << ")+(char*)" << h << ")");
- } else {
- P(d, "exp", "*(" << valueType << "*)"
- "(((sizeof(" << keyType << ")>" << intsize << ")?" << nodeLv << ":"
- "((sizeof(" << valueType << ")>" << intsize << ")?"
- << nodeNLv << ":" << nodeNSv << "))+(char*)" << h << ")");
- }
- d.endHash();
- d << "]";
- }
- d.disarm();
-}
-
-static void qDumpQHash(QDumper &d)
-{
- QHashData *h = *reinterpret_cast<QHashData *const*>(d.data);
- const char *keyType = d.templateParameters[0];
- const char *valueType = d.templateParameters[1];
-
- qCheckPointer(h->fakeNext);
- qCheckPointer(h->buckets);
-
- int n = h->size;
-
- if (n < 0)
- qProvokeSegFault();
- if (n > 0) {
- qCheckPointer(h->fakeNext);
- qCheckPointer(*h->buckets);
- }
-
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", "<" << n << " items>");
- P(d, "numchild", n);
- if (d.dumpChildren) {
- if (n > 100)
- n = 100;
- d << ",children=[";
-
- QHashData::Node *node = h->firstNode();
- QHashData::Node *end = reinterpret_cast<QHashData::Node *>(h);
- int i = 0;
-
- while (node != end) {
- d.beginHash();
- P(d, "name", "[" << i << "]");
- P(d, "type", "QHashNode<" << keyType << "," << valueType << " >");
- P(d, "exp", "*(QHashNode<" << keyType << "," << valueType << " >*)" << node);
- d.endHash();
-
- ++i;
- node = QHashData::nextNode(node);
- }
- d << "]";
- }
- d.disarm();
-}
-
-static void qDumpQMapNode(QDumper &d)
-{
- const QMapData *h = reinterpret_cast<const QMapData *>(d.data);
- const char *keyType = d.templateParameters[0];
- const char *valueType = d.templateParameters[1];
-
- qCheckAccess(h->backward);
- qCheckAccess(h->forward[0]);
-
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", "");
- P(d, "numchild", 2);
- if (d.dumpChildren) {
- unsigned long voidpsize = sizeof(void*);
- d << ",children=[";
- d.beginHash();
- P(d, "name", "key");
- P(d, "type", keyType);
- P(d, "exp", "*(" << keyType << "*)"
- << "("
- << 2 * voidpsize
- << "-sizeof('QMap<" << keyType << "," << valueType << ">::Node')"
- << "+(char*)" << h
- << ")");
- d.endHash();
- d.beginHash();
- P(d, "name", "value");
- P(d, "type", valueType);
- P(d, "exp", "*(" << valueType << "*)"
- << "("
- << "(size_t)&(('QMap<" << keyType << "," << valueType << ">::Node'*)0)->value"
- << "+" << 2 * voidpsize
- << "-sizeof('QMap<" << keyType << "," << valueType << ">::Node')"
- << "+(char*)" << h
- << ")");
- d.endHash();
- d << "]";
- }
-
- d.disarm();
-}
-
-static void qDumpQMap(QDumper &d)
-{
- QMapData *h = *reinterpret_cast<QMapData *const*>(d.data);
- const char *keyType = d.templateParameters[0];
- const char *valueType = d.templateParameters[1];
-
- int n = h->size;
-
- if (n < 0)
- qProvokeSegFault();
- if (n > 0) {
- qCheckAccess(h->backward);
- qCheckAccess(h->forward[0]);
- qCheckPointer(h->backward->backward);
- qCheckPointer(h->forward[0]->backward);
- }
-
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", "<" << n << " items>");
- P(d, "numchild", n);
- if (d.dumpChildren) {
- if (n > 100)
- n = 100;
- d << ",children=[";
-
- QMapData::Node *node = reinterpret_cast<QMapData::Node *>(h->forward[0]);
- QMapData::Node *end = reinterpret_cast<QMapData::Node *>(h);
- int i = 0;
-
- while (node != end) {
- d.beginHash();
- P(d, "name", "[" << i << "]");
- P(d, "type", "QMap<" << keyType << "," << valueType << ">::Node");
- P(d, "exp", "*('QMap<" << keyType << "," << valueType << ">::Node'*)" << node);
- d.endHash();
-
- ++i;
- node = node->forward[0];
- }
- d << "]";
- }
-
- d.disarm();
-}
-
-static void qDumpQSet(QDumper &d)
-{
- // This uses the knowledge that QHash<T> has only a single member
- // of union { QHashData *d; QHashNode<Key, T> *e; };
- QHashData *hd = *(QHashData**)d.data;
- QHashData::Node *node = hd->firstNode();
-
- int n = hd->size;
- if (n < 0)
- qProvokeSegFault();
- if (n > 0) {
- qCheckAccess(node);
- qCheckPointer(node->next);
- }
-
- P(d, "iname", d.iname);
- P(d, "addr", d.data);
- P(d, "value", "<" << n << " items>");
- P(d, "valuedisabled", "true");
- P(d, "numchild", 2 * n);
- if (d.dumpChildren) {
- if (n > 100)
- n = 100;
- d << ",children=[";
- int i = 0;
- for (int bucket = 0; bucket != hd->numBuckets; ++bucket) {
- for (node = hd->buckets[bucket]; node->next; node = node->next) {
- d.beginHash();
- P(d, "name", "[" << i << "]");
- P(d, "type", d.innertype);
- P(d, "exp", "(('QHashNode<" << d.innertype
- << ",QHashDummyValue>'*)"
- << static_cast<const void*>(node) << ")->key"
- );
- d.endHash();
- ++i;
- }
- }
- d << "]";
- }
- d.disarm();
-}
-
-static void handleProtocolVersion2(QDumper & d)
-{
- if (!d.outertype[0]) {
- qDumpUnknown(d);
- return;
- }
-
- d.setupTemplateParameters();
- // d.outertype[0] is usally 'Q', so don't use it
- switch (d.outertype[1]) {
- case 'D':
- if (qstrcmp(d.outertype, "QDateTime") == 0)
- qDumpQDateTime(d);
- else if (qstrcmp(d.outertype, "QDir") == 0)
- qDumpQDir(d);
- break;
- case 'F':
- if (qstrcmp(d.outertype, "QFileInfo") == 0)
- qDumpQFileInfo(d);
- break;
- case 'H':
- if (qstrcmp(d.outertype, "QHash") == 0)
- qDumpQHash(d);
- else if (qstrcmp(d.outertype, "QHashNode") == 0)
- qDumpQHashNode(d);
- break;
- case 'L':
- if (qstrcmp(d.outertype, "QList") == 0)
- qDumpQList(d);
- break;
- case 'M':
- if (qstrcmp(d.outertype, "QMap") == 0)
- qDumpQMap(d);
- else if (qstrcmp(d.outertype, "QMap::Node") == 0)
- qDumpQMapNode(d);
- break;
- case 'O':
- if (qstrcmp(d.outertype, "QObject") == 0)
- qDumpQObject(d);
- break;
- case 'P':
- if (qstrcmp(d.outertype, "QPropertyList") == 0)
- qDumpQPropertyList(d);
- break;
- case 'S':
- if (qstrcmp(d.outertype, "QSet") == 0)
- qDumpQSet(d);
- else if (qstrcmp(d.outertype, "QString") == 0)
- qDumpQString(d);
- else if (qstrcmp(d.outertype, "QStringList") == 0)
- qDumpQStringList(d);
- break;
- case 'V':
- if (qstrcmp(d.outertype, "QVariant") == 0)
- qDumpQVariant(d);
- else if (qstrcmp(d.outertype, "QVector") == 0)
- qDumpQVector(d);
- break;
- }
-
- if (!d.success)
- qDumpUnknown(d);
-}
-
-} // anonymous namespace
-
-
-extern "C" Q_CORE_EXPORT void qDumpObjectData(
- int protocolVersion,
- int token,
- const char *outertype,
- const char *iname,
- const char *exp,
- const char *innertype,
- const void *data,
- bool dumpChildren)
-{
- if (protocolVersion == 1) {
- // used to test whether error output gets through
- //fprintf(stderr, "using stderr, qDebug follows: %d\n", token);
- //qDebug() << "using qDebug, stderr already used: " << token;
- }
-
- else if (protocolVersion == 2) {
- QDumper d;
- d.protocolVersion = protocolVersion;
- d.token = token;
- d.outertype = outertype ? outertype : "";
- d.iname = iname ? iname : "";
- d.exp = exp ? exp : "";
- d.innertype = innertype ? innertype : "";
- d.data = data ? data : "";
- d.dumpChildren = dumpChildren;
- handleProtocolVersion2(d);
- }
-
- else {
- qDebug() << "Unsupported protocol version" << protocolVersion;
- }
-}
-
-QT_END_NAMESPACE
-
-#endif // !Q_OS_WINCE && !QT_NO_QDUMPER
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
new file mode 100644
index 0000000..e84e3f0
--- /dev/null
+++ b/src/corelib/tools/qeasingcurve.cpp
@@ -0,0 +1,850 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+
+| *property* | *Used for type* |
+| period | QEasingCurve::{In,Out,InOut,OutIn}Elastic |
+| amplitude | QEasingCurve::{In,Out,InOut,OutIn}Bounce, QEasingCurve::{In,Out,InOut,OutIn}Elastic |
+| overshoot | QEasingCurve::{In,Out,InOut,OutIn}Back |
+
+*/
+
+
+
+
+/*!
+ \class QEasingCurve
+ \since 4.6
+ \ingroup animation
+ \brief The QEasingCurve class provides easing curves for controlling animation.
+
+ Easing curves describe a function that controls how the speed of the interpolation
+ between 0 and 1 should be. Easing curves allow transitions from
+ one value to another to appear more natural than a simple constant speed would allow.
+ The QEasingCurve class is usually used in conjunction with the QVariantAnimation and
+ QPropertyAnimation classes but can be used on its own. It is usually used to accelerate
+ the interpolation from zero velocity (ease in) or decelerate to zero velocity (ease out).
+ Ease in and ease out can also be combined in the same easing curve.
+
+ To calculate the speed of the interpolation, the easing curve provides the function
+ valueForProgress(), where the \a progress argument specifies the progress of the
+ interpolation: 0 is the start value of the interpolation, 1 is the end value of the
+ interpolation. The returned value is the effective progress of the interpolation.
+ If the returned value is the same as the input value for all input values the easing
+ curve is a linear curve. This is the default behaviour.
+
+ For example,
+ \code
+ QEasingCurve easing(QEasingCurve::InOutQuad);
+
+ for(qreal t = 0.0; t < 1.0; t+=0.1)
+ qWarning() << "Effective progress" << t << " is
+ << easing.valueForProgress(t);
+ \endcode
+ will print the effective progress of the interpolation between 0 and 1.
+
+ When using a QPropertyAnimation, the associated easing curve will be used to control the
+ progress of the interpolation between startValue and endValue:
+ \code
+ QPropertyAnimation animation;
+ animation.setStartValue(0);
+ animation.setEndValue(1000);
+ animation.setDuration(1000);
+ animation.setEasingCurve(QEasingCurve::InOutQuad);
+ \endcode
+ */
+
+/*!
+ \enum QEasingCurve::Type
+
+ The type of easing curve.
+
+ \value Linear \inlineimage qeasingcurve-linear.png
+ \br
+ Easing curve for a linear (t) function:
+ velocity is constant.
+ \value InQuad \inlineimage qeasingcurve-inquad.png
+ \br
+ Easing curve for a quadratic (t^2) function:
+ accelerating from zero velocity.
+ \value OutQuad \inlineimage qeasingcurve-outquad.png
+ \br
+ Easing curve for a quadratic (t^2) function:
+ decelerating to zero velocity.
+ \value InOutQuad \inlineimage qeasingcurve-inoutquad.png
+ \br
+ Easing curve for a quadratic (t^2) function:
+ acceleration until halfway, then deceleration.
+ \value OutInQuad \inlineimage qeasingcurve-outinquad.png
+ \br
+ Easing curve for a quadratic (t^2) function:
+ deceleration until halfway, then acceleration.
+ \value InCubic \inlineimage qeasingcurve-incubic.png
+ \br
+ Easing curve for a cubic (t^3) function:
+ accelerating from zero velocity.
+ \value OutCubic \inlineimage qeasingcurve-outcubic.png
+ \br
+ Easing curve for a cubic (t^3) function:
+ decelerating from zero velocity.
+ \value InOutCubic \inlineimage qeasingcurve-inoutcubic.png
+ \br
+ Easing curve for a cubic (t^3) function:
+ acceleration until halfway, then deceleration.
+ \value OutInCubic \inlineimage qeasingcurve-outincubic.png
+ \br
+ Easing curve for a cubic (t^3) function:
+ deceleration until halfway, then acceleration.
+ \value InQuart \inlineimage qeasingcurve-inquart.png
+ \br
+ Easing curve for a quartic (t^4) function:
+ accelerating from zero velocity.
+ \value OutQuart \inlineimage qeasingcurve-outquart.png
+ \br
+ Easing curve for a cubic (t^4) function:
+ decelerating from zero velocity.
+ \value InOutQuart \inlineimage qeasingcurve-inoutquart.png
+ \br
+ Easing curve for a cubic (t^4) function:
+ acceleration until halfway, then deceleration.
+ \value OutInQuart \inlineimage qeasingcurve-outinquart.png
+ \br
+ Easing curve for a cubic (t^4) function:
+ deceleration until halfway, then acceleration.
+ \value InQuint \inlineimage qeasingcurve-inquint.png
+ \br
+ Easing curve for a quintic (t^5) easing
+ in: accelerating from zero velocity.
+ \value OutQuint \inlineimage qeasingcurve-outquint.png
+ \br
+ Easing curve for a cubic (t^5) function:
+ decelerating from zero velocity.
+ \value InOutQuint \inlineimage qeasingcurve-inoutquint.png
+ \br
+ Easing curve for a cubic (t^5) function:
+ acceleration until halfway, then deceleration.
+ \value OutInQuint \inlineimage qeasingcurve-outinquint.png
+ \br
+ Easing curve for a cubic (t^5) function:
+ deceleration until halfway, then acceleration.
+ \value InSine \inlineimage qeasingcurve-insine.png
+ \br
+ Easing curve for a sinusoidal (sin(t)) function:
+ accelerating from zero velocity.
+ \value OutSine \inlineimage qeasingcurve-outsine.png
+ \br
+ Easing curve for a sinusoidal (sin(t)) function:
+ decelerating from zero velocity.
+ \value InOutSine \inlineimage qeasingcurve-inoutsine.png
+ \br
+ Easing curve for a sinusoidal (sin(t)) function:
+ acceleration until halfway, then deceleration.
+ \value OutInSine \inlineimage qeasingcurve-outinsine.png
+ \br
+ Easing curve for a sinusoidal (sin(t)) function:
+ deceleration until halfway, then acceleration.
+ \value InExpo \inlineimage qeasingcurve-inexpo.png
+ \br
+ Easing curve for an exponential (2^t) function:
+ accelerating from zero velocity.
+ \value OutExpo \inlineimage qeasingcurve-outexpo.png
+ \br
+ Easing curve for an exponential (2^t) function:
+ decelerating from zero velocity.
+ \value InOutExpo \inlineimage qeasingcurve-inoutexpo.png
+ \br
+ Easing curve for an exponential (2^t) function:
+ acceleration until halfway, then deceleration.
+ \value OutInExpo \inlineimage qeasingcurve-outinexpo.png
+ \br
+ Easing curve for an exponential (2^t) function:
+ deceleration until halfway, then acceleration.
+ \value InCirc \inlineimage qeasingcurve-incirc.png
+ \br
+ Easing curve for a circular (sqrt(1-t^2)) function:
+ accelerating from zero velocity.
+ \value OutCirc \inlineimage qeasingcurve-outcirc.png
+ \br
+ Easing curve for a circular (sqrt(1-t^2)) function:
+ decelerating from zero velocity.
+ \value InOutCirc \inlineimage qeasingcurve-inoutcirc.png
+ \br
+ Easing curve for a circular (sqrt(1-t^2)) function:
+ acceleration until halfway, then deceleration.
+ \value OutInCirc \inlineimage qeasingcurve-outincirc.png
+ \br
+ Easing curve for a circular (sqrt(1-t^2)) function:
+ deceleration until halfway, then acceleration.
+ \value InElastic \inlineimage qeasingcurve-inelastic.png
+ \br
+ Easing curve for an elastic
+ (exponentially decaying sine wave) function:
+ accelerating from zero velocity. The peak amplitude
+ can be set with the \e amplitude parameter, and the
+ period of decay by the \e period parameter.
+ \value OutElastic \inlineimage qeasingcurve-outelastic.png
+ \br
+ Easing curve for an elastic
+ (exponentially decaying sine wave) function:
+ decelerating from zero velocity. The peak amplitude
+ can be set with the \e amplitude parameter, and the
+ period of decay by the \e period parameter.
+ \value InOutElastic \inlineimage qeasingcurve-inoutelastic.png
+ \br
+ Easing curve for an elastic
+ (exponentially decaying sine wave) function:
+ acceleration until halfway, then deceleration.
+ \value OutInElastic \inlineimage qeasingcurve-outinelastic.png
+ \br
+ Easing curve for an elastic
+ (exponentially decaying sine wave) function:
+ deceleration until halfway, then acceleration.
+ \value InBack \inlineimage qeasingcurve-inback.png
+ \br
+ Easing curve for a back (overshooting
+ cubic function: (s+1)*t^3 - s*t^2) easing in:
+ accelerating from zero velocity.
+ \value OutBack \inlineimage qeasingcurve-outback.png
+ \br
+ Easing curve for a back (overshooting
+ cubic function: (s+1)*t^3 - s*t^2) easing out:
+ decelerating to zero velocity.
+ \value InOutBack \inlineimage qeasingcurve-inoutback.png
+ \br
+ Easing curve for a back (overshooting
+ cubic function: (s+1)*t^3 - s*t^2) easing in/out:
+ acceleration until halfway, then deceleration.
+ \value OutInBack \inlineimage qeasingcurve-outinback.png
+ \br
+ Easing curve for a back (overshooting
+ cubic easing: (s+1)*t^3 - s*t^2) easing out/in:
+ deceleration until halfway, then acceleration.
+ \value InBounce \inlineimage qeasingcurve-inbounce.png
+ \br
+ Easing curve for a bounce (exponentially
+ decaying parabolic bounce) function: accelerating
+ from zero velocity.
+ \value OutBounce \inlineimage qeasingcurve-outbounce.png
+ \br
+ Easing curve for a bounce (exponentially
+ decaying parabolic bounce) function: decelerating
+ from zero velocity.
+ \value InOutBounce \inlineimage qeasingcurve-inoutbounce.png
+ \br
+ Easing curve for a bounce (exponentially
+ decaying parabolic bounce) function easing in/out:
+ acceleration until halfway, then deceleration.
+ \value OutInBounce \inlineimage qeasingcurve-outinbounce.png
+ \br
+ Easing curve for a bounce (exponentially
+ decaying parabolic bounce) function easing out/in:
+ deceleration until halfway, then acceleration.
+ \omitvalue InCurve
+ \omitvalue OutCurve
+ \omitvalue SineCurve
+ \omitvalue CosineCurve
+ \value Custom This is returned if the user specified a custom curve type with
+ setCustomType(). Note that you cannot call setType() with this value,
+ but type() can return it.
+ \omitvalue NCurveTypes
+*/
+
+/*!
+ \typedef QEasingCurve::EasingFunction
+
+ This is a typedef for a pointer to a function with the following
+ signature:
+
+ \snippet doc/src/snippets/code/src_corelib_tools_qeasingcurve.cpp 0
+*/
+
+#include "qeasingcurve.h"
+
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+#include <QtCore/qstring.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static bool isConfigFunction(QEasingCurve::Type type)
+{
+ return type >= QEasingCurve::InElastic
+ && type <= QEasingCurve::OutInBounce;
+}
+
+class QEasingCurveFunction
+{
+public:
+ enum Type { In, Out, InOut, OutIn };
+
+ QEasingCurveFunction(QEasingCurveFunction::Type type = In, qreal period = 0.3, qreal amplitude = 1.0,
+ qreal overshoot = 1.70158f)
+ : _t(type), _p(period), _a(amplitude), _o(overshoot)
+ { }
+ virtual ~QEasingCurveFunction() {}
+ virtual qreal value(qreal t);
+ virtual QEasingCurveFunction *copy() const;
+ bool operator==(const QEasingCurveFunction& other);
+
+ Type _t;
+ qreal _p;
+ qreal _a;
+ qreal _o;
+};
+
+qreal QEasingCurveFunction::value(qreal t)
+{
+ return t;
+}
+
+QEasingCurveFunction *QEasingCurveFunction::copy() const
+{
+ return new QEasingCurveFunction(_t, _p, _a, _o);
+}
+
+bool QEasingCurveFunction::operator==(const QEasingCurveFunction& other)
+{
+ return _t == other._t &&
+ _p == other._p &&
+ _a == other._a &&
+ _o == other._o;
+}
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "../../3rdparty/easing/easing.cpp"
+QT_END_INCLUDE_NAMESPACE
+
+class QEasingCurvePrivate
+{
+public:
+ QEasingCurvePrivate()
+ : type(QEasingCurve::Linear),
+ config(0),
+ func(&easeNone)
+ { }
+ ~QEasingCurvePrivate() { delete config; }
+ void setType_helper(QEasingCurve::Type);
+
+ QEasingCurve::Type type;
+ QEasingCurveFunction *config;
+ QEasingCurve::EasingFunction func;
+};
+
+struct ElasticEase : public QEasingCurveFunction
+{
+ ElasticEase(Type type)
+ : QEasingCurveFunction(type, qreal(0.3), qreal(1.0))
+ { }
+
+ QEasingCurveFunction *copy() const
+ {
+ ElasticEase *rv = new ElasticEase(_t);
+ rv->_p = _p;
+ rv->_a = _a;
+ return rv;
+ }
+
+ qreal value(qreal t)
+ {
+ qreal p = (_p < 0) ? 0.3f : _p;
+ qreal a = (_a < 0) ? 1.0f : _a;
+ switch(_t) {
+ case In:
+ return easeInElastic(t, a, p);
+ case Out:
+ return easeOutElastic(t, a, p);
+ case InOut:
+ return easeInOutElastic(t, a, p);
+ case OutIn:
+ return easeOutInElastic(t, a, p);
+ default:
+ return t;
+ }
+ }
+};
+
+struct BounceEase : public QEasingCurveFunction
+{
+ BounceEase(Type type)
+ : QEasingCurveFunction(type, 0.3f, 1.0f)
+ { }
+
+ QEasingCurveFunction *copy() const
+ {
+ BounceEase *rv = new BounceEase(_t);
+ rv->_a = _a;
+ return rv;
+ }
+
+ qreal value(qreal t)
+ {
+ qreal a = (_a < 0) ? 1.0f : _a;
+ switch(_t) {
+ case In:
+ return easeInBounce(t, a);
+ case Out:
+ return easeOutBounce(t, a);
+ case InOut:
+ return easeInOutBounce(t, a);
+ case OutIn:
+ return easeOutInBounce(t, a);
+ default:
+ return t;
+ }
+ }
+};
+
+struct BackEase : public QEasingCurveFunction
+{
+ BackEase(Type type)
+ : QEasingCurveFunction(type, 0.3f, 1.0f, 1.70158f)
+ { }
+
+ QEasingCurveFunction *copy() const
+ {
+ BackEase *rv = new BackEase(_t);
+ rv->_o = _o;
+ return rv;
+ }
+
+ qreal value(qreal t)
+ {
+ qreal o = (_o < 0) ? 1.70158f : _o;
+ switch(_t) {
+ case In:
+ return easeInBack(t, o);
+ case Out:
+ return easeOutBack(t, o);
+ case InOut:
+ return easeInOutBack(t, o);
+ case OutIn:
+ return easeOutInBack(t, o);
+ default:
+ return t;
+ }
+ }
+};
+
+static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve)
+{
+ switch(curve) {
+ case QEasingCurve::Linear:
+ return &easeNone;
+ case QEasingCurve::InQuad:
+ return &easeInQuad;
+ case QEasingCurve::OutQuad:
+ return &easeOutQuad;
+ case QEasingCurve::InOutQuad:
+ return &easeInOutQuad;
+ case QEasingCurve::OutInQuad:
+ return &easeOutInQuad;
+ case QEasingCurve::InCubic:
+ return &easeInCubic;
+ case QEasingCurve::OutCubic:
+ return &easeOutCubic;
+ case QEasingCurve::InOutCubic:
+ return &easeInOutCubic;
+ case QEasingCurve::OutInCubic:
+ return &easeOutInCubic;
+ case QEasingCurve::InQuart:
+ return &easeInQuart;
+ case QEasingCurve::OutQuart:
+ return &easeOutQuart;
+ case QEasingCurve::InOutQuart:
+ return &easeInOutQuart;
+ case QEasingCurve::OutInQuart:
+ return &easeOutInQuart;
+ case QEasingCurve::InQuint:
+ return &easeInQuint;
+ case QEasingCurve::OutQuint:
+ return &easeOutQuint;
+ case QEasingCurve::InOutQuint:
+ return &easeInOutQuint;
+ case QEasingCurve::OutInQuint:
+ return &easeOutInQuint;
+ case QEasingCurve::InSine:
+ return &easeInSine;
+ case QEasingCurve::OutSine:
+ return &easeOutSine;
+ case QEasingCurve::InOutSine:
+ return &easeInOutSine;
+ case QEasingCurve::OutInSine:
+ return &easeOutInSine;
+ case QEasingCurve::InExpo:
+ return &easeInExpo;
+ case QEasingCurve::OutExpo:
+ return &easeOutExpo;
+ case QEasingCurve::InOutExpo:
+ return &easeInOutExpo;
+ case QEasingCurve::OutInExpo:
+ return &easeOutInExpo;
+ case QEasingCurve::InCirc:
+ return &easeInCirc;
+ case QEasingCurve::OutCirc:
+ return &easeOutCirc;
+ case QEasingCurve::InOutCirc:
+ return &easeInOutCirc;
+ case QEasingCurve::OutInCirc:
+ return &easeOutInCirc;
+ // Internal for, compatibility with QTimeLine only ??
+ case QEasingCurve::InCurve:
+ return &easeInCurve;
+ case QEasingCurve::OutCurve:
+ return &easeOutCurve;
+ case QEasingCurve::SineCurve:
+ return &easeSineCurve;
+ case QEasingCurve::CosineCurve:
+ return &easeCosineCurve;
+ default:
+ return 0;
+ };
+}
+
+static QEasingCurveFunction *curveToFunctionObject(QEasingCurve::Type type)
+{
+ QEasingCurveFunction *curveFunc = 0;
+ switch(type) {
+ case QEasingCurve::InElastic:
+ curveFunc = new ElasticEase(ElasticEase::In);
+ break;
+ case QEasingCurve::OutElastic:
+ curveFunc = new ElasticEase(ElasticEase::Out);
+ break;
+ case QEasingCurve::InOutElastic:
+ curveFunc = new ElasticEase(ElasticEase::InOut);
+ break;
+ case QEasingCurve::OutInElastic:
+ curveFunc = new ElasticEase(ElasticEase::OutIn);
+ break;
+ case QEasingCurve::OutBounce:
+ curveFunc = new BounceEase(BounceEase::Out);
+ break;
+ case QEasingCurve::InBounce:
+ curveFunc = new BounceEase(BounceEase::In);
+ break;
+ case QEasingCurve::OutInBounce:
+ curveFunc = new BounceEase(BounceEase::OutIn);
+ break;
+ case QEasingCurve::InOutBounce:
+ curveFunc = new BounceEase(BounceEase::InOut);
+ break;
+ case QEasingCurve::InBack:
+ curveFunc = new BackEase(BackEase::In);
+ break;
+ case QEasingCurve::OutBack:
+ curveFunc = new BackEase(BackEase::Out);
+ break;
+ case QEasingCurve::InOutBack:
+ curveFunc = new BackEase(BackEase::InOut);
+ break;
+ case QEasingCurve::OutInBack:
+ curveFunc = new BackEase(BackEase::OutIn);
+ break;
+ default:
+ curveFunc = new QEasingCurveFunction(QEasingCurveFunction::In, 0.3f, 1.0f, 1.70158f); // ###
+ }
+
+ return curveFunc;
+}
+
+/*!
+ Constructs an easing curve of the given \a type.
+ */
+QEasingCurve::QEasingCurve(Type type)
+ : d_ptr(new QEasingCurvePrivate)
+{
+ setType(type);
+}
+
+/*!
+ Construct a copy of \a other.
+ */
+QEasingCurve::QEasingCurve(const QEasingCurve &other)
+: d_ptr(new QEasingCurvePrivate)
+{
+ // ### non-atomic, requires malloc on shallow copy
+ *d_ptr = *other.d_ptr;
+ if(other.d_ptr->config)
+ d_ptr->config = other.d_ptr->config->copy();
+}
+
+/*!
+ Destructor.
+ */
+
+QEasingCurve::~QEasingCurve()
+{
+ delete d_ptr;
+}
+
+/*!
+ Copy \a other.
+ */
+QEasingCurve &QEasingCurve::operator=(const QEasingCurve &other)
+{
+ // ### non-atomic, requires malloc on shallow copy
+ if (d_ptr->config) {
+ delete d_ptr->config;
+ d_ptr->config = 0;
+ }
+
+ *d_ptr = *other.d_ptr;
+ if(other.d_ptr->config)
+ d_ptr->config = other.d_ptr->config->copy();
+
+ return *this;
+}
+
+/*!
+ Compare this easing curve with \a other and returns true if they are
+ equal. It will also compare the properties of a curve.
+ */
+bool QEasingCurve::operator==(const QEasingCurve &other) const
+{
+ bool res = d_ptr->func == other.d_ptr->func
+ && d_ptr->type == other.d_ptr->type;
+ if (res && d_ptr->config && other.d_ptr->config) {
+ // catch the config content
+ res = d_ptr->config->operator==(*(other.d_ptr->config));
+ }
+ return res;
+}
+
+/*!
+ \fn bool QEasingCurve::operator!=(const QEasingCurve &other) const
+ Compare this easing curve with \a other and returns true if they are not equal.
+ It will also compare the properties of a curve.
+
+ \sa operator==()
+*/
+
+/*!
+ Returns the amplitude. This is not applicable for all curve types.
+ It is only applicable for bounce and elastic curves (curves of type()
+ QEasingCurve::InBounce, QEasingCurve::OutBounce, QEasingCurve::InOutBounce,
+ QEasingCurve::OutInBounce, QEasingCurve::InElastic, QEasingCurve::OutElastic,
+ QEasingCurve::InOutElastic or QEasingCurve::OutInElastic).
+ */
+qreal QEasingCurve::amplitude() const
+{
+ return d_ptr->config ? d_ptr->config->_a : 1.0;
+}
+
+/*!
+ Sets the amplitude to \a amplitude.
+
+ This will set the amplitude of the bounce or the amplitude of the
+ elastic "spring" effect. The higher the number, the higher the amplitude.
+ \sa amplitude()
+*/
+void QEasingCurve::setAmplitude(qreal amplitude)
+{
+ if (!d_ptr->config)
+ d_ptr->config = curveToFunctionObject(d_ptr->type);
+ d_ptr->config->_a = amplitude;
+}
+
+/*!
+ Returns the period. This is not applicable for all curve types.
+ It is only applicable if type() is QEasingCurve::InElastic, QEasingCurve::OutElastic,
+ QEasingCurve::InOutElastic or QEasingCurve::OutInElastic.
+ */
+qreal QEasingCurve::period() const
+{
+ return d_ptr->config ? d_ptr->config->_p : 0.3;
+}
+
+/*!
+ Sets the period to \a period.
+ Setting a small period value will give a high frequency of the curve. A
+ large period will give it a small frequency.
+
+ \sa period()
+*/
+void QEasingCurve::setPeriod(qreal period)
+{
+ if (!d_ptr->config)
+ d_ptr->config = curveToFunctionObject(d_ptr->type);
+ d_ptr->config->_p = period;
+}
+
+/*!
+ Returns the overshoot. This is not applicable for all curve types.
+ It is only applicable if type() is QEasingCurve::InBack, QEasingCurve::OutBack,
+ QEasingCurve::InOutBack or QEasingCurve::OutInBack.
+ */
+qreal QEasingCurve::overshoot() const
+{
+ return d_ptr->config ? d_ptr->config->_o : 1.70158f;
+}
+
+/*!
+ Sets the overshoot to \a overshoot.
+
+ 0 produces no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent.
+
+ \sa overshoot()
+*/
+void QEasingCurve::setOvershoot(qreal overshoot)
+{
+ if (!d_ptr->config)
+ d_ptr->config = curveToFunctionObject(d_ptr->type);
+ d_ptr->config->_o = overshoot;
+}
+
+/*!
+ Returns the type of the easing curve.
+*/
+QEasingCurve::Type QEasingCurve::type() const
+{
+ return d_ptr->type;
+}
+
+void QEasingCurvePrivate::setType_helper(QEasingCurve::Type newType)
+{
+ qreal amp = -1.0;
+ qreal period = -1.0;
+ qreal overshoot = -1.0;
+
+ if (config) {
+ amp = config->_a;
+ period = config->_p;
+ overshoot = config->_o;
+ delete config;
+ config = 0;
+ }
+
+ if (isConfigFunction(newType) || (amp != -1.0) || (period != -1.0) || (overshoot != -1.0)) {
+ config = curveToFunctionObject(newType);
+ if (amp != -1.0)
+ config->_a = amp;
+ if (period != -1.0)
+ config->_p = period;
+ if (overshoot != -1.0)
+ config->_o = overshoot;
+ func = 0;
+ } else if (newType != QEasingCurve::Custom) {
+ func = curveToFunc(newType);
+ }
+ Q_ASSERT((func == 0) == (config != 0));
+ type = newType;
+}
+
+/*!
+ Sets the type of the easing curve to \a type.
+*/
+void QEasingCurve::setType(Type type)
+{
+ if (d_ptr->type == type)
+ return;
+ if (type < Linear || type >= NCurveTypes - 1) {
+ qWarning("QEasingCurve: Invalid curve type %d", type);
+ return;
+ }
+
+ d_ptr->setType_helper(type);
+}
+
+/*!
+ Sets a custom easing curve that is defined by the user in the function \a func.
+ The signature of the function is qreal myEasingFunction(qreal progress),
+ where \e progress and the return value is considered to be normalized between 0 and 1.
+ (In some cases the return value can be outside that range)
+ After calling this function type() will return QEasingCurve::Custom.
+ \a func cannot be zero.
+
+ \sa customType()
+ \sa valueForProgress()
+*/
+void QEasingCurve::setCustomType(EasingFunction func)
+{
+ if (!func) {
+ qWarning("Function pointer must not be null");
+ return;
+ }
+ d_ptr->func = func;
+ d_ptr->setType_helper(Custom);
+}
+
+/*!
+ Returns the function pointer to the custom easing curve.
+ If type() does not return QEasingCurve::Custom, this function
+ will return 0.
+*/
+QEasingCurve::EasingFunction QEasingCurve::customType() const
+{
+ return d_ptr->type == Custom ? d_ptr->func : 0;
+}
+
+/*!
+ Return the effective progress for the easing curve at \a progress.
+ While \a progress must be between 0 and 1, the returned effective progress
+ can be outside those bounds. For instance, QEasingCurve::InBack will
+ return negative values in the beginning of the function.
+ */
+qreal QEasingCurve::valueForProgress(qreal progress) const
+{
+ progress = qBound<qreal>(0, progress, 1);
+ if (d_ptr->func)
+ return d_ptr->func(progress);
+ else if (d_ptr->config)
+ return d_ptr->config->value(progress);
+ else
+ return progress;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QEasingCurve &item)
+{
+ debug << "type:" << item.d_ptr->type
+ << "func:" << item.d_ptr->func;
+ if (item.d_ptr->config) {
+ debug << QString::fromAscii("period:%1").arg(item.d_ptr->config->_p, 0, 'f', 20)
+ << QString::fromAscii("amp:%1").arg(item.d_ptr->config->_a, 0, 'f', 20)
+ << QString::fromAscii("overshoot:%1").arg(item.d_ptr->config->_o, 0, 'f', 20);
+ }
+ return debug;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h
new file mode 100644
index 0000000..4f48bd4
--- /dev/null
+++ b/src/corelib/tools/qeasingcurve.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEASINGCURVE_H
+#define QEASINGCURVE_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qobjectdefs.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QEasingCurvePrivate;
+class Q_CORE_EXPORT QEasingCurve
+{
+ Q_GADGET
+ Q_ENUMS(Type)
+public:
+ enum Type {
+ Linear,
+ InQuad, OutQuad, InOutQuad, OutInQuad,
+ InCubic, OutCubic, InOutCubic, OutInCubic,
+ InQuart, OutQuart, InOutQuart, OutInQuart,
+ InQuint, OutQuint, InOutQuint, OutInQuint,
+ InSine, OutSine, InOutSine, OutInSine,
+ InExpo, OutExpo, InOutExpo, OutInExpo,
+ InCirc, OutCirc, InOutCirc, OutInCirc,
+ InElastic, OutElastic, InOutElastic, OutInElastic,
+ InBack, OutBack, InOutBack, OutInBack,
+ InBounce, OutBounce, InOutBounce, OutInBounce,
+ InCurve, OutCurve, SineCurve, CosineCurve,
+ Custom, NCurveTypes
+ };
+
+ QEasingCurve(Type type = Linear);
+ QEasingCurve(const QEasingCurve &other);
+ ~QEasingCurve();
+
+ QEasingCurve &operator=(const QEasingCurve &other);
+ bool operator==(const QEasingCurve &other) const;
+ inline bool operator!=(const QEasingCurve &other) const
+ { return !(this->operator==(other)); }
+
+ qreal amplitude() const;
+ void setAmplitude(qreal amplitude);
+
+ qreal period() const;
+ void setPeriod(qreal period);
+
+ qreal overshoot() const;
+ void setOvershoot(qreal overshoot);
+
+ Type type() const;
+ void setType(Type type);
+ typedef qreal (*EasingFunction)(qreal progress);
+ void setCustomType(EasingFunction func);
+ EasingFunction customType() const;
+
+ qreal valueForProgress(qreal progress) const;
+private:
+ QEasingCurvePrivate *d_ptr;
+ friend Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item);
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/tools/qharfbuzz.cpp b/src/corelib/tools/qharfbuzz.cpp
index 6d06b37..9a39f2f 100644
--- a/src/corelib/tools/qharfbuzz.cpp
+++ b/src/corelib/tools/qharfbuzz.cpp
@@ -39,12 +39,12 @@
**
****************************************************************************/
-#include "qharfbuzz_p.h"
-
#include "qunicodetables_p.h"
#include "qlibrary.h"
#include "qtextcodec.h"
+#include "qharfbuzz_p.h"
+
QT_USE_NAMESPACE
extern "C" {
@@ -126,6 +126,7 @@ char *HB_TextCodec_ConvertFromUnicode(void *codec, const HB_UChar16 *unicode, hb
QByteArray data = reinterpret_cast<QTextCodec *>(codec)->fromUnicode((const QChar *)unicode, length);
// ### suboptimal
char *output = (char *)malloc(data.length() + 1);
+ Q_CHECK_PTR(output);
memcpy(output, data.constData(), data.length() + 1);
if (outputLength)
*outputLength = data.length();
diff --git a/src/corelib/tools/qharfbuzz_p.h b/src/corelib/tools/qharfbuzz_p.h
index 8b877b8..06b15e8 100644
--- a/src/corelib/tools/qharfbuzz_p.h
+++ b/src/corelib/tools/qharfbuzz_p.h
@@ -53,8 +53,8 @@
#ifndef QHARFBUZZ_P_H
#define QHARFBUZZ_P_H
-#include <harfbuzz-shaper.h>
#include <QtCore/qglobal.h>
+#include <harfbuzz-shaper.h>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index 0021547..f6100fb 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -171,7 +171,9 @@ QHashData QHashData::shared_null = {
void *QHashData::allocateNode()
{
- return qMalloc(nodeSize);
+ void *ptr = qMalloc(nodeSize);
+ Q_CHECK_PTR(ptr);
+ return ptr;
}
void QHashData::freeNode(void *node)
@@ -181,6 +183,13 @@ void QHashData::freeNode(void *node)
QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *), int nodeSize)
{
+ return detach_helper( node_duplicate, 0, nodeSize );
+}
+
+QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *),
+ void (*node_delete)(Node *),
+ int nodeSize)
+{
union {
QHashData *d;
Node *e;
@@ -197,18 +206,43 @@ QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *), int
d->sharable = true;
if (numBuckets) {
- d->buckets = new Node *[numBuckets];
+ QT_TRY {
+ d->buckets = new Node *[numBuckets];
+ } QT_CATCH(...) {
+ // restore a consistent state for d
+ d->numBuckets = 0;
+ // roll back
+ d->free_helper(node_delete);
+ QT_RETHROW;
+ }
+
Node *this_e = reinterpret_cast<Node *>(this);
for (int i = 0; i < numBuckets; ++i) {
Node **nextNode = &d->buckets[i];
Node *oldNode = buckets[i];
while (oldNode != this_e) {
- Node *dup = static_cast<Node *>(allocateNode());
- node_duplicate(oldNode, dup);
- dup->h = oldNode->h;
- *nextNode = dup;
- nextNode = &dup->next;
- oldNode = oldNode->next;
+ QT_TRY {
+ Node *dup = static_cast<Node *>(allocateNode());
+
+ QT_TRY {
+ node_duplicate(oldNode, dup);
+ } QT_CATCH(...) {
+ freeNode( dup );
+ QT_RETHROW;
+ }
+
+ dup->h = oldNode->h;
+ *nextNode = dup;
+ nextNode = &dup->next;
+ oldNode = oldNode->next;
+ } QT_CATCH(...) {
+ // restore a consistent state for d
+ *nextNode = e;
+ d->numBuckets = i+1;
+ // roll back
+ d->free_helper(node_delete);
+ QT_RETHROW;
+ }
}
*nextNode = e;
}
@@ -216,6 +250,26 @@ QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *), int
return d;
}
+void QHashData::free_helper(void (*node_delete)(Node *))
+{
+ if (node_delete) {
+ Node *this_e = reinterpret_cast<Node *>(this);
+ Node **bucket = reinterpret_cast<Node **>(this->buckets);
+
+ int n = numBuckets;
+ while (n--) {
+ Node *cur = *bucket++;
+ while (cur != this_e) {
+ Node *next = cur->next;
+ node_delete(cur);
+ cur = next;
+ }
+ }
+ }
+ delete [] buckets;
+ delete this;
+}
+
QHashData::Node *QHashData::nextNode(Node *node)
{
union {
@@ -298,9 +352,10 @@ void QHashData::rehash(int hint)
Node **oldBuckets = buckets;
int oldNumBuckets = numBuckets;
+ int nb = primeForNumBits(hint);
+ buckets = new Node *[nb];
numBits = hint;
- numBuckets = primeForNumBits(hint);
- buckets = new Node *[numBuckets];
+ numBuckets = nb;
for (int i = 0; i < numBuckets; ++i)
buckets[i] = e;
@@ -327,8 +382,7 @@ void QHashData::rehash(int hint)
void QHashData::destroyAndFree()
{
- delete [] buckets;
- delete this;
+ free_helper(0);
}
#ifdef QT_QHASH_DEBUG
@@ -485,7 +539,7 @@ void QHashData::checkSanity()
\ingroup tools
\ingroup shared
- \mainclass
+
\reentrant
QHash\<Key, T\> is one of Qt's generic \l{container classes}. It
@@ -1618,7 +1672,7 @@ void QHashData::checkSanity()
\ingroup tools
\ingroup shared
- \mainclass
+
\reentrant
QMultiHash\<Key, T\> is one of Qt's generic \l{container classes}.
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index ab72304..73ebb77 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -129,12 +129,15 @@ struct Q_CORE_EXPORT QHashData
void *allocateNode();
void freeNode(void *node);
- QHashData *detach_helper(void (*node_duplicate)(Node *, void *), int nodeSize);
+ QHashData *detach_helper(void (*node_duplicate)(Node *, void *), int nodeSize); // ### Qt5 remove me
+ QHashData *detach_helper(void (*node_duplicate)(Node *, void *), void (*node_delete)(Node *),
+ int nodeSize);
void mightGrow();
bool willGrow();
void hasShrunk();
void rehash(int hint);
- void destroyAndFree();
+ void free_helper(void (*node_delete)(Node *));
+ void destroyAndFree(); // ### Qt5 remove me
Node *firstNode();
#ifdef QT_QHASH_DEBUG
void dump();
@@ -147,10 +150,10 @@ struct Q_CORE_EXPORT QHashData
};
inline void QHashData::mightGrow() // ### Qt 5: eliminate
-{
+{
if (size >= numBuckets)
rehash(numBits + 1);
-}
+}
inline bool QHashData::willGrow()
{
@@ -164,8 +167,13 @@ inline bool QHashData::willGrow()
inline void QHashData::hasShrunk()
{
- if (size <= (numBuckets >> 3) && numBits > userNumBits)
- rehash(qMax(int(numBits) - 2, int(userNumBits)));
+ if (size <= (numBuckets >> 3) && numBits > userNumBits) {
+ QT_TRY {
+ rehash(qMax(int(numBits) - 2, int(userNumBits)));
+ } QT_CATCH(const std::bad_alloc &) {
+ // ignore bad allocs - shrinking shouldn't throw. rehash is exception safe.
+ }
+ }
}
inline QHashData::Node *QHashData::firstNode()
@@ -476,21 +484,30 @@ private:
Node **findNode(const Key &key, uint *hp = 0) const;
Node *createNode(uint h, const Key &key, const T &value, Node **nextNode);
void deleteNode(Node *node);
+ static void deleteNode(QHashData::Node *node);
static void duplicateNode(QHashData::Node *originalNode, void *newNode);
};
+
template <class Key, class T>
Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode(Node *node)
{
+ deleteNode(reinterpret_cast<QHashData::Node*>(node));
+}
+
+
+template <class Key, class T>
+Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode(QHashData::Node *node)
+{
#ifdef Q_CC_BOR
- node->~QHashNode<Key, T>();
+ concrete(node)->~QHashNode<Key, T>();
#elif defined(QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION)
- node->~QHashNode();
+ concrete(node)->~QHashNode();
#else
- node->~Node();
+ concrete(node)->~Node();
#endif
- d->freeNode(node);
+ qFree(node);
}
template <class Key, class T>
@@ -538,18 +555,7 @@ Q_INLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::unite(const QHash<Key, T> &other
template <class Key, class T>
Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::freeData(QHashData *x)
{
- Node *e_for_x = reinterpret_cast<Node *>(x);
- Node **bucket = reinterpret_cast<Node **>(x->buckets);
- int n = x->numBuckets;
- while (n--) {
- Node *cur = *bucket++;
- while (cur != e_for_x) {
- Node *next = cur->next;
- deleteNode(cur);
- cur = next;
- }
- }
- x->destroyAndFree();
+ x->free_helper(deleteNode);
}
template <class Key, class T>
@@ -561,7 +567,7 @@ Q_INLINE_TEMPLATE void QHash<Key, T>::clear()
template <class Key, class T>
Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::detach_helper()
{
- QHashData *x = d->detach_helper(duplicateNode,
+ QHashData *x = d->detach_helper(duplicateNode, deleteNode,
QTypeInfo<T>::isDummy ? sizeof(DummyNode) : sizeof(Node));
if (!d->ref.deref())
freeData(d);
@@ -760,6 +766,8 @@ Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insertMulti(co
template <class Key, class T>
Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::remove(const Key &akey)
{
+ if (isEmpty()) // prevents detaching shared null
+ return 0;
detach();
int oldSize = d->size;
@@ -781,6 +789,8 @@ Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::remove(const Key &akey)
template <class Key, class T>
Q_OUTOFLINE_TEMPLATE T QHash<Key, T>::take(const Key &akey)
{
+ if (isEmpty()) // prevents detaching shared null
+ return T();
detach();
Node **node = findNode(akey);
@@ -911,7 +921,8 @@ public:
inline QMultiHash operator+(const QMultiHash &other) const
{ QMultiHash result = *this; result += other; return result; }
-#ifndef Q_NO_USING_KEYWORD
+#if !defined(Q_NO_USING_KEYWORD) && !defined(Q_CC_RVCT)
+ // RVCT compiler doesn't handle using-keyword right when used functions are overloaded in child class
using QHash<Key, T>::contains;
using QHash<Key, T>::remove;
using QHash<Key, T>::count;
@@ -981,7 +992,12 @@ Q_INLINE_TEMPLATE int QMultiHash<Key, T>::remove(const Key &key, const T &value)
typename QHash<Key, T>::iterator end(QHash<Key, T>::end());
while (i != end && i.key() == key) {
if (i.value() == value) {
+#if defined(Q_CC_RVCT)
+ // RVCT has problems with scoping, apparently.
+ i = QHash<Key, T>::erase(i);
+#else
i = erase(i);
+#endif
++n;
} else {
++i;
diff --git a/src/corelib/tools/qiterator.qdoc b/src/corelib/tools/qiterator.qdoc
new file mode 100644
index 0000000..adb6b98
--- /dev/null
+++ b/src/corelib/tools/qiterator.qdoc
@@ -0,0 +1,1431 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QListIterator
+ \inmodule QtCore
+
+ \brief The QListIterator class provides a Java-style const iterator for QList and QQueue.
+
+ QList has both \l{Java-style iterators} and \l{STL-style
+ iterators}. The Java-style iterators are more high-level and
+ easier to use than the STL-style iterators; on the other hand,
+ they are slightly less efficient.
+
+ An alternative to using iterators is to use index positions. Most
+ QList member functions take an index as their first parameter,
+ making it possible to access, modify, and remove items without
+ using iterators.
+
+ QListIterator\<T\> allows you to iterate over a QList\<T\> (or a
+ QQueue\<T\>). If you want to modify the list as you iterate over
+ it, use QMutableListIterator\<T\> instead.
+
+ The QListIterator constructor takes a QList as argument. After
+ construction, the iterator is located at the very beginning of
+ the list (before the first item). Here's how to iterate over all
+ the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 0
+
+ The next() function returns the next item in the list and
+ advances the iterator. Unlike STL-style iterators, Java-style
+ iterators point \e between items rather than directly \e at
+ items. The first call to next() advances the iterator to the
+ position between the first and second item, and returns the first
+ item; the second call to next() advances the iterator to the
+ position between the second and third item, and returns the second
+ item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 1
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop.
+
+ Multiple iterators can be used on the same list. If the list is
+ modified while a QListIterator is active, the QListIterator will
+ continue iterating over the original list, ignoring the modified
+ copy.
+
+ \sa QMutableListIterator, QList::const_iterator
+*/
+
+/*!
+ \class QLinkedListIterator
+ \inmodule QtCore
+
+ \brief The QLinkedListIterator class provides a Java-style const iterator for QLinkedList.
+
+ QLinkedList has both \l{Java-style iterators} and
+ \l{STL-style iterators}. The Java-style iterators are more
+ high-level and easier to use than the STL-style iterators; on the
+ other hand, they are slightly less efficient.
+
+ QLinkedListIterator\<T\> allows you to iterate over a
+ QLinkedList\<T\>. If you want to modify the list as you iterate
+ over it, use QMutableLinkedListIterator\<T\> instead.
+
+ The QLinkedListIterator constructor takes a QLinkedList as
+ argument. After construction, the iterator is located at the very
+ beginning of the list (before the first item). Here's how to
+ iterate over all the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 2
+
+ The next() function returns the next item in the list and
+ advances the iterator. Unlike STL-style iterators, Java-style
+ iterators point \e between items rather than directly \e at
+ items. The first call to next() advances the iterator to the
+ position between the first and second item, and returns the first
+ item; the second call to next() advances the iterator to the
+ position between the second and third item, and returns the second
+ item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 3
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop.
+
+ Multiple iterators can be used on the same list. If the list is
+ modified while a QLinkedListIterator is active, the
+ QLinkedListIterator will continue iterating over the original
+ list, ignoring the modified copy.
+
+ \sa QMutableLinkedListIterator, QLinkedList::const_iterator
+*/
+
+/*!
+ \class QVectorIterator
+ \inmodule QtCore
+ \brief The QVectorIterator class provides a Java-style const iterator for QVector and QStack.
+
+ QVector has both \l{Java-style iterators} and \l{STL-style
+ iterators}. The Java-style iterators are more high-level and
+ easier to use than the STL-style iterators; on the other hand,
+ they are slightly less efficient.
+
+ An alternative to using iterators is to use index positions. Most
+ QVector member functions take an index as their first parameter,
+ making it possible to access, insert, and remove items without
+ using iterators.
+
+ QVectorIterator\<T\> allows you to iterate over a QVector\<T\>
+ (or a QStack\<T\>). If you want to modify the vector as you
+ iterate over it, use QMutableVectorIterator\<T\> instead.
+
+ The QVectorIterator constructor takes a QVector as argument.
+ After construction, the iterator is located at the very beginning
+ of the vector (before the first item). Here's how to iterate over
+ all the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 4
+
+ The next() function returns the next item in the vector and
+ advances the iterator. Unlike STL-style iterators, Java-style
+ iterators point \e between items rather than directly \e at
+ items. The first call to next() advances the iterator to the
+ position between the first and second item, and returns the first
+ item; the second call to next() advances the iterator to the
+ position between the second and third item, returning the second
+ item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 5
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop.
+
+ Multiple iterators can be used on the same vector. If the vector
+ is modified while a QVectorIterator is active, the QVectorIterator
+ will continue iterating over the original vector, ignoring the
+ modified copy.
+
+ \sa QMutableVectorIterator, QVector::const_iterator
+*/
+
+/*!
+ \class QSetIterator
+ \inmodule QtCore
+ \brief The QSetIterator class provides a Java-style const iterator for QSet.
+
+ QSet supports both \l{Java-style iterators} and \l{STL-style
+ iterators}. The Java-style iterators are more high-level and
+ easier to use than the STL-style iterators; on the other hand,
+ they are slightly less efficient.
+
+ QSetIterator\<T\> allows you to iterate over a QSet\<T\>. If you
+ want to modify the set as you iterate over it, use
+ QMutableSetIterator\<T\> instead.
+
+ The constructor takes a QSet as argument. After construction, the
+ iterator is located at the very beginning of the set (before
+ the first item). Here's how to iterate over all the elements
+ sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 6
+
+ The next() function returns the next item in the set and
+ advances the iterator. Unlike STL-style iterators, Java-style
+ iterators point \e between items rather than directly \e at
+ items. The first call to next() advances the iterator to the
+ position between the first and second item, and returns the first
+ item; the second call to next() advances the iterator to the
+ position between the second and third item, returning the second
+ item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 7
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop.
+
+ Multiple iterators can be used on the same set. If the set
+ is modified while a QSetIterator is active, the QSetIterator
+ will continue iterating over the original set, ignoring the
+ modified copy.
+
+ \sa QMutableSetIterator, QSet::const_iterator
+*/
+
+/*!
+ \class QMutableListIterator
+ \inmodule QtCore
+
+ \brief The QMutableListIterator class provides a Java-style non-const iterator for QList and QQueue.
+
+ QList has both \l{Java-style iterators} and \l{STL-style
+ iterators}. The Java-style iterators are more high-level and
+ easier to use than the STL-style iterators; on the other hand,
+ they are slightly less efficient.
+
+ An alternative to using iterators is to use index positions. Most
+ QList member functions take an index as their first parameter,
+ making it possible to access, insert, and remove items without
+ using iterators.
+
+ QMutableListIterator\<T\> allows you to iterate over a QList\<T\>
+ (or a QQueue\<T\>) and modify the list. If you don't want to
+ modify the list (or have a const QList), use the slightly faster
+ QListIterator\<T\> instead.
+
+ The QMutableListIterator constructor takes a QList as argument.
+ After construction, the iterator is located at the very beginning
+ of the list (before the first item). Here's how to iterate over
+ all the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 8
+
+ The next() function returns the next item in the list and
+ advances the iterator. Unlike STL-style iterators, Java-style
+ iterators point \e between items rather than directly \e at
+ items. The first call to next() advances the iterator to the
+ position between the first and second item, and returns the first
+ item; the second call to next() advances the iterator to the
+ position between the second and third item, returning the second
+ item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 9
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop.
+
+ If you want to remove items as you iterate over the list, use
+ remove(). If you want to modify the value of an item, use
+ setValue(). If you want to insert a new item in the list, use
+ insert().
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 10
+
+ The example traverses a list, replacing negative numbers with
+ their absolute values, and eliminating zeroes.
+
+ Only one mutable iterator can be active on a given list at any
+ time. Furthermore, no changes should be done directly to the list
+ while the iterator is active (as opposed to through the
+ iterator), since this could invalidate the iterator and lead to
+ undefined behavior.
+
+ \sa QListIterator, QList::iterator
+*/
+
+/*!
+ \class QMutableLinkedListIterator
+ \inmodule QtCore
+
+ \brief The QMutableLinkedListIterator class provides a Java-style non-const iterator for QLinkedList.
+
+ QLinkedList has both \l{Java-style iterators} and
+ \l{STL-style iterators}. The Java-style iterators are more
+ high-level and easier to use than the STL-style iterators; on the
+ other hand, they are slightly less efficient.
+
+ QMutableLinkedListIterator\<T\> allows you to iterate over a
+ QLinkedList\<T\> and modify the list. If you don't want to modify
+ the list (or have a const QLinkedList), use the slightly faster
+ QLinkedListIterator\<T\> instead.
+
+ The QMutableLinkedListIterator constructor takes a QLinkedList as
+ argument. After construction, the iterator is located at the very
+ beginning of the list (before the first item). Here's how to
+ iterate over all the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 11
+
+ The next() function returns the next item in the list and
+ advances the iterator. Unlike STL-style iterators, Java-style
+ iterators point \e between items rather than directly \e at
+ items. The first call to next() advances the iterator to the
+ position between the first and second item, and returns the first
+ item; the second call to next() advances the iterator to the
+ position between the second and third item, returning the second
+ item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 12
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop.
+
+ If you want to remove items as you iterate over the list, use
+ remove(). If you want to modify the value of an item, use
+ setValue(). If you want to insert a new item in the list, use
+ insert().
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 13
+
+ The example traverses a list, replacing negative numbers with
+ their absolute values, and eliminating zeroes.
+
+ Only one mutable iterator can be active on a given list at any
+ time. Furthermore, no changes should be done directly to the list
+ while the iterator is active (as opposed to through the
+ iterator), since this could invalidate the iterator and lead to
+ undefined behavior.
+
+ \sa QLinkedListIterator, QLinkedList::iterator
+*/
+
+/*!
+ \class QMutableVectorIterator
+ \inmodule QtCore
+
+ \brief The QMutableVectorIterator class provides a Java-style non-const iterator for QVector and QStack.
+
+ QVector has both \l{Java-style iterators} and \l{STL-style
+ iterators}. The Java-style iterators are more high-level and
+ easier to use than the STL-style iterators; on the other hand,
+ they are slightly less efficient.
+
+ An alternative to using iterators is to use index positions. Most
+ QVector member functions take an index as their first parameter,
+ making it possible to access, insert, and remove items without
+ using iterators.
+
+ QMutableVectorIterator\<T\> allows you to iterate over a
+ QVector\<T\> and modify the vector. If you don't want to modify
+ the vector (or have a const QVector), use the slightly faster
+ QVectorIterator\<T\> instead.
+
+ The QMutableVectorIterator constructor takes a QVector as
+ argument. After construction, the iterator is located at the very
+ beginning of the list (before the first item). Here's how to
+ iterate over all the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 14
+
+ The next() function returns the next item in the vector and
+ advances the iterator. Unlike STL-style iterators, Java-style
+ iterators point \e between items rather than directly \e at
+ items. The first call to next() advances the iterator to the
+ position between the first and second item, and returns the first
+ item; the second call to next() advances the iterator to the
+ position between the second and third item, returning the second
+ item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 15
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop.
+
+ If you want to remove items as you iterate over the vector, use
+ remove(). If you want to modify the value of an item, use
+ setValue(). If you want to insert a new item in the vector, use
+ insert().
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 16
+
+ The example traverses a vector, replacing negative numbers with
+ their absolute values, and eliminating zeroes.
+
+ Only one mutable iterator can be active on a given vector at any
+ time. Furthermore, no changes should be done directly to the
+ vector while the iterator is active (as opposed to through the
+ iterator), since this could invalidate the iterator and lead to
+ undefined behavior.
+
+ \sa QVectorIterator, QVector::iterator
+*/
+
+/*!
+ \class QMutableSetIterator
+ \inmodule QtCore
+ \since 4.2
+
+ \brief The QMutableSetIterator class provides a Java-style non-const iterator for QSet.
+
+ QSet has both \l{Java-style iterators} and \l{STL-style
+ iterators}. The Java-style iterators are more high-level and
+ easier to use than the STL-style iterators; on the other hand,
+ they are slightly less efficient.
+
+ QMutableSetIterator\<T\> allows you to iterate over a QSet\<T\>
+ and remove items from the set as you iterate. If you don't want
+ to modify the set (or have a const QSet), use the slightly faster
+ QSetIterator\<T\> instead.
+
+ The QMutableSetIterator constructor takes a QSet as argument.
+ After construction, the iterator is located at the very beginning
+ of the set (before the first item). Here's how to iterate over
+ all the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 17
+
+ The next() function returns the next item in the set and
+ advances the iterator. Unlike STL-style iterators, Java-style
+ iterators point \e between items rather than directly \e at
+ items. The first call to next() advances the iterator to the
+ position between the first and second item, and returns the first
+ item; the second call to next() advances the iterator to the
+ position between the second and third item, returning the second
+ item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 18
+
+ If you want to remove items as you iterate over the set, use
+ remove().
+
+ Only one mutable iterator can be active on a given set at any
+ time. Furthermore, no changes should be done directly to the set
+ while the iterator is active (as opposed to through the
+ iterator), since this could invalidate the iterator and lead to
+ undefined behavior.
+
+ \sa QSetIterator, QSet::iterator
+*/
+
+/*!
+ \fn QListIterator::QListIterator(const QList<T> &list)
+ \fn QLinkedListIterator::QLinkedListIterator(const QLinkedList<T> &list)
+ \fn QMutableListIterator::QMutableListIterator(QList<T> &list)
+ \fn QMutableLinkedListIterator::QMutableLinkedListIterator(QLinkedList<T> &list)
+
+ Constructs an iterator for traversing \a list. The iterator is
+ set to be at the front of the list (before the first item).
+
+ \sa operator=()
+*/
+
+/*!
+ \fn QVectorIterator::QVectorIterator(const QVector<T> &vector)
+ \fn QMutableVectorIterator::QMutableVectorIterator(QVector<T> &vector)
+
+ Constructs an iterator for traversing \a vector. The iterator is
+ set to be at the front of the vector (before the first item).
+
+ \sa operator=()
+*/
+
+/*!
+ \fn QSetIterator::QSetIterator(const QSet<T> &set)
+ \fn QMutableSetIterator::QMutableSetIterator(QSet<T> &set)
+
+ Constructs an iterator for traversing \a set. The iterator is
+ set to be at the front of the set (before the first item).
+
+ \sa operator=()
+*/
+
+/*!
+ \fn QMutableListIterator::~QMutableListIterator()
+ \fn QMutableLinkedListIterator::~QMutableLinkedListIterator()
+ \fn QMutableVectorIterator::~QMutableVectorIterator()
+ \fn QMutableSetIterator::~QMutableSetIterator()
+
+ Destroys the iterator.
+
+ \sa operator=()
+*/
+
+/*! \fn QMutableListIterator &QMutableListIterator::operator=(QList<T> &list)
+ \fn QMutableLinkedListIterator &QMutableLinkedListIterator::operator=(QLinkedList<T> &list)
+ \fn QListIterator &QListIterator::operator=(const QList<T> &list)
+ \fn QLinkedListIterator &QLinkedListIterator::operator=(const QLinkedList<T> &list)
+
+ Makes the iterator operate on \a list. The iterator is set to be
+ at the front of the list (before the first item).
+
+ \sa toFront(), toBack()
+*/
+
+/*! \fn QVectorIterator &QVectorIterator::operator=(const QVector<T> &vector)
+ \fn QMutableVectorIterator &QMutableVectorIterator::operator=(QVector<T> &vector)
+
+ Makes the iterator operate on \a vector. The iterator is set to be
+ at the front of the vector (before the first item).
+
+ \sa toFront(), toBack()
+*/
+
+/*! \fn QSetIterator &QSetIterator::operator=(const QSet<T> &set)
+ \fn QMutableSetIterator &QMutableSetIterator::operator=(QSet<T> &set)
+
+ Makes the iterator operate on \a set. The iterator is set to be
+ at the front of the set (before the first item).
+
+ \sa toFront(), toBack()
+*/
+
+/*! \fn void QListIterator::toFront()
+ \fn void QLinkedListIterator::toFront()
+ \fn void QVectorIterator::toFront()
+ \fn void QSetIterator::toFront()
+ \fn void QMutableListIterator::toFront()
+ \fn void QMutableLinkedListIterator::toFront()
+ \fn void QMutableVectorIterator::toFront()
+ \fn void QMutableSetIterator::toFront()
+
+ Moves the iterator to the front of the container (before the
+ first item).
+
+ \sa toBack(), next()
+*/
+
+/*! \fn void QListIterator::toBack()
+ \fn void QLinkedListIterator::toBack()
+ \fn void QVectorIterator::toBack()
+ \fn void QSetIterator::toBack()
+ \fn void QMutableListIterator::toBack()
+ \fn void QMutableLinkedListIterator::toBack()
+ \fn void QMutableVectorIterator::toBack()
+ \fn void QMutableSetIterator::toBack()
+
+ Moves the iterator to the back of the container (after the last
+ item).
+
+ \sa toFront(), previous()
+*/
+
+/*! \fn bool QListIterator::hasNext() const
+ \fn bool QLinkedListIterator::hasNext() const
+ \fn bool QVectorIterator::hasNext() const
+ \fn bool QSetIterator::hasNext() const
+ \fn bool QMutableListIterator::hasNext() const
+ \fn bool QMutableLinkedListIterator::hasNext() const
+ \fn bool QMutableVectorIterator::hasNext() const
+ \fn bool QMutableSetIterator::hasNext() const
+
+ Returns true if there is at least one item ahead of the iterator,
+ i.e. the iterator is \e not at the back of the container;
+ otherwise returns false.
+
+ \sa hasPrevious(), next()
+*/
+
+/*! \fn const T &QListIterator::next()
+ \fn const T &QLinkedListIterator::next()
+ \fn const T &QVectorIterator::next()
+ \fn const T &QSetIterator::next()
+ \fn const T &QMutableSetIterator::next()
+
+ Returns the next item and advances the iterator by one position.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), peekNext(), previous()
+*/
+
+/*! \fn T &QMutableListIterator::next()
+ \fn T &QMutableLinkedListIterator::next()
+ \fn T &QMutableVectorIterator::next()
+
+ Returns a reference to the next item, and advances the iterator
+ by one position.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), peekNext(), previous()
+*/
+
+/*! \fn const T &QListIterator::peekNext() const
+ \fn const T &QLinkedListIterator::peekNext() const
+ \fn const T &QVectorIterator::peekNext() const
+ \fn const T &QSetIterator::peekNext() const
+ \fn const T &QMutableSetIterator::peekNext() const
+
+ Returns the next item without moving the iterator.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), next(), peekPrevious()
+*/
+
+/*! \fn T &QMutableListIterator::peekNext() const
+ \fn T &QMutableLinkedListIterator::peekNext() const
+ \fn T &QMutableVectorIterator::peekNext() const
+
+ Returns a reference to the next item, without moving the iterator.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), next(), peekPrevious()
+*/
+
+/*! \fn bool QListIterator::hasPrevious() const
+ \fn bool QLinkedListIterator::hasPrevious() const
+ \fn bool QVectorIterator::hasPrevious() const
+ \fn bool QSetIterator::hasPrevious() const
+ \fn bool QMutableListIterator::hasPrevious() const
+ \fn bool QMutableLinkedListIterator::hasPrevious() const
+ \fn bool QMutableVectorIterator::hasPrevious() const
+ \fn bool QMutableSetIterator::hasPrevious() const
+
+ Returns true if there is at least one item behind the iterator,
+ i.e. the iterator is \e not at the front of the container;
+ otherwise returns false.
+
+ \sa hasNext(), previous()
+*/
+
+/*! \fn const T &QListIterator::previous()
+ \fn const T &QLinkedListIterator::previous()
+ \fn const T &QVectorIterator::previous()
+ \fn const T &QSetIterator::previous()
+ \fn const T &QMutableSetIterator::previous()
+
+ Returns the previous item and moves the iterator back by one
+ position.
+
+ Calling this function on an iterator located at the front of the
+ container leads to undefined results.
+
+ \sa hasPrevious(), peekPrevious(), next()
+*/
+
+/*! \fn T &QMutableListIterator::previous()
+ \fn T &QMutableLinkedListIterator::previous()
+ \fn T &QMutableVectorIterator::previous()
+
+ Returns a reference to the previous item and moves the iterator
+ back by one position.
+
+ Calling this function on an iterator located at the front of the
+ container leads to undefined results.
+
+ \sa hasPrevious(), peekPrevious(), next()
+*/
+
+/*! \fn const T &QListIterator::peekPrevious() const
+ \fn const T &QLinkedListIterator::peekPrevious() const
+ \fn const T &QVectorIterator::peekPrevious() const
+ \fn const T &QSetIterator::peekPrevious() const
+ \fn const T &QMutableSetIterator::peekPrevious() const
+
+ Returns the previous item without moving the iterator.
+
+ Calling this function on an iterator located at the front of the
+ container leads to undefined results.
+
+ \sa hasPrevious(), previous(), peekNext()
+*/
+
+/*! \fn T &QMutableListIterator::peekPrevious() const
+ \fn T &QMutableLinkedListIterator::peekPrevious() const
+ \fn T &QMutableVectorIterator::peekPrevious() const
+
+ Returns a reference to the previous item, without moving the iterator.
+
+ Calling this function on an iterator located at the front of the
+ container leads to undefined results.
+
+ \sa hasPrevious(), previous(), peekNext()
+*/
+
+/*! \fn bool QListIterator::findNext(const T &value)
+ \fn bool QLinkedListIterator::findNext(const T &value)
+ \fn bool QVectorIterator::findNext(const T &value)
+ \fn bool QSetIterator::findNext(const T &value)
+ \fn bool QMutableListIterator::findNext(const T &value)
+ \fn bool QMutableLinkedListIterator::findNext(const T &value)
+ \fn bool QMutableVectorIterator::findNext(const T &value)
+ \fn bool QMutableSetIterator::findNext(const T &value)
+
+ Searches for \a value starting from the current iterator position
+ forward. Returns true if \a value is found; otherwise returns false.
+
+ After the call, if \a value was found, the iterator is positioned
+ just after the matching item; otherwise, the iterator is
+ positioned at the back of the container.
+
+ \sa findPrevious()
+*/
+
+/*! \fn bool QListIterator::findPrevious(const T &value)
+ \fn bool QLinkedListIterator::findPrevious(const T &value)
+ \fn bool QVectorIterator::findPrevious(const T &value)
+ \fn bool QSetIterator::findPrevious(const T &value)
+ \fn bool QMutableListIterator::findPrevious(const T &value)
+ \fn bool QMutableLinkedListIterator::findPrevious(const T &value)
+ \fn bool QMutableVectorIterator::findPrevious(const T &value)
+ \fn bool QMutableSetIterator::findPrevious(const T &value)
+
+ Searches for \a value starting from the current iterator position
+ backward. Returns true if \a value is found; otherwise returns
+ false.
+
+ After the call, if \a value was found, the iterator is positioned
+ just before the matching item; otherwise, the iterator is
+ positioned at the front of the container.
+
+ \sa findNext()
+*/
+
+/*! \fn void QMutableListIterator::remove()
+
+ Removes the last item that was jumped over using one of the
+ traversal functions (next(), previous(), findNext(), findPrevious()).
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 19
+
+ \sa insert(), setValue()
+*/
+
+/*! \fn void QMutableLinkedListIterator::remove()
+
+ Removes the last item that was jumped over using one of the
+ traversal functions (next(), previous(), findNext(), findPrevious()).
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 20
+
+ \sa insert(), setValue()
+*/
+
+/*! \fn void QMutableVectorIterator::remove()
+
+ Removes the last item that was jumped over using one of the
+ traversal functions (next(), previous(), findNext(), findPrevious()).
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 21
+
+ \sa insert(), setValue()
+*/
+
+/*! \fn void QMutableSetIterator::remove()
+
+ Removes the last item that was jumped over using one of the
+ traversal functions (next(), previous(), findNext(), findPrevious()).
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 22
+
+ \sa value()
+*/
+
+/*! \fn void QMutableListIterator::setValue(const T &value) const
+
+ Replaces the value of the last item that was jumped over using
+ one of the traversal functions with \a value.
+
+ The traversal functions are next(), previous(), findNext(), and
+ findPrevious().
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 23
+
+ \sa value(), remove(), insert()
+*/
+
+/*! \fn void QMutableLinkedListIterator::setValue(const T &value) const
+
+ Replaces the value of the last item that was jumped over using
+ one of the traversal functions with \a value.
+
+ The traversal functions are next(), previous(), findNext(), and
+ findPrevious().
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 24
+
+ \sa value(), remove(), insert()
+*/
+
+/*! \fn void QMutableVectorIterator::setValue(const T &value) const
+
+ Replaces the value of the last item that was jumped over using
+ one of the traversal functions with \a value.
+
+ The traversal functions are next(), previous(), findNext(), and
+ findPrevious().
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 25
+
+ \sa value(), remove(), insert()
+*/
+
+/*! \fn const T &QMutableListIterator::value() const
+ \fn const T &QMutableLinkedListIterator::value() const
+ \fn const T &QMutableVectorIterator::value() const
+ \fn const T &QMutableSetIterator::value() const
+
+ Returns the value of the last item that was jumped over using one
+ of the traversal functions (next(), previous(), findNext(),
+ findPrevious()).
+
+ After a call to next() or findNext(), value() is equivalent to
+ peekPrevious(). After a call to previous() or findPrevious(), value() is
+ equivalent to peekNext().
+*/
+
+/*!
+ \fn T &QMutableListIterator::value()
+ \fn T &QMutableLinkedListIterator::value()
+ \fn T &QMutableVectorIterator::value()
+ \overload
+
+ Returns a non-const reference to the value of the last item that
+ was jumped over using one of the traversal functions.
+*/
+
+/*! \fn void QMutableListIterator::insert(const T &value)
+ \fn void QMutableLinkedListIterator::insert(const T &value)
+ \fn void QMutableVectorIterator::insert(const T &value)
+
+ Inserts \a value at the current iterator position. After the
+ call, the iterator is located just after the inserted item.
+
+ \sa remove(), setValue()
+*/
+
+/*!
+ \class QMapIterator
+ \inmodule QtCore
+
+ \brief The QMapIterator class provides a Java-style const iterator for QMap and QMultiMap.
+
+ QMap has both \l{Java-style iterators} and \l{STL-style
+ iterators}. The Java-style iterators are more high-level and
+ easier to use than the STL-style iterators; on the other hand,
+ they are slightly less efficient.
+
+ QMapIterator\<Key, T\> allows you to iterate over a QMap (or a
+ QMultiMap). If you want to modify the map as you iterate over
+ it, use QMutableMapIterator instead.
+
+ The QMapIterator constructor takes a QMap as argument. After
+ construction, the iterator is located at the very beginning of
+ the map (before the first item). Here's how to iterate over all
+ the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 26
+
+ The next() function returns the next item in the map and
+ advances the iterator. The key() and value() functions return the
+ key and value of the last item that was jumped over.
+
+ Unlike STL-style iterators, Java-style iterators point \e between
+ items rather than directly \e at items. The first call to next()
+ advances the iterator to the position between the first and
+ second item, and returns the first item; the second call to
+ next() advances the iterator to the position between the second
+ and third item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 27
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop. For example:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 28
+
+ Multiple iterators can be used on the same map. If the map is
+ modified while a QMapIterator is active, the QMapIterator will
+ continue iterating over the original map, ignoring the modified
+ copy.
+
+ \sa QMutableMapIterator, QMap::const_iterator
+*/
+
+/*!
+ \class QHashIterator
+ \inmodule QtCore
+
+ \brief The QHashIterator class provides a Java-style const iterator for QHash and QMultiHash.
+
+ QHash has both \l{Java-style iterators} and \l{STL-style
+ iterators}. The Java-style iterators are more high-level and
+ easier to use than the STL-style iterators; on the other hand,
+ they are slightly less efficient.
+
+ QHashIterator\<Key, T\> allows you to iterate over a QHash (or a
+ QMultiHash). If you want to modify the hash as you iterate over
+ it, use QMutableHashIterator instead.
+
+ The QHashIterator constructor takes a QHash as argument. After
+ construction, the iterator is located at the very beginning of
+ the hash (before the first item). Here's how to iterate over all
+ the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 29
+
+ The next() function returns the next item in the hash and
+ advances the iterator. The key() and value() functions return the
+ key and value of the last item that was jumped over.
+
+ Unlike STL-style iterators, Java-style iterators point \e between
+ items rather than directly \e at items. The first call to next()
+ advances the iterator to the position between the first and
+ second item, and returns the first item; the second call to
+ next() advances the iterator to the position between the second
+ and third item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 30
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop. For example:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 31
+
+ Multiple iterators can be used on the same hash. If the hash is
+ modified while a QHashIterator is active, the QHashIterator will
+ continue iterating over the original hash, ignoring the modified
+ copy.
+
+ \sa QMutableHashIterator, QHash::const_iterator
+*/
+
+/*!
+ \class QMutableMapIterator
+ \inmodule QtCore
+
+ \brief The QMutableMapIterator class provides a Java-style non-const iterator for QMap and QMultiMap.
+
+ QMap has both \l{Java-style iterators} and \l{STL-style
+ iterators}. The Java-style iterators are more high-level and
+ easier to use than the STL-style iterators; on the other hand,
+ they are slightly less efficient.
+
+ QMutableMapIterator\<Key, T\> allows you to iterate over a QMap
+ (or a QMultiMap) and modify the map. If you don't want to modify
+ the map (or have a const QMap), use the slightly faster
+ QMapIterator instead.
+
+ The QMutableMapIterator constructor takes a QMap as argument.
+ After construction, the iterator is located at the very beginning
+ of the map (before the first item). Here's how to iterate over
+ all the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 32
+
+ The next() function returns the next item in the map and
+ advances the iterator. The key() and value() functions return the
+ key and value of the last item that was jumped over.
+
+ Unlike STL-style iterators, Java-style iterators point \e between
+ items rather than directly \e at items. The first call to next()
+ advances the iterator to the position between the first and
+ second item, and returns the first item; the second call to
+ next() advances the iterator to the position between the second
+ and third item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 33
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop. For example:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 34
+
+ If you want to remove items as you iterate over the map, use
+ remove(). If you want to modify the value of an item, use
+ setValue().
+
+ Example:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 35
+
+ The example removes all (key, value) pairs where the key and the
+ value are the same.
+
+ Only one mutable iterator can be active on a given map at any
+ time. Furthermore, no changes should be done directly to the map
+ while the iterator is active (as opposed to through the
+ iterator), since this could invalidate the iterator and lead to
+ undefined behavior.
+
+ \sa QMapIterator, QMap::iterator
+*/
+
+/*!
+ \class QMutableHashIterator
+ \inmodule QtCore
+
+ \brief The QMutableHashIterator class provides a Java-style non-const iterator for QHash and QMultiHash.
+
+ QHash has both \l{Java-style iterators} and \l{STL-style
+ iterators}. The Java-style iterators are more high-level and
+ easier to use than the STL-style iterators; on the other hand,
+ they are slightly less efficient.
+
+ QMutableHashIterator\<Key, T\> allows you to iterate over a QHash
+ (or a QMultiHash) and modify the hash. If you don't want to modify
+ the hash (or have a const QHash), use the slightly faster
+ QHashIterator instead.
+
+ The QMutableHashIterator constructor takes a QHash as argument.
+ After construction, the iterator is located at the very beginning
+ of the hash (before the first item). Here's how to iterate over
+ all the elements sequentially:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 36
+
+ The next() function returns the next item in the hash and
+ advances the iterator. The key() and value() functions return the
+ key and value of the last item that was jumped over.
+
+ Unlike STL-style iterators, Java-style iterators point \e between
+ items rather than directly \e at items. The first call to next()
+ advances the iterator to the position between the first and
+ second item, and returns the first item; the second call to
+ next() advances the iterator to the position between the second
+ and third item; and so on.
+
+ \img javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 37
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop. For example:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 38
+
+ If you want to remove items as you iterate over the hash, use
+ remove(). If you want to modify the value of an item, use
+ setValue().
+
+ Example:
+
+ \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 39
+
+ The example removes all (key, value) pairs where the key and the
+ value are the same.
+
+ Only one mutable iterator can be active on a given hash at any
+ time. Furthermore, no changes should be done directly to the hash
+ while the iterator is active (as opposed to through the
+ iterator), since this could invalidate the iterator and lead to
+ undefined behavior.
+
+ \sa QHashIterator, QHash::iterator
+*/
+
+/*! \fn QMapIterator::QMapIterator(const QMap<Key, T> &map)
+ \fn QMutableMapIterator::QMutableMapIterator(QMap<Key, T> &map)
+
+ Constructs an iterator for traversing \a map. The iterator is set
+ to be at the front of the map (before the first item).
+
+ \sa operator=()
+*/
+
+/*! \fn QHashIterator::QHashIterator(const QHash<Key, T> &hash)
+ \fn QMutableHashIterator::QMutableHashIterator(QHash<Key, T> &hash)
+
+ Constructs an iterator for traversing \a hash. The iterator is
+ set to be at the front of the hash (before the first item).
+
+ \sa operator=()
+*/
+
+/*!
+ \fn QMutableMapIterator::~QMutableMapIterator()
+ \fn QMutableHashIterator::~QMutableHashIterator()
+
+ Destroys the iterator.
+
+ \sa operator=()
+*/
+
+/*! \fn QMapIterator &QMapIterator::operator=(const QMap<Key, T> &map)
+ \fn QMutableMapIterator &QMutableMapIterator::operator=(QMap<Key, T> &map)
+
+ Makes the iterator operate on \a map. The iterator is set to be
+ at the front of the map (before the first item).
+
+ \sa toFront(), toBack()
+*/
+
+/*! \fn QHashIterator &QHashIterator::operator=(const QHash<Key, T> &hash)
+ \fn QMutableHashIterator &QMutableHashIterator::operator=(QHash<Key, T> &hash)
+
+ Makes the iterator operate on \a hash. The iterator is set to be
+ at the front of the hash (before the first item).
+
+ \sa toFront(), toBack()
+*/
+
+/*! \fn void QMapIterator::toFront()
+ \fn void QHashIterator::toFront()
+ \fn void QMutableMapIterator::toFront()
+ \fn void QMutableHashIterator::toFront()
+
+ Moves the iterator to the front of the container (before the
+ first item).
+
+ \sa toBack(), next()
+*/
+
+/*! \fn void QMapIterator::toBack()
+ \fn void QHashIterator::toBack()
+ \fn void QMutableMapIterator::toBack()
+ \fn void QMutableHashIterator::toBack()
+
+ Moves the iterator to the back of the container (after the last
+ item).
+
+ \sa toFront(), previous()
+*/
+
+/*! \fn bool QMapIterator::hasNext() const
+ \fn bool QHashIterator::hasNext() const
+ \fn bool QMutableMapIterator::hasNext() const
+ \fn bool QMutableHashIterator::hasNext() const
+
+ Returns true if there is at least one item ahead of the iterator,
+ i.e. the iterator is \e not at the back of the container;
+ otherwise returns false.
+
+ \sa hasPrevious(), next()
+*/
+
+/*! \fn QMapIterator::Item QMapIterator::next()
+ \fn QHashIterator::Item QHashIterator::next()
+
+ Returns the next item and advances the iterator by one position.
+
+ Call key() on the return value to obtain the item's key, and
+ value() to obtain the value.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), peekNext(), previous()
+*/
+
+/*! \fn QMutableMapIterator::Item QMutableMapIterator::next()
+ \fn QMutableHashIterator::Item QMutableHashIterator::next()
+
+ Returns the next item and advances the iterator by one position.
+
+ Call key() on the return value to obtain the item's key, and
+ value() to obtain the value.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), peekNext(), previous()
+*/
+
+/*! \fn QMapIterator::Item QMapIterator::peekNext() const
+ \fn QHashIterator::Item QHashIterator::peekNext() const
+
+ Returns the next item without moving the iterator.
+
+ Call key() on the return value to obtain the item's key, and
+ value() to obtain the value.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), next(), peekPrevious()
+*/
+
+/*! \fn QMutableMapIterator::Item QMutableMapIterator::peekNext() const
+ \fn QMutableHashIterator::Item QMutableHashIterator::peekNext() const
+
+ Returns a reference to the next item without moving the iterator.
+
+ Call key() on the return value to obtain the item's key, and
+ value() to obtain the value.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), next(), peekPrevious()
+*/
+
+/*! \fn bool QMapIterator::hasPrevious() const
+ \fn bool QHashIterator::hasPrevious() const
+ \fn bool QMutableMapIterator::hasPrevious() const
+ \fn bool QMutableHashIterator::hasPrevious() const
+
+ Returns true if there is at least one item behind the iterator,
+ i.e. the iterator is \e not at the front of the container;
+ otherwise returns false.
+
+ \sa hasNext(), previous()
+*/
+
+/*! \fn QMapIterator::Item QMapIterator::previous()
+ \fn QHashIterator::Item QHashIterator::previous()
+
+ Returns the previous item and moves the iterator back by one
+ position.
+
+ Call key() on the return value to obtain the item's key, and
+ value() to obtain the value.
+
+ Calling this function on an iterator located at the front of the
+ container leads to undefined results.
+
+ \sa hasPrevious(), peekPrevious(), next()
+*/
+
+/*! \fn QMutableMapIterator::Item QMutableMapIterator::previous()
+ \fn QMutableHashIterator::Item QMutableHashIterator::previous()
+
+ Returns the previous item and moves the iterator back by one
+ position.
+
+ Call key() on the return value to obtain the item's key, and
+ value() to obtain the value.
+
+ Calling this function on an iterator located at the front of the
+ container leads to undefined results.
+
+ \sa hasPrevious(), peekPrevious(), next()
+*/
+
+/*! \fn QMapIterator::Item QMapIterator::peekPrevious() const
+ \fn QHashIterator::Item QHashIterator::peekPrevious() const
+
+ Returns the previous item without moving the iterator.
+
+ Call key() on the return value to obtain the item's key, and
+ value() to obtain the value.
+
+ Calling this function on an iterator located at the front of the
+ container leads to undefined results.
+
+ \sa hasPrevious(), previous(), peekNext()
+*/
+
+/*! \fn QMutableMapIterator::Item QMutableMapIterator::peekPrevious() const
+ \fn QMutableHashIterator::Item QMutableHashIterator::peekPrevious() const
+
+ Returns the previous item without moving the iterator.
+
+ Call key() on the return value to obtain the item's key, and
+ value() to obtain the value.
+
+ Calling this function on an iterator located at the front of the
+ container leads to undefined results.
+
+ \sa hasPrevious(), previous(), peekNext()
+*/
+
+/*! \fn const T &QMapIterator::value() const
+ \fn const T &QHashIterator::value() const
+
+ Returns the value of the last item that was jumped over using one
+ of the traversal functions (next(), previous(), findNext(),
+ findPrevious()).
+
+ After a call to next() or findNext(), value() is
+ equivalent to peekPrevious().value(). After a call to previous()
+ or findPrevious(), value() is equivalent to peekNext().value().
+
+ \sa key()
+*/
+
+/*!
+ \fn const T &QMutableMapIterator::value() const
+ \fn const T &QMutableHashIterator::value() const
+
+ Returns the value of the last item that was jumped over using one
+ of the traversal functions (next(), previous(), findNext(),
+ findPrevious()).
+
+ After a call to next() or findNext(), value() is
+ equivalent to peekPrevious().value(). After a call to previous()
+ or findPrevious(), value() is equivalent to peekNext().value().
+
+ \sa key(), setValue()
+*/
+
+/*!
+ \fn T &QMutableMapIterator::value()
+ \fn T &QMutableHashIterator::value()
+ \overload
+
+ Returns a non-const reference to the value of
+ the last item that was jumped over using one
+ of the traversal functions.
+*/
+
+/*! \fn const Key &QMapIterator::key() const
+ \fn const Key &QHashIterator::key() const
+ \fn const Key &QMutableMapIterator::key() const
+ \fn const Key &QMutableHashIterator::key() const
+
+ Returns the key of the last item that was jumped over using one
+ of the traversal functions (next(), previous(), findNext(),
+ findPrevious()).
+
+ After a call to next() or findNext(), key() is
+ equivalent to peekPrevious().key(). After a call to previous() or
+ findPrevious(), key() is equivalent to peekNext().key().
+
+ \sa value()
+*/
+
+/*! \fn bool QMapIterator::findNext(const T &value)
+ \fn bool QHashIterator::findNext(const T &value)
+ \fn bool QMutableMapIterator::findNext(const T &value)
+ \fn bool QMutableHashIterator::findNext(const T &value)
+
+ Searches for \a value starting from the current iterator position
+ forward. Returns true if a (key, value) pair with value \a value
+ is found; otherwise returns false.
+
+ After the call, if \a value was found, the iterator is positioned
+ just after the matching item; otherwise, the iterator is
+ positioned at the back of the container.
+
+ \sa findPrevious()
+*/
+
+/*! \fn bool QMapIterator::findPrevious(const T &value)
+ \fn bool QHashIterator::findPrevious(const T &value)
+ \fn bool QMutableMapIterator::findPrevious(const T &value)
+ \fn bool QMutableHashIterator::findPrevious(const T &value)
+
+ Searches for \a value starting from the current iterator position
+ backward. Returns true if a (key, value) pair with value \a value
+ is found; otherwise returns false.
+
+ After the call, if \a value was found, the iterator is positioned
+ just before the matching item; otherwise, the iterator is
+ positioned at the front of the container.
+
+ \sa findNext()
+*/
+
+/*! \fn void QMutableMapIterator::remove()
+ \fn void QMutableHashIterator::remove()
+
+ Removes the last item that was jumped over using one of the
+ traversal functions (next(), previous(), findNext(), findPrevious()).
+
+ \sa setValue()
+*/
+
+/*! \fn void QMutableMapIterator::setValue(const T &value)
+ \fn void QMutableHashIterator::setValue(const T &value)
+
+ Replaces the value of the last item that was jumped over using
+ one of the traversal functions with \a value.
+
+ The traversal functions are next(), previous(), findNext(), and
+ findPrevious().
+
+ \sa key(), value(), remove()
+*/
diff --git a/src/corelib/tools/qline.cpp b/src/corelib/tools/qline.cpp
index 8f01043..838e55b 100644
--- a/src/corelib/tools/qline.cpp
+++ b/src/corelib/tools/qline.cpp
@@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QLine
- \ingroup multimedia
+ \ingroup painting
\brief The QLine class provides a two-dimensional vector using
integer precision.
@@ -260,7 +260,7 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const QLine &p)
{
- d << "QLine(" << p.p1() << "," << p.p2() << ")";
+ d << "QLine(" << p.p1() << ',' << p.p2() << ')';
return d;
}
#endif
@@ -309,7 +309,7 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
/*!
\class QLineF
- \ingroup multimedia
+ \ingroup painting
\brief The QLineF class provides a two-dimensional vector using
floating point precision.
@@ -822,7 +822,7 @@ qreal QLineF::angle(const QLineF &l) const
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const QLineF &p)
{
- d << "QLineF(" << p.p1() << "," << p.p2() << ")";
+ d << "QLineF(" << p.p1() << ',' << p.p2() << ')';
return d;
}
#endif
diff --git a/src/corelib/tools/qlinkedlist.cpp b/src/corelib/tools/qlinkedlist.cpp
index 1ca4930..0d4711b 100644
--- a/src/corelib/tools/qlinkedlist.cpp
+++ b/src/corelib/tools/qlinkedlist.cpp
@@ -53,7 +53,7 @@ QLinkedListData QLinkedListData::shared_null = {
\ingroup tools
\ingroup shared
- \mainclass
+
\reentrant
QLinkedList\<T\> is one of Qt's generic \l{container classes}. It
diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h
index aeb14be..f7ae421 100644
--- a/src/corelib/tools/qlinkedlist.h
+++ b/src/corelib/tools/qlinkedlist.h
@@ -265,15 +265,22 @@ void QLinkedList<T>::detach_helper()
x.d->ref = 1;
x.d->size = d->size;
x.d->sharable = true;
- Node *i = e->n, *j = x.e;
- while (i != e) {
- j->n = new Node(i->t);
- j->n->p = j;
- i = i->n;
- j = j->n;
+ Node *original = e->n;
+ Node *copy = x.e;
+ while (original != e) {
+ QT_TRY {
+ copy->n = new Node(original->t);
+ copy->n->p = copy;
+ original = original->n;
+ copy = copy->n;
+ } QT_CATCH(...) {
+ copy->n = x.e;
+ free(x.d);
+ QT_RETHROW;
+ }
}
- j->n = x.e;
- x.e->p = j;
+ copy->n = x.e;
+ x.e->p = copy;
if (!d->ref.deref())
free(d);
d = x.d;
@@ -474,14 +481,21 @@ QLinkedList<T> &QLinkedList<T>::operator+=(const QLinkedList<T> &l)
detach();
int n = l.d->size;
d->size += n;
- Node *o = l.e->n;
+ Node *original = l.e->n;
while (n--) {
- Node *i = new Node(o->t);
- o = o->n;
- i->n = e;
- i->p = e->p;
- i->p->n = i;
- e->p = i;
+ QT_TRY {
+ Node *copy = new Node(original->t);
+ original = original->n;
+ copy->n = e;
+ copy->p = e->p;
+ copy->p->n = copy;
+ e->p = copy;
+ } QT_CATCH(...) {
+ // restore the original list
+ while (n++<d->size)
+ removeLast();
+ QT_RETHROW;
+ }
}
return *this;
}
diff --git a/src/corelib/tools/qlistdata.cpp b/src/corelib/tools/qlist.cpp
index 872bdd8..e63d46d 100644
--- a/src/corelib/tools/qlistdata.cpp
+++ b/src/corelib/tools/qlist.cpp
@@ -39,6 +39,7 @@
**
****************************************************************************/
+#include <new>
#include "qlist.h"
#include "qtools_p.h"
#include <string.h>
@@ -71,15 +72,18 @@ static int grow(int size)
QListData::Data *QListData::detach()
{
Data *x = static_cast<Data *>(qMalloc(DataHeaderSize + d->alloc * sizeof(void *)));
- if (!x)
- qFatal("QList: Out of memory");
+ Q_CHECK_PTR(x);
- ::memcpy(x, d, DataHeaderSize + d->alloc * sizeof(void *));
- x->alloc = d->alloc;
x->ref = 1;
x->sharable = true;
- if (!x->alloc)
- x->begin = x->end = 0;
+ x->alloc = d->alloc;
+ if (!x->alloc) {
+ x->begin = 0;
+ x->end = 0;
+ } else {
+ x->begin = d->begin;
+ x->end = d->end;
+ }
qSwap(d, x);
if (!x->ref.deref())
@@ -87,20 +91,63 @@ QListData::Data *QListData::detach()
return 0;
}
-// Returns the old (shared) data, it is up to the caller to deref() and free()
+/*!
+ * Detaches the QListData by reallocating new memory.
+ * Returns the old (shared) data, it is up to the caller to deref() and free()
+ * For the new data node_copy needs to be called.
+ *
+ * \internal
+ */
+#if QT_VERSION >= 0x050000
+# error "Remove QListData::detach2(), it is only required for binary compatibility for 4.3.x to 4.5.x"
+#endif
QListData::Data *QListData::detach2()
{
Data *x = d;
- d = static_cast<Data *>(qMalloc(DataHeaderSize + x->alloc * sizeof(void *)));
- if (!d)
- qFatal("QList: Out of memory");
-
- ::memcpy(d, x, DataHeaderSize + x->alloc * sizeof(void *));
- d->alloc = x->alloc;
- d->ref = 1;
- d->sharable = true;
- if (!d->alloc)
- d->begin = d->end = 0;
+ Data* t = static_cast<Data *>(qMalloc(DataHeaderSize + x->alloc * sizeof(void *)));
+ Q_CHECK_PTR(t);
+
+ ::memcpy(t, d, DataHeaderSize + d->alloc * sizeof(void *));
+
+ t->ref = 1;
+ t->sharable = true;
+ t->alloc = x->alloc;
+ if (!t->alloc) {
+ t->begin = 0;
+ t->end = 0;
+ } else {
+ t->begin = x->begin;
+ t->end = x->end;
+ }
+ d = t;
+
+ return x;
+}
+
+/*!
+ * Detaches the QListData by reallocating new memory.
+ * Returns the old (shared) data, it is up to the caller to deref() and free()
+ * For the new data node_copy needs to be called.
+ *
+ * \internal
+ */
+QListData::Data *QListData::detach3()
+{
+ Data *x = d;
+ Data* t = static_cast<Data *>(qMalloc(DataHeaderSize + x->alloc * sizeof(void *)));
+ Q_CHECK_PTR(t);
+
+ t->ref = 1;
+ t->sharable = true;
+ t->alloc = x->alloc;
+ if (!t->alloc) {
+ t->begin = 0;
+ t->end = 0;
+ } else {
+ t->begin = x->begin;
+ t->end = x->end;
+ }
+ d = t;
return x;
}
@@ -109,8 +156,7 @@ void QListData::realloc(int alloc)
{
Q_ASSERT(d->ref == 1);
Data *x = static_cast<Data *>(qRealloc(d, DataHeaderSize + alloc * sizeof(void *)));
- if (!x)
- qFatal("QList: Out of memory");
+ Q_CHECK_PTR(x);
d = x;
d->alloc = alloc;
@@ -118,12 +164,14 @@ void QListData::realloc(int alloc)
d->begin = d->end = 0;
}
+// ensures that enough space is available to append one element
void **QListData::append()
{
Q_ASSERT(d->ref == 1);
if (d->end == d->alloc) {
int n = d->end - d->begin;
if (d->begin > 2 * d->alloc / 3) {
+ // we have enough space. Just not at the end -> move it.
::memcpy(d->array + n, d->array + d->begin, n * sizeof(void *));
d->begin = n;
d->end = n * 2;
@@ -134,6 +182,10 @@ void **QListData::append()
return d->array + d->end++;
}
+// ensures that enough space is available to append the list
+#if QT_VERSION >= 0x050000
+# error "Remove QListData::append(), it is only required for binary compatibility up to 4.5.x"
+#endif
void **QListData::append(const QListData& l)
{
Q_ASSERT(d->ref == 1);
@@ -142,7 +194,21 @@ void **QListData::append(const QListData& l)
if (n) {
if (e + n > d->alloc)
realloc(grow(e + l.d->end - l.d->begin));
- ::memcpy(d->array + d->end, l.d->array + l.d->begin, n * sizeof(void*));
+ ::memcpy(d->array + d->end, l.d->array + l.d->begin, n*sizeof(void*));
+ d->end += n;
+ }
+ return d->array + e;
+}
+
+// ensures that enough space is available to append the list
+void **QListData::append2(const QListData& l)
+{
+ Q_ASSERT(d->ref == 1);
+ int e = d->end;
+ int n = l.d->end - l.d->begin;
+ if (n) {
+ if (e + n > d->alloc)
+ realloc(grow(e + l.d->end - l.d->begin));
d->end += n;
}
return d->array + e;
@@ -289,7 +355,7 @@ void **QListData::erase(void **xi)
\ingroup tools
\ingroup shared
- \mainclass
+
\reentrant
QList\<T\> is one of Qt's generic \l{container classes}. It
@@ -514,6 +580,15 @@ void **QListData::erase(void **xi)
\internal
*/
+/*! \fn void QList::detachShared()
+
+ \internal
+
+ like detach(), but does nothing if we're shared_null.
+ This prevents needless mallocs, and makes QList more exception safe
+ in case of cleanup work done in destructors on empty lists.
+*/
+
/*! \fn bool QList::isDetached() const
\internal
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index fcab7c1..ba8ae56 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -72,13 +72,15 @@ struct Q_CORE_EXPORT QListData {
enum { DataHeaderSize = sizeof(Data) - sizeof(void *) };
Data *detach(); // remove in 5.0
- Data *detach2();
+ Data *detach2(); // remove in 5.0
+ Data *detach3();
void realloc(int alloc);
static Data shared_null;
Data *d;
void **erase(void **xi);
void **append();
void **append(const QListData &l);
+ void **append2(const QListData &l); // remove in 5.0
void **prepend();
void **insert(int i);
void remove(int i);
@@ -117,6 +119,14 @@ public:
inline int size() const { return p.size(); }
inline void detach() { if (d->ref != 1) detach_helper(); }
+
+ inline void detachShared()
+ {
+ // The "this->" qualification is needed for GCCE.
+ if (d->ref != 1 && this->d != &QListData::shared_null)
+ detach_helper();
+ }
+
inline bool isDetached() const { return d->ref == 1; }
inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; }
@@ -352,12 +362,31 @@ Q_INLINE_TEMPLATE void QList<T>::node_destruct(Node *n)
template <typename T>
Q_INLINE_TEMPLATE void QList<T>::node_copy(Node *from, Node *to, Node *src)
{
- if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic)
- while(from != to)
- (from++)->v = new T(*reinterpret_cast<T*>((src++)->v));
- else if (QTypeInfo<T>::isComplex)
- while(from != to)
- new (from++) T(*reinterpret_cast<T*>(src++));
+ Node *current = from;
+ if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) {
+ QT_TRY {
+ while(current != to) {
+ (current++)->v = new T(*reinterpret_cast<T*>((src++)->v));
+ }
+ } QT_CATCH(...) {
+ while (current != from)
+ delete reinterpret_cast<T*>(current--);
+ QT_RETHROW;
+ }
+
+ } else if (QTypeInfo<T>::isComplex) {
+ QT_TRY {
+ while(current != to)
+ new (current++) T(*reinterpret_cast<T*>(src++));
+ } QT_CATCH(...) {
+ while (current != from)
+ (reinterpret_cast<T*>(current--))->~T();
+ QT_RETHROW;
+ }
+ } else {
+ if (src != from && to - from > 0)
+ memcpy(from, src, (to - from) * sizeof(Node *));
+ }
}
template <typename T>
@@ -384,8 +413,17 @@ Q_INLINE_TEMPLATE QList<T> &QList<T>::operator=(const QList<T> &l)
}
template <typename T>
inline typename QList<T>::iterator QList<T>::insert(iterator before, const T &t)
-{ Node *n = reinterpret_cast<Node *>(p.insert(before.i-reinterpret_cast<Node *>(p.begin())));
- node_construct(n,t); return n; }
+{
+ int iBefore = before.i - reinterpret_cast<Node *>(p.begin());
+ Node *n = reinterpret_cast<Node *>(p.insert(iBefore));
+ QT_TRY {
+ node_construct(n, t);
+ } QT_CATCH(...) {
+ p.remove(iBefore);
+ QT_RETHROW;
+ }
+ return n;
+}
template <typename T>
inline typename QList<T>::iterator QList<T>::erase(iterator it)
{ node_destruct(it.i);
@@ -423,10 +461,22 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t)
{
detach();
if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) {
- node_construct(reinterpret_cast<Node *>(p.append()), t);
+ Node *n = reinterpret_cast<Node *>(p.append());
+ QT_TRY {
+ node_construct(n, t);
+ } QT_CATCH(...) {
+ --d->end;
+ QT_RETHROW;
+ }
} else {
const T cpy(t);
- node_construct(reinterpret_cast<Node *>(p.append()), cpy);
+ Node *n = reinterpret_cast<Node *>(p.append());
+ QT_TRY {
+ node_construct(n, cpy);
+ } QT_CATCH(...) {
+ --d->end;
+ QT_RETHROW;
+ }
}
}
@@ -435,10 +485,22 @@ inline void QList<T>::prepend(const T &t)
{
detach();
if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) {
- node_construct(reinterpret_cast<Node *>(p.prepend()), t);
+ Node *n = reinterpret_cast<Node *>(p.prepend());
+ QT_TRY {
+ node_construct(n, t);
+ } QT_CATCH(...) {
+ ++d->begin;
+ QT_RETHROW;
+ }
} else {
const T cpy(t);
- node_construct(reinterpret_cast<Node *>(p.prepend()), cpy);
+ Node *n = reinterpret_cast<Node *>(p.prepend());
+ QT_TRY {
+ node_construct(n, cpy);
+ } QT_CATCH(...) {
+ ++d->begin;
+ QT_RETHROW;
+ }
}
}
@@ -447,10 +509,22 @@ inline void QList<T>::insert(int i, const T &t)
{
detach();
if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) {
- node_construct(reinterpret_cast<Node *>(p.insert(i)), t);
+ Node *n = reinterpret_cast<Node *>(p.insert(i));
+ QT_TRY {
+ node_construct(n, t);
+ } QT_CATCH(...) {
+ p.remove(i);
+ QT_RETHROW;
+ }
} else {
const T cpy(t);
- node_construct(reinterpret_cast<Node *>(p.insert(i)), cpy);
+ Node *n = reinterpret_cast<Node *>(p.insert(i));
+ QT_TRY {
+ node_construct(n, cpy);
+ } QT_CATCH(...) {
+ p.remove(i);
+ QT_RETHROW;
+ }
}
}
@@ -521,8 +595,15 @@ template <typename T>
Q_OUTOFLINE_TEMPLATE void QList<T>::detach_helper()
{
Node *n = reinterpret_cast<Node *>(p.begin());
- QListData::Data *x = p.detach2();
- node_copy(reinterpret_cast<Node *>(p.begin()), reinterpret_cast<Node *>(p.end()), n);
+ QListData::Data *x = p.detach3();
+ QT_TRY {
+ node_copy(reinterpret_cast<Node *>(p.begin()), reinterpret_cast<Node *>(p.end()), n);
+ } QT_CATCH(...) {
+ qFree(d);
+ d = x;
+ QT_RETHROW;
+ }
+
if (!x->ref.deref())
free(x);
}
@@ -572,7 +653,7 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::clear()
template <typename T>
Q_OUTOFLINE_TEMPLATE int QList<T>::removeAll(const T &_t)
{
- detach();
+ detachShared();
const T t = _t;
int removedCount=0, i=0;
Node *n;
@@ -590,7 +671,7 @@ Q_OUTOFLINE_TEMPLATE int QList<T>::removeAll(const T &_t)
template <typename T>
Q_OUTOFLINE_TEMPLATE bool QList<T>::removeOne(const T &_t)
{
- detach();
+ detachShared();
int index = indexOf(_t);
if (index != -1) {
removeAt(index);
@@ -614,8 +695,14 @@ template <typename T>
Q_OUTOFLINE_TEMPLATE QList<T> &QList<T>::operator+=(const QList<T> &l)
{
detach();
- Node *n = reinterpret_cast<Node *>(p.append(l.p));
- node_copy(n, reinterpret_cast<Node *>(p.end()), reinterpret_cast<Node *>(l.p.begin()));
+ Node *n = reinterpret_cast<Node *>(p.append2(l.p));
+ QT_TRY{
+ node_copy(n, reinterpret_cast<Node *>(p.end()), reinterpret_cast<Node *>(l.p.begin()));
+ } QT_CATCH(...) {
+ // restore the old end
+ d->end -= (reinterpret_cast<Node *>(p.end()) - n);
+ QT_RETHROW;
+ }
return *this;
}
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index 1ebebf8..ded36c2 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -42,7 +42,6 @@
#include "qglobal.h"
#ifndef QT_NO_SYSTEMLOCALE
-#define QLOCALE_CPP
QT_BEGIN_NAMESPACE
class QSystemLocale;
static QSystemLocale *QSystemLocale_globalSystemLocale();
@@ -120,9 +119,16 @@ static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt,
Q_CORE_EXPORT char *qdtoa(double d, int mode, int ndigits, int *decpt,
int *sign, char **rve, char **digits_str);
Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
-Q_CORE_EXPORT qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok);
+static qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok);
static qulonglong qstrtoull(const char *nptr, const char **endptr, register int base, bool *ok);
+#if defined(Q_CC_MWERKS) && defined(Q_OS_WIN32)
+inline bool isascii(int c)
+{
+ return (c >= 0 && c <=127);
+}
+#endif
+
/******************************************************************************
** Helpers for accessing Qt locale database
*/
@@ -186,8 +192,7 @@ static QString languageToCode(QLocale::Language language)
const unsigned char *c = language_code_list + 3*(uint(language));
- QString code;
- code.resize(c[2] == 0 ? 2 : 3);
+ QString code(c[2] == 0 ? 2 : 3, Qt::Uninitialized);
code[0] = ushort(c[0]);
code[1] = ushort(c[1]);
@@ -202,8 +207,7 @@ static QString countryToCode(QLocale::Country country)
if (country == QLocale::AnyCountry)
return QString();
- QString code;
- code.resize(2);
+ QString code(2, Qt::Uninitialized);
const unsigned char *c = country_code_list + 2*(uint(country));
code[0] = ushort(c[0]);
code[1] = ushort(c[1]);
@@ -291,7 +295,7 @@ static bool splitLocaleName(const QString &name, QChar *lang_begin, QChar *cntry
return lang_len == 2 || lang_len == 3;
}
-static void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Country &cntry)
+void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Country &cntry)
{
lang = QLocale::C;
cntry = QLocale::AnyCountry;
@@ -321,7 +325,7 @@ static QString readEscapedFormatString(const QString &format, int *idx)
{
int &i = *idx;
- Q_ASSERT(format.at(i).unicode() == '\'');
+ Q_ASSERT(format.at(i) == QLatin1Char('\''));
++i;
if (i == format.size())
return QString();
@@ -389,15 +393,8 @@ static QString winIso3116CtryName(LCID id = LOCALE_USER_DEFAULT);
static QString getWinLocaleInfo(LCTYPE type)
{
- int cnt = 0;
-
LCID id = GetUserDefaultLCID();
-
- QT_WA({
- cnt = GetLocaleInfoW(id, type, 0, 0)*2;
- } , {
- cnt = GetLocaleInfoA(id, type, 0, 0);
- });
+ int cnt = GetLocaleInfo(id, type, 0, 0) * 2;
if (cnt == 0) {
qWarning("QLocale: empty windows locale info (%d)", (int)type);
@@ -406,27 +403,14 @@ static QString getWinLocaleInfo(LCTYPE type)
QByteArray buff(cnt, 0);
- QT_WA({
- cnt = GetLocaleInfoW(id, type,
- reinterpret_cast<wchar_t*>(buff.data()),
- buff.size()/2);
- } , {
- cnt = GetLocaleInfoA(id, type,
- buff.data(), buff.size());
- });
+ cnt = GetLocaleInfo(id, type, reinterpret_cast<wchar_t*>(buff.data()), buff.size() / 2);
if (cnt == 0) {
qWarning("QLocale: empty windows locale info (%d)", (int)type);
return QString();
}
- QString result;
- QT_WA({
- result = QString::fromUtf16(reinterpret_cast<ushort*>(buff.data()));
- } , {
- result = QString::fromLocal8Bit(buff.data());
- });
- return result;
+ return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(buff.data()));
}
QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT)
@@ -436,8 +420,8 @@ QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT)
result = envVarLocale();
QChar lang[3];
QChar cntry[2];
- if ( result == "C" || !result.isEmpty()
- && splitLocaleName(QString::fromLocal8Bit(result), lang, cntry) ) {
+ if ( result == "C" || (!result.isEmpty()
+ && splitLocaleName(QString::fromLocal8Bit(result), lang, cntry)) ) {
long id = 0;
bool ok = false;
id = qstrtoll(result.data(), 0, 0, &ok);
@@ -448,20 +432,19 @@ QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT)
}
}
- if (QSysInfo::WindowsVersion == QSysInfo::WV_95
- || (QSysInfo::WindowsVersion & QSysInfo::WV_CE_based)) {
- result = winLangCodeToIsoName(id != LOCALE_USER_DEFAULT ? id : GetUserDefaultLCID());
- } else {
- if (id == LOCALE_USER_DEFAULT)
- id = GetUserDefaultLCID();
- QString resultuage = winIso639LangName(id);
- QString country = winIso3116CtryName(id);
- result = resultuage.toLatin1();
- if (!country.isEmpty()) {
- result += '_';
- result += country.toLatin1();
- }
+#if defined(Q_OS_WINCE)
+ result = winLangCodeToIsoName(id != LOCALE_USER_DEFAULT ? id : GetUserDefaultLCID());
+#else
+ if (id == LOCALE_USER_DEFAULT)
+ id = GetUserDefaultLCID();
+ QString resultuage = winIso639LangName(id);
+ QString country = winIso3116CtryName(id);
+ result = resultuage.toLatin1();
+ if (!country.isEmpty()) {
+ result += '_';
+ result += country.toLatin1();
}
+#endif
return result;
}
@@ -547,15 +530,9 @@ static QString winDateToString(const QDate &date, DWORD flags)
LCID id = GetUserDefaultLCID();
- QT_WA({
- TCHAR buf[255];
- if (GetDateFormatW(id, flags, &st, 0, buf, 255))
- return QString::fromUtf16((ushort*)buf);
- } , {
- char buf[255];
- if (GetDateFormatA(id, flags, &st, 0, (char*)&buf, 255))
- return QString::fromLocal8Bit(buf);
- });
+ wchar_t buf[255];
+ if (GetDateFormat(id, flags, &st, 0, buf, 255))
+ return QString::fromWCharArray(buf);
return QString();
}
@@ -572,15 +549,9 @@ static QString winTimeToString(const QTime &time)
DWORD flags = 0;
LCID id = GetUserDefaultLCID();
- QT_WA({
- TCHAR buf[255];
- if (GetTimeFormatW(id, flags, &st, 0, buf, 255))
- return QString::fromUtf16((ushort*)buf);
- } , {
- char buf[255];
- if (GetTimeFormatA(id, flags, &st, 0, (char*)&buf, 255))
- return QString::fromLocal8Bit(buf);
- });
+ wchar_t buf[255];
+ if (GetTimeFormat(id, flags, &st, 0, buf, 255))
+ return QString::fromWCharArray(buf);
return QString();
}
@@ -629,13 +600,11 @@ static QString winMonthName(int month, bool short_format)
static QLocale::MeasurementSystem winSystemMeasurementSystem()
{
LCID id = GetUserDefaultLCID();
- TCHAR output[2];
+ wchar_t output[2];
if (GetLocaleInfo(id, LOCALE_IMEASURE, output, 2)) {
- QString iMeasure = QT_WA_INLINE(
- QString::fromUtf16(reinterpret_cast<ushort*>(output)),
- QString::fromLocal8Bit(reinterpret_cast<char*>(output)));
- if (iMeasure == QString::fromLatin1("1")) {
+ QString iMeasure = QString::fromWCharArray(output);
+ if (iMeasure == QLatin1String("1")) {
return QLocale::ImperialSystem;
}
}
@@ -646,12 +615,10 @@ static QLocale::MeasurementSystem winSystemMeasurementSystem()
static QString winSystemAMText()
{
LCID id = GetUserDefaultLCID();
- TCHAR output[15]; // maximum length including terminating zero character for Win2003+
+ wchar_t output[15]; // maximum length including terminating zero character for Win2003+
if (GetLocaleInfo(id, LOCALE_S1159, output, 15)) {
- return QT_WA_INLINE(
- QString::fromUtf16(reinterpret_cast<ushort*>(output)),
- QString::fromLocal8Bit(reinterpret_cast<char*>(output)));
+ return QString::fromWCharArray(output);
}
return QString();
@@ -660,12 +627,10 @@ static QString winSystemAMText()
static QString winSystemPMText()
{
LCID id = GetUserDefaultLCID();
- TCHAR output[15]; // maximum length including terminating zero character for Win2003+
+ wchar_t output[15]; // maximum length including terminating zero character for Win2003+
if (GetLocaleInfo(id, LOCALE_S2359, output, 15)) {
- return QT_WA_INLINE(
- QString::fromUtf16(reinterpret_cast<ushort*>(output)),
- QString::fromLocal8Bit(reinterpret_cast<char*>(output)));
+ return QString::fromWCharArray(output);
}
return QString();
@@ -769,11 +734,8 @@ QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
return QVariant();
}
-/* Win95 doesn't have a function to return the ISO lang/country name of the user's locale.
- Instead it can return a "Windows code". This maps windows codes to ISO country names. */
-
struct WindowsToISOListElt {
- int windows_code;
+ ushort windows_code;
char iso_name[6];
};
@@ -927,15 +889,9 @@ static QString winIso639LangName(LCID id)
// Windows returns the wrong ISO639 for some languages, we need to detect them here using
// the language code
QString lang_code;
- QT_WA({
- TCHAR out[256];
- if (GetLocaleInfoW(id, LOCALE_ILANGUAGE, out, 255))
- lang_code = QString::fromUtf16((ushort*)out);
- } , {
- char out[256];
- if (GetLocaleInfoA(id, LOCALE_ILANGUAGE, out, 255))
- lang_code = QString::fromLocal8Bit(out);
- });
+ wchar_t out[256];
+ if (GetLocaleInfo(id, LOCALE_ILANGUAGE, out, 255))
+ lang_code = QString::fromWCharArray(out);
if (!lang_code.isEmpty()) {
const char *endptr;
@@ -957,15 +913,8 @@ static QString winIso639LangName(LCID id)
return result;
// not one of the problematic languages - do the usual lookup
- QT_WA({
- TCHAR out[256];
- if (GetLocaleInfoW(id, LOCALE_SISO639LANGNAME , out, 255))
- result = QString::fromUtf16((ushort*)out);
- } , {
- char out[256];
- if (GetLocaleInfoA(id, LOCALE_SISO639LANGNAME, out, 255))
- result = QString::fromLocal8Bit(out);
- });
+ if (GetLocaleInfo(id, LOCALE_SISO639LANGNAME , out, 255))
+ result = QString::fromWCharArray(out);
return result;
}
@@ -974,15 +923,9 @@ static QString winIso3116CtryName(LCID id)
{
QString result;
- QT_WA({
- TCHAR out[256];
- if (GetLocaleInfoW(id, LOCALE_SISO3166CTRYNAME, out, 255))
- result = QString::fromUtf16((ushort*)out);
- } , {
- char out[256];
- if (GetLocaleInfoA(id, LOCALE_SISO3166CTRYNAME, out, 255))
- result = QString::fromLocal8Bit(out);
- });
+ wchar_t out[256];
+ if (GetLocaleInfo(id, LOCALE_SISO3166CTRYNAME, out, 255))
+ result = QString::fromWCharArray(out);
return result;
}
@@ -1014,21 +957,17 @@ static QString macMonthName(int month, bool short_format)
if (month < 0 || month > 11)
return QString();
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
- QCFType<CFDateFormatterRef> formatter
- = CFDateFormatterCreate(0, QCFType<CFLocaleRef>(CFLocaleCopyCurrent()),
- kCFDateFormatterNoStyle, kCFDateFormatterNoStyle);
- QCFType<CFArrayRef> values
- = static_cast<CFArrayRef>(CFDateFormatterCopyProperty(formatter,
- short_format ? kCFDateFormatterShortMonthSymbols
- : kCFDateFormatterMonthSymbols));
- if (values != 0) {
- CFStringRef cfstring = static_cast<CFStringRef>(CFArrayGetValueAtIndex(values, month));
- return QCFString::toQString(cfstring);
- }
+ QCFType<CFDateFormatterRef> formatter
+ = CFDateFormatterCreate(0, QCFType<CFLocaleRef>(CFLocaleCopyCurrent()),
+ kCFDateFormatterNoStyle, kCFDateFormatterNoStyle);
+ QCFType<CFArrayRef> values
+ = static_cast<CFArrayRef>(CFDateFormatterCopyProperty(formatter,
+ short_format ? kCFDateFormatterShortMonthSymbols
+ : kCFDateFormatterMonthSymbols));
+ if (values != 0) {
+ CFStringRef cfstring = static_cast<CFStringRef>(CFArrayGetValueAtIndex(values, month));
+ return QCFString::toQString(cfstring);
}
-#endif
return QString();
}
@@ -1038,20 +977,16 @@ static QString macDayName(int day, bool short_format)
if (day < 1 || day > 7)
return QString();
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
- QCFType<CFDateFormatterRef> formatter
- = CFDateFormatterCreate(0, QCFType<CFLocaleRef>(CFLocaleCopyCurrent()),
- kCFDateFormatterNoStyle, kCFDateFormatterNoStyle);
- QCFType<CFArrayRef> values = static_cast<CFArrayRef>(CFDateFormatterCopyProperty(formatter,
- short_format ? kCFDateFormatterShortWeekdaySymbols
- : kCFDateFormatterWeekdaySymbols));
- if (values != 0) {
- CFStringRef cfstring = static_cast<CFStringRef>(CFArrayGetValueAtIndex(values, day % 7));
- return QCFString::toQString(cfstring);
- }
+ QCFType<CFDateFormatterRef> formatter
+ = CFDateFormatterCreate(0, QCFType<CFLocaleRef>(CFLocaleCopyCurrent()),
+ kCFDateFormatterNoStyle, kCFDateFormatterNoStyle);
+ QCFType<CFArrayRef> values = static_cast<CFArrayRef>(CFDateFormatterCopyProperty(formatter,
+ short_format ? kCFDateFormatterShortWeekdaySymbols
+ : kCFDateFormatterWeekdaySymbols));
+ if (values != 0) {
+ CFStringRef cfstring = static_cast<CFStringRef>(CFArrayGetValueAtIndex(values, day % 7));
+ return QCFString::toQString(cfstring);
}
-#endif
return QString();
}
@@ -1136,7 +1071,7 @@ static QString macToQtFormat(const QString &sys_fmt)
break;
case 'S': // fractional second
if (repeat < 3)
- result += QLatin1String("z");
+ result += QLatin1Char('z');
else
result += QLatin1String("zzz");
break;
@@ -1150,7 +1085,7 @@ static QString macToQtFormat(const QString &sys_fmt)
if (repeat >= 2)
result += QLatin1String("dd");
else
- result += QLatin1String("d");
+ result += QLatin1Char('d');
break;
case 'a':
result += QLatin1String("AP");
@@ -1271,7 +1206,7 @@ QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
return QVariant();
}
-#elif defined(Q_OS_UNIX)
+#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
static uint unixGetSystemMeasurementSystem()
{
@@ -1315,7 +1250,7 @@ QVariant QSystemLocale::query(QueryType type, QVariant /* in */) const
}
}
-#else
+#elif !defined(Q_OS_SYMBIAN)
/*!
Returns a fallback locale, that will get used for everything that
@@ -1534,7 +1469,7 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l)
l = QLocale(s);
return ds;
}
-#endif
+#endif // QT_NO_DATASTREAM
/*!
@@ -1544,9 +1479,9 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l)
\reentrant
\ingroup i18n
- \ingroup text
+ \ingroup string-processing
\ingroup shared
- \mainclass
+
QLocale is initialized with a language/country pair in its
constructor and offers number-to-string and string-to-number
@@ -1602,6 +1537,8 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l)
This constructor converts the locale name to a language/country
pair; it does not use the system locale database.
+ QLocale's data is based on Common Locale Data Repository v1.6.1.
+
The double-to-string and string-to-double conversion functions are
covered by the following licenses:
@@ -1622,8 +1559,6 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l)
This product includes software developed by the University of
California, Berkeley and its contributors.
- QLocale's data is based on Common Locale Data Repository v1.6.1.
-
\sa QString::arg(), QString::toInt(), QString::toDouble()
*/
@@ -2700,7 +2635,7 @@ static QString timeZone()
DWORD res = GetTimeZoneInformation(&info);
if (res == TIME_ZONE_ID_UNKNOWN)
return QString();
- return QString::fromUtf16(reinterpret_cast<const ushort *> (info.StandardName));
+ return QString::fromWCharArray(info.StandardName);
#elif defined(Q_OS_WIN)
_tzset();
# if defined(_MSC_VER) && _MSC_VER >= 1400
@@ -2712,6 +2647,8 @@ static QString timeZone()
# else
return QString::fromLocal8Bit(_tzname[1]);
# endif
+#elif defined(Q_OS_VXWORKS)
+ return QString();
#else
tzset();
return QString::fromLocal8Bit(tzname[1]);
@@ -3947,7 +3884,13 @@ QString QLocalePrivate::doubleToString(double d,
char *rve = 0;
char *buff = 0;
- digits = QLatin1String(qdtoa(d, mode, pr, &decpt, &sign, &rve, &buff));
+ QT_TRY {
+ digits = QLatin1String(qdtoa(d, mode, pr, &decpt, &sign, &rve, &buff));
+ } QT_CATCH(...) {
+ if (buff != 0)
+ free(buff);
+ QT_RETHROW;
+ }
if (buff != 0)
free(buff);
#endif // QT_QLOCALE_USES_FCVT
@@ -4671,7 +4614,7 @@ static qulonglong qstrtoull(const char *nptr, const char **endptr, register int
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
-Q_CORE_EXPORT qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok)
+static qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok)
{
register const char *s;
register qulonglong acc;
@@ -5010,6 +4953,9 @@ static inline void Storeinc(ULong *&a, const ULong &b, const ULong &c)
#define Bletch 0x10
#define Bndry_mask 0xfffff
#define Bndry_mask1 0xfffff
+#if defined(LSB) && defined(Q_OS_VXWORKS)
+#undef LSB
+#endif
#define LSB 1
#define Sign_bit 0x80000000
#define Log2P 1
@@ -5117,6 +5063,7 @@ static Bigint *Balloc(int k)
x = 1 << k;
rv = static_cast<Bigint *>(MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long)));
+ Q_CHECK_PTR(rv);
rv->k = k;
rv->maxwds = x;
rv->sign = rv->wds = 0;
@@ -5367,6 +5314,18 @@ static Bigint *mult(Bigint *a, Bigint *b)
static Bigint *p5s;
+struct p5s_deleter
+{
+ ~p5s_deleter()
+ {
+ while (p5s) {
+ Bigint *next = p5s->next;
+ Bfree(p5s);
+ p5s = next;
+ }
+ }
+};
+
static Bigint *pow5mult(Bigint *b, int k)
{
Bigint *b1, *p5, *p51;
@@ -5388,6 +5347,7 @@ static Bigint *pow5mult(Bigint *b, int k)
return b;
if (!(p5 = p5s)) {
/* first time */
+ static p5s_deleter deleter;
p5 = p5s = i2b(625);
p5->next = 0;
}
@@ -6780,7 +6740,13 @@ static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt,
if (i <= 0)
i = 1;
}
- *resultp = static_cast<char *>(malloc(i + 1));
+ QT_TRY {
+ *resultp = static_cast<char *>(malloc(i + 1));
+ Q_CHECK_PTR(*resultp);
+ } QT_CATCH(...) {
+ Bfree(b);
+ QT_RETHROW;
+ }
s = s0 = *resultp;
if (ilim >= 0 && ilim <= Quick_max && try_quick) {
@@ -7202,6 +7168,7 @@ Q_CORE_EXPORT char *qdtoa( double d, int mode, int ndigits, int *decpt, int *sig
n = i + 1;
}
*resultp = static_cast<char*>(malloc(n + 1));
+ Q_CHECK_PTR(resultp);
qstrncpy(*resultp, res, n + 1);
return *resultp;
}
diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h
index 313d9ff..4248a3d 100644
--- a/src/corelib/tools/qlocale.h
+++ b/src/corelib/tools/qlocale.h
@@ -99,11 +99,9 @@ public:
virtual QVariant query(QueryType type, QVariant in) const;
virtual QLocale fallbackLocale() const;
-#ifdef QLOCALE_CPP
private:
QSystemLocale(bool);
friend QSystemLocale *QSystemLocale_globalSystemLocale();
-#endif
};
#endif
diff --git a/src/corelib/tools/qlocale_data_p.h b/src/corelib/tools/qlocale_data_p.h
index 7a0c89d..8f931c0 100644
--- a/src/corelib/tools/qlocale_data_p.h
+++ b/src/corelib/tools/qlocale_data_p.h
@@ -60,8 +60,8 @@ QT_BEGIN_NAMESPACE
*/
struct CountryLanguage
{
- quint32 languageId;
- quint32 countryId;
+ quint16 languageId;
+ quint16 countryId;
};
static const CountryLanguage ImperialMeasurementSystems[] = {
{ 31, 225 },
@@ -83,7 +83,7 @@ static const int ImperialMeasurementSystemsCount =
*/
-static const uint locale_index[] = {
+static const quint16 locale_index[] = {
0, // unused
0, // C
0, // Abkhazian
@@ -2313,7 +2313,7 @@ static const char language_name_list[] =
"Chewa\0"
;
-static const uint language_name_index[] = {
+static const quint16 language_name_index[] = {
0, // Unused
8, // C
10, // Abkhazian
@@ -2727,7 +2727,7 @@ static const char country_name_list[] =
"SerbiaAndMontenegro\0"
;
-static const uint country_name_index[] = {
+static const quint16 country_name_index[] = {
0, // AnyCountry
8, // Afghanistan
20, // Albania
diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h
index fadd3a1..a1e79a1 100644
--- a/src/corelib/tools/qlocale_p.h
+++ b/src/corelib/tools/qlocale_p.h
@@ -96,7 +96,7 @@ public:
ShowBase = 0x80,
UppercaseBase = 0x100,
- ForcePoint = Alternate,
+ ForcePoint = Alternate
};
enum GroupSeparatorMode {
@@ -140,29 +140,29 @@ public:
QString dateTimeToString(const QString &format, const QDate *date, const QTime *time,
const QLocale *q) const;
- quint32 m_language_id, m_country_id;
+ quint16 m_language_id, m_country_id;
quint16 m_decimal, m_group, m_list, m_percent,
m_zero, m_minus, m_plus, m_exponential;
- quint32 m_short_date_format_idx, m_short_date_format_size;
- quint32 m_long_date_format_idx, m_long_date_format_size;
- quint32 m_short_time_format_idx, m_short_time_format_size;
- quint32 m_long_time_format_idx, m_long_time_format_size;
- quint32 m_standalone_short_month_names_idx, m_standalone_short_month_names_size;
- quint32 m_standalone_long_month_names_idx, m_standalone_long_month_names_size;
- quint32 m_standalone_narrow_month_names_idx, m_standalone_narrow_month_names_size;
- quint32 m_short_month_names_idx, m_short_month_names_size;
- quint32 m_long_month_names_idx, m_long_month_names_size;
- quint32 m_narrow_month_names_idx, m_narrow_month_names_size;
- quint32 m_standalone_short_day_names_idx, m_standalone_short_day_names_size;
- quint32 m_standalone_long_day_names_idx, m_standalone_long_day_names_size;
- quint32 m_standalone_narrow_day_names_idx, m_standalone_narrow_day_names_size;
- quint32 m_short_day_names_idx, m_short_day_names_size;
- quint32 m_long_day_names_idx, m_long_day_names_size;
- quint32 m_narrow_day_names_idx, m_narrow_day_names_size;
- quint32 m_am_idx, m_am_size;
- quint32 m_pm_idx, m_pm_size;
+ quint16 m_short_date_format_idx, m_short_date_format_size;
+ quint16 m_long_date_format_idx, m_long_date_format_size;
+ quint16 m_short_time_format_idx, m_short_time_format_size;
+ quint16 m_long_time_format_idx, m_long_time_format_size;
+ quint16 m_standalone_short_month_names_idx, m_standalone_short_month_names_size;
+ quint16 m_standalone_long_month_names_idx, m_standalone_long_month_names_size;
+ quint16 m_standalone_narrow_month_names_idx, m_standalone_narrow_month_names_size;
+ quint16 m_short_month_names_idx, m_short_month_names_size;
+ quint16 m_long_month_names_idx, m_long_month_names_size;
+ quint16 m_narrow_month_names_idx, m_narrow_month_names_size;
+ quint16 m_standalone_short_day_names_idx, m_standalone_short_day_names_size;
+ quint16 m_standalone_long_day_names_idx, m_standalone_long_day_names_size;
+ quint16 m_standalone_narrow_day_names_idx, m_standalone_narrow_day_names_size;
+ quint16 m_short_day_names_idx, m_short_day_names_size;
+ quint16 m_long_day_names_idx, m_long_day_names_size;
+ quint16 m_narrow_day_names_idx, m_narrow_day_names_size;
+ quint16 m_am_idx, m_am_size;
+ quint16 m_pm_idx, m_pm_size;
};
inline char QLocalePrivate::digitToCLocale(const QChar &in) const
diff --git a/src/corelib/tools/qlocale_symbian.cpp b/src/corelib/tools/qlocale_symbian.cpp
new file mode 100644
index 0000000..2da768b
--- /dev/null
+++ b/src/corelib/tools/qlocale_symbian.cpp
@@ -0,0 +1,879 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDate>
+#include <QLocale>
+#include <QTime>
+#include <QVariant>
+
+#include <e32std.h>
+#include "private/qcore_symbian_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+// Located in qlocale.cpp
+extern void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Country &cntry);
+
+static TExtendedLocale _s60Locale;
+
+// Type definitions for runtime resolved function pointers
+typedef void (*FormatFunc)(TTime&, TDes&, const TDesC&, const TLocale&);
+typedef TPtrC (*FormatSpecFunc)(TExtendedLocale&);
+
+// Runtime resolved functions
+static FormatFunc ptrTimeFormatL = NULL;
+static FormatSpecFunc ptrGetTimeFormatSpec = NULL;
+static FormatSpecFunc ptrGetLongDateFormatSpec = NULL;
+static FormatSpecFunc ptrGetShortDateFormatSpec = NULL;
+
+// Default functions if functions cannot be resolved
+static void defaultTimeFormatL(TTime&, TDes& des, const TDesC&, const TLocale&)
+{
+ des.Zero();
+}
+
+static TPtrC defaultFormatSpec(TExtendedLocale&)
+{
+ return TPtrC(KNullDesC);
+}
+
+/*
+ Definition of struct for mapping Symbian to ISO locale
+*/
+struct symbianToISO {
+ int symbian_language;
+ char iso_name[8];
+};
+
+
+/*
+ Mapping from Symbian to ISO locale
+*/
+static const symbianToISO symbian_to_iso_list[] = {
+ { ELangEnglish, "en_GB" },
+ { ELangFrench, "fr_FR" },
+ { ELangGerman, "de_DE" },
+ { ELangSpanish, "es_ES" },
+ { ELangItalian, "it_IT" },
+ { ELangSwedish, "sv_SE" },
+ { ELangDanish, "da_DK" },
+ { ELangNorwegian, "no_NO" },
+ { ELangFinnish, "fi_FI" },
+ { ELangAmerican, "en_US" },
+ { ELangPortuguese, "pt_PT" },
+ { ELangTurkish, "tr_TR" },
+ { ELangIcelandic, "is_IS" },
+ { ELangRussian, "ru_RU" },
+ { ELangHungarian, "hu_HU" },
+ { ELangDutch, "nl_NL" },
+ { ELangBelgianFlemish, "nl_BE" },
+ { ELangCzech, "cs_CZ" },
+ { ELangSlovak, "sk_SK" },
+ { ELangPolish, "pl_PL" },
+ { ELangSlovenian, "sl_SI" },
+ { ELangTaiwanChinese, "zh_TW" },
+ { ELangHongKongChinese, "zh_HK" },
+ { ELangPrcChinese, "zh_CN" },
+ { ELangJapanese, "ja_JP" },
+ { ELangThai, "th_TH" },
+ { ELangArabic, "ar_AE" },
+ { ELangTagalog, "tl_PH" },
+ { ELangBulgarian, "bg_BG" },
+ { ELangCatalan, "ca_ES" },
+ { ELangCroatian, "hr_HR" },
+ { ELangEstonian, "et_EE" },
+ { ELangFarsi, "fa_IR" },
+ { ELangCanadianFrench, "fr_CA" },
+ { ELangGreek, "el_GR" },
+ { ELangHebrew, "he_IL" },
+ { ELangHindi, "hi_IN" },
+ { ELangIndonesian, "id_ID" },
+ { ELangLatvian, "lv_LV" },
+ { ELangLithuanian, "lt_LT" },
+ { ELangMalay, "ms_MY" },
+ { ELangBrazilianPortuguese, "pt_BR" },
+ { ELangRomanian, "ro_RO" },
+ { ELangSerbian, "sr_YU" },
+ { ELangLatinAmericanSpanish, "es" },
+ { ELangUkrainian, "uk_UA" },
+ { ELangUrdu, "ur_PK" }, // India/Pakistan
+ { ELangVietnamese, "vi_VN" },
+#ifdef __E32LANG_H__
+// 5.0
+ { ELangBasque, "eu_ES" },
+ { ELangGalician, "gl_ES" },
+#endif
+#if !defined(__SERIES60_31__)
+ { ELangEnglish_Apac, "en" },
+ { ELangEnglish_Taiwan, "en_TW" },
+ { ELangEnglish_HongKong, "en_HK" },
+ { ELangEnglish_Prc, "en_CN" },
+ { ELangEnglish_Japan, "en_JP"},
+ { ELangEnglish_Thailand, "en_TH" },
+ { ELangMalay_Apac, "ms" }
+#endif
+};
+
+/*!
+ Returns ISO name corresponding to the Symbian locale code \a sys_fmt.
+*/
+QByteArray qt_symbianLocaleName(int code)
+{
+ //Number of Symbian to ISO locale mappings
+ static const int symbian_to_iso_count
+ = sizeof(symbian_to_iso_list)/sizeof(symbianToISO);
+
+ int cmp = code - symbian_to_iso_list[0].symbian_language;
+ if (cmp < 0)
+ return 0;
+
+ if (cmp == 0)
+ return symbian_to_iso_list[0].iso_name;
+
+ int begin = 0;
+ int end = symbian_to_iso_count;
+
+ while (end - begin > 1) {
+ uint mid = (begin + end)/2;
+
+ const symbianToISO *elt = symbian_to_iso_list + mid;
+ int cmp = code - elt->symbian_language;
+ if (cmp < 0)
+ end = mid;
+ else if (cmp > 0)
+ begin = mid;
+ else
+ return elt->iso_name;
+ }
+
+ return 0;
+}
+
+
+// order is: normal, abbr, nmode, nmode+abbr
+static const char *us_locale_dep[] = {
+ "MM", "dd", "yyyy", "MM", "dd",
+ "M", "d", "yy", "M", "d",
+ "MMMM", "dd", "yyyy", "MMMM", "dd",
+ "MMM", "d", "yy", "MMM", "d" };
+
+static const char *eu_locale_dep[] = {
+ "dd", "MM", "yyyy", "dd", "MM",
+ "d", "M", "yy", "d", "M",
+ "dd", "MMMM", "yyyy", "dd", "MMMM",
+ "d", "MMM", "yy", "d", "MMM" };
+
+static const char *jp_locale_dep[] = {
+ "yyyy", "MM", "dd", "MM", "dd",
+ "yy", "M", "d", "M", "d",
+ "yyyy", "MMMM", "dd", "MMMM", "dd",
+ "yy", "MMM", "d", "MMM", "d" };
+
+/*!
+ Returns a Qt version of the given \a sys_fmt Symbian locale format string.
+*/
+static QString s60ToQtFormat(const QString &sys_fmt)
+{
+ TLocale *locale = _s60Locale.GetLocale();
+
+ QString result;
+ QString other;
+ QString qtformatchars = QString::fromLatin1("adhmsyzAHM");
+
+ QChar c;
+ int i = 0;
+ bool open_escape = false;
+ bool abbrev_next = false;
+ bool locale_indep_ordering = false;
+ bool minus_mode = false;
+ bool plus_mode = false;
+ bool n_mode = false;
+ TTimeFormat tf = locale->TimeFormat();
+
+ while (i < sys_fmt.size()) {
+
+ c = sys_fmt.at(i);
+
+ // let formatting thru
+ if (c.unicode() == '%') {
+ // if we have gathered string, concat it
+ if (!other.isEmpty()) {
+ result += other;
+ other.clear();
+ }
+ // if we have open escape, end it
+ if (open_escape) {
+ result += QLatin1Char('\'');
+ open_escape = false;
+ }
+
+ ++i;
+ if (i >= sys_fmt.size())
+ break;
+
+ c = sys_fmt.at(i);
+
+ // process specials
+ abbrev_next = c.unicode() == '*';
+ plus_mode = c.unicode() == '+';
+ minus_mode = c.unicode() == '-';
+
+ if (abbrev_next || plus_mode || minus_mode) {
+ ++i;
+ if (i >= sys_fmt.size())
+ break;
+
+ c = sys_fmt.at(i);
+
+ if (plus_mode || minus_mode) {
+ // break on undefined plus/minus mode
+ if (c.unicode() != 'A' && c.unicode() != 'B')
+ break;
+ }
+ }
+
+ switch (c.unicode()) {
+ case 'F':
+ {
+ // locale indep mode on
+ locale_indep_ordering = true;
+ break;
+ }
+
+ case '/':
+ {
+ // date sep 0-3
+ ++i;
+ if (i >= sys_fmt.size())
+ break;
+
+ c = sys_fmt.at(i);
+ if (c.isDigit() && c.digitValue() <= 3) {
+ TChar s = locale->DateSeparator(c.digitValue());
+ TUint val = s;
+ // some indexes return zero for empty
+ if (val > 0)
+ result += QChar(val);
+ }
+ break;
+ }
+
+ case 'D':
+ {
+ if (!locale_indep_ordering)
+ break;
+
+ if (!abbrev_next)
+ result += QLatin1String("dd");
+ else
+ result += QLatin1Char('d');
+
+ break;
+ }
+
+ case 'M':
+ {
+ if (!locale_indep_ordering)
+ break;
+
+ if (!n_mode) {
+ if (!abbrev_next)
+ result += QLatin1String("MM");
+ else
+ result += QLatin1String("M");
+ } else {
+ if (!abbrev_next)
+ result += QLatin1String("MMMM");
+ else
+ result += QLatin1String("MMM");
+ }
+
+ break;
+ }
+
+ case 'N':
+ {
+ n_mode = true;
+
+ if (!locale_indep_ordering)
+ break;
+
+ if (!abbrev_next)
+ result += QLatin1String("MMMM");
+ else
+ result += QLatin1String("MMM");
+
+ break;
+ }
+
+ case 'Y':
+ {
+ if (!locale_indep_ordering)
+ break;
+
+ if (!abbrev_next)
+ result += QLatin1String("yyyy");
+ else
+ result += QLatin1String("yy");
+
+ break;
+ }
+
+ case 'E':
+ {
+ if (!abbrev_next)
+ result += QLatin1String("dddd");
+ else
+ result += QLatin1String("ddd");
+
+ break;
+ }
+
+ case ':':
+ {
+ // timesep 0-3
+ ++i;
+ if (i >= sys_fmt.size())
+ break;
+
+ c = sys_fmt.at(i);
+ if (c.isDigit() && c.digitValue() <= 3) {
+ TChar s = locale->TimeSeparator(c.digitValue());
+ TUint val = s;
+ // some indexes return zero for empty
+ if (val > 0)
+ result += QChar(val);
+ }
+
+ break;
+ }
+
+ case 'J':
+ {
+ if (tf == ETime24 && !abbrev_next)
+ result += QLatin1String("hh");
+ else
+ result += QLatin1Char('h');
+
+ break;
+ }
+
+ case 'H':
+ {
+ if (!abbrev_next)
+ result += QLatin1String("hh");
+ else
+ result += QLatin1Char('h');
+
+ break;
+ }
+
+ case 'I':
+ {
+ result += QLatin1Char('h');
+ break;
+ }
+
+ case 'T':
+ {
+ if (!abbrev_next)
+ result += QLatin1String("mm");
+ else
+ result += QLatin1Char('m');
+
+ break;
+ }
+
+ case 'S':
+ {
+ if (!abbrev_next)
+ result += QLatin1String("ss");
+ else
+ result += QLatin1Char('s');
+
+ break;
+ }
+
+ case 'B':
+ {
+ // only done for 12h clock
+ if (tf == ETime24)
+ break;
+ }
+
+ // fallthru to A
+ case 'A': {
+ // quickie to get capitalization, can't use s60 string as is because Qt 'hh' format's am/pm logic
+ TAmPmName ampm = TAmPmName();
+ TChar first(ampm[0]);
+ QString qtampm = QString::fromLatin1(first.IsUpper() ? "AP" : "ap");
+
+ int pos = locale->AmPmSymbolPosition();
+
+ if ((minus_mode && pos != ELocaleBefore) ||
+ (plus_mode && pos != ELocaleAfter))
+ break;
+
+ if (!abbrev_next && locale->AmPmSpaceBetween()) {
+ if (pos == ELocaleBefore)
+ qtampm.append(QLatin1Char(' '));
+ else
+ qtampm.prepend(QLatin1Char(' '));
+ }
+
+ result += qtampm;
+ }
+ break;
+
+ case '.': {
+ // decimal sep
+ TChar s = locale->DecimalSeparator();
+ TUint val = s;
+ if (val > 0)
+ result += QChar(val);
+ }
+ break;
+
+ case 'C':
+ {
+ // six digits in s60, three digits in qt
+ if (!abbrev_next) {
+ result += QLatin1String("zzz");
+ } else {
+ // next char is number from 0-6, how many digits to display
+ ++i;
+ if (i >= sys_fmt.size())
+ break;
+
+ c = sys_fmt.at(i);
+
+ if (c.isDigit()) {
+ // try to match wanted digits
+ QChar val(c.digitValue());
+
+ if (val >= 3) {
+ result += QLatin1String("zzz");
+ } else if (val > 0) {
+ result += QLatin1Char('z');
+ }
+ }
+ }
+ break;
+ }
+
+ // these cases fallthru
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ {
+
+ // shouldn't parse these with %F
+ if (locale_indep_ordering)
+ break;
+
+ TDateFormat df = locale->DateFormat();
+
+ const char **locale_dep;
+ switch (df) {
+ default: // fallthru to american
+ case EDateAmerican:
+ locale_dep = us_locale_dep;
+ break;
+ case EDateEuropean:
+ locale_dep = eu_locale_dep;
+ break;
+ case EDateJapanese:
+ locale_dep = jp_locale_dep;
+ break;
+ }
+ int offset = 0;
+ if (abbrev_next)
+ offset += 5;
+ if (n_mode)
+ offset += 10;
+
+ result += QLatin1String(locale_dep[offset + (c.digitValue()-1)]);
+ break;
+ }
+
+ case '%': // fallthru percent
+ {
+ // any junk gets copied as is
+ }
+ default:
+ {
+ result += c;
+ break;
+ }
+
+ case 'Z': // Qt doesn't support these :(
+ case 'X':
+ case 'W':
+ {
+ break;
+ }
+ }
+ } else {
+ // double any single quotes, don't begin escape
+ if (c.unicode() == '\'') {
+ // end open escape
+ if (open_escape) {
+ result += other;
+ other.clear();
+ result += QLatin1Char('\'');
+ open_escape = false;
+ }
+
+ other += c;
+ }
+
+ // gather chars and escape them in one go if any format chars are found
+ if (!open_escape && qtformatchars.indexOf(c) != -1) {
+ result += QLatin1Char('\'');
+ open_escape = true;
+ }
+ other += c;
+ }
+
+ ++i;
+ }
+
+ if (!other.isEmpty())
+ result += other;
+ if (open_escape)
+ result += QLatin1Char('\'');
+
+ return result;
+}
+
+/*!
+ Retrieves Symbian locale decimal separator.
+*/
+static QString symbianDecimalPoint()
+{
+ TLocale *locale = _s60Locale.GetLocale();
+
+ TChar decPoint = locale->DecimalSeparator();
+ int val = decPoint;
+ return QChar(val);
+}
+
+/*!
+ Retrieves Symbian locale group separator.
+*/
+static QString symbianGroupSeparator()
+{
+ TLocale *locale = _s60Locale.GetLocale();
+
+ TChar grpSep = locale->ThousandsSeparator();
+ int val = grpSep;
+ return QChar(val);
+}
+
+/*!
+ Retrieves Symbian locale zero digit.
+*/
+static QString symbianZeroDigit()
+{
+ TLocale *locale = _s60Locale.GetLocale();
+
+ // TDigitType enumeration value returned by TLocale
+ // will always correspond to zero digit unicode value.
+ TDigitType digit = locale->DigitType();
+ return QChar(digit);
+}
+
+/*!
+ Retrieves a day name from Symbian locale. The \a day is an integer
+ from 1 to 7. When \a short_format is true the method returns
+ the day in short format. Otherwise it returns the day in a long format.
+*/
+static QString symbianDayName(int day, bool short_format)
+{
+ day -= 1;
+
+ if (day < 0 || day > 6)
+ return QString();
+
+ if (short_format) {
+ return qt_TDes2QString(TDayNameAbb(TDay(day)));
+ } else {
+ return qt_TDes2QString(TDayName(TDay(day)));
+ }
+}
+
+/*!
+ Retrieves a month name from Symbian locale. The \a month is an integer
+ from 1 to 12. When \a short_format is true the method returns
+ the month in short format. Otherwise it returns the month in a long format.
+*/
+static QString symbianMonthName(int month, bool short_format)
+{
+ month -= 1;
+ if (month < 0 || month > 11)
+ return QString();
+
+ if (short_format) {
+ return qt_TDes2QString(TMonthNameAbb(TMonth(month)));
+ } else {
+ return qt_TDes2QString(TMonthName(TMonth(month)));
+ }
+}
+
+/*!
+ Retrieves date format from Symbian locale and
+ transforms it to Qt format.
+
+ When \a short_format is true the method returns
+ short date format. Otherwise it returns the long format.
+*/
+static QString symbianDateFormat(bool short_format)
+{
+ TPtrC dateFormat;
+
+ if (short_format) {
+ dateFormat.Set(ptrGetShortDateFormatSpec(_s60Locale));
+ } else {
+ dateFormat.Set(ptrGetLongDateFormatSpec(_s60Locale));
+ }
+
+ return s60ToQtFormat(qt_TDesC2QString(dateFormat));
+}
+
+/*!
+ Retrieves time format from Symbian locale and
+ transforms it to Qt format.
+*/
+static QString symbianTimeFormat()
+{
+ return s60ToQtFormat(qt_TDesC2QString(ptrGetTimeFormatSpec(_s60Locale)));
+}
+
+/*!
+ Returns localized string representation of given \a date
+ formatted with Symbian locale date format.
+
+ If \a short_format is true the format will be a short version.
+ Otherwise it uses a longer version.
+*/
+static QString symbianDateToString(const QDate &date, bool short_format)
+{
+ int month = date.month() - 1;
+ int day = date.day() - 1;
+ int year = date.year();
+
+ TDateTime dateTime;
+ dateTime.Set(year, TMonth(month), day, 0, 0, 0, 0);
+
+ TTime timeStr(dateTime);
+ TBuf<KMaxLongDateFormatSpec*2> buffer;
+
+ TPtrC dateFormat;
+ if (short_format) {
+ dateFormat.Set(ptrGetShortDateFormatSpec(_s60Locale));
+ } else {
+ dateFormat.Set(ptrGetLongDateFormatSpec(_s60Locale));
+ }
+
+ TRAPD(err, ptrTimeFormatL(timeStr, buffer, dateFormat, *_s60Locale.GetLocale());)
+
+ if (err == KErrNone)
+ return qt_TDes2QString(buffer);
+ else
+ return QString();
+}
+
+/*!
+ Returns localized string representation of given \a time
+ formatted with Symbian locale time format.
+*/
+static QString symbianTimeToString(const QTime &time)
+{
+ int hour = time.hour();
+ int minute = time.minute();
+ int second = time.second();
+ int milliseconds = 0;
+
+ TDateTime dateTime;
+ dateTime.Set(0, TMonth(0), 0, hour, minute, second, milliseconds);
+
+ TTime timeStr(dateTime);
+ TBuf<KMaxTimeFormatSpec*2> buffer;
+
+ TRAPD(err, ptrTimeFormatL(
+ timeStr,
+ buffer,
+ ptrGetTimeFormatSpec(_s60Locale),
+ *_s60Locale.GetLocale());
+ )
+
+ if (err == KErrNone)
+ return qt_TDes2QString(buffer);
+ else
+ return QString();
+}
+
+/*!
+ Returns the measurement system stored in Symbian locale
+
+ \sa QLocale::MeasurementSystem
+*/
+static QLocale::MeasurementSystem symbianMeasurementSystem()
+{
+ TLocale *locale = _s60Locale.GetLocale();
+
+ TUnitsFormat unitFormat = locale->UnitsGeneral();
+ if (unitFormat == EUnitsImperial)
+ return QLocale::ImperialSystem;
+ else
+ return QLocale::MetricSystem;
+}
+
+QLocale QSystemLocale::fallbackLocale() const
+{
+ // load system data before query calls
+ static bool initDone = false;
+ if (!initDone) {
+ _s60Locale.LoadSystemSettings();
+
+ // Initialize platform version dependent function pointers
+ ptrTimeFormatL = reinterpret_cast<FormatFunc>
+ (qt_resolveS60PluginFunc(S60Plugin_TimeFormatL));
+ ptrGetTimeFormatSpec = reinterpret_cast<FormatSpecFunc>
+ (qt_resolveS60PluginFunc(S60Plugin_GetTimeFormatSpec));
+ ptrGetLongDateFormatSpec = reinterpret_cast<FormatSpecFunc>
+ (qt_resolveS60PluginFunc(S60Plugin_GetLongDateFormatSpec));
+ ptrGetShortDateFormatSpec = reinterpret_cast<FormatSpecFunc>
+ (qt_resolveS60PluginFunc(S60Plugin_GetShortDateFormatSpec));
+ if (!ptrTimeFormatL)
+ ptrTimeFormatL = &defaultTimeFormatL;
+ if (!ptrGetTimeFormatSpec)
+ ptrGetTimeFormatSpec = &defaultFormatSpec;
+ if (!ptrGetLongDateFormatSpec)
+ ptrGetLongDateFormatSpec = &defaultFormatSpec;
+ if (!ptrGetShortDateFormatSpec)
+ ptrGetShortDateFormatSpec = &defaultFormatSpec;
+ }
+
+ TLanguage lang = User::Language();
+ QString locale = qt_symbianLocaleName(lang);
+ return QLocale(locale);
+}
+
+/*!
+ Generic query method for locale data. Provides indirection.
+ Denotes the \a type of the query
+ with \a in as input data depending on the query.
+
+ \sa QSystemLocale::QueryType
+*/
+QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
+{
+ switch(type) {
+ case DecimalPoint:
+ return symbianDecimalPoint();
+ case GroupSeparator:
+ return symbianGroupSeparator();
+
+ case ZeroDigit:
+ return symbianZeroDigit();
+
+ case DayNameLong:
+ case DayNameShort:
+ return symbianDayName(in.toInt(), (type == DayNameShort) );
+
+ case MonthNameLong:
+ case MonthNameShort:
+ return symbianMonthName(in.toInt(), (type == MonthNameShort) );
+
+ case DateFormatLong:
+ case DateFormatShort:
+ return symbianDateFormat( (type == DateFormatShort) );
+ case TimeFormatLong:
+ case TimeFormatShort:
+ return symbianTimeFormat();
+ case DateTimeFormatLong:
+ case DateTimeFormatShort:
+ return symbianDateFormat( (type == DateTimeFormatShort) ) + QLatin1Char(' ') + symbianTimeFormat();
+ case DateToStringShort:
+ case DateToStringLong:
+ return symbianDateToString(in.toDate(), (type == DateToStringShort) );
+ case TimeToStringShort:
+ case TimeToStringLong:
+ return symbianTimeToString(in.toTime());
+ case DateTimeToStringShort:
+ case DateTimeToStringLong: {
+ const QDateTime dt = in.toDateTime();
+ return symbianDateToString(dt.date(), (type == DateTimeToStringShort) )
+ + QLatin1Char(' ') + symbianTimeToString(dt.time());
+ }
+ case MeasurementSystem:
+ return static_cast<int>(symbianMeasurementSystem());
+ case LanguageId:
+ case CountryId: {
+ TLanguage language = User::Language();
+ QString locale = qt_symbianLocaleName(language);
+ QLocale::Language lang;
+ QLocale::Country cntry;
+ getLangAndCountry(locale, lang, cntry);
+ if (type == LanguageId)
+ return lang;
+ // few iso codes have no country and will use this
+ if (cntry == QLocale::AnyCountry)
+ return fallbackLocale().country();
+
+ return cntry;
+ }
+ case NegativeSign:
+ case PositiveSign:
+ case AMText:
+ case PMText:
+ break;
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp
index 34e093c..abd9b00 100644
--- a/src/corelib/tools/qmap.cpp
+++ b/src/corelib/tools/qmap.cpp
@@ -59,6 +59,7 @@ QMapData QMapData::shared_null = {
QMapData *QMapData::createData()
{
QMapData *d = new QMapData;
+ Q_CHECK_PTR(d);
Node *e = reinterpret_cast<Node *>(d);
e->backward = e;
e->forward[0] = e;
@@ -84,6 +85,18 @@ void QMapData::continueFreeData(int offset)
delete this;
}
+/*!
+ Creates a new node inside the data structure.
+
+ \a update is an array with pointers to the node after which the new node
+ should be inserted. Because of the strange skip list data structure there
+ could be several pointers to this node on different levels.
+ \a offset is an amount of bytes that needs to reserved just before the
+ QMapData::Node structure.
+
+ \internal
+ \since 4.6
+*/
QMapData::Node *QMapData::node_create(Node *update[], int offset)
{
int level = 0;
@@ -94,10 +107,6 @@ QMapData::Node *QMapData::node_create(Node *update[], int offset)
mask <<= Sparseness;
}
- ++randomBits;
- if (level == 3 && !insertInOrder)
- randomBits = qrand();
-
if (level > topLevel) {
Node *e = reinterpret_cast<Node *>(this);
level = ++topLevel;
@@ -105,7 +114,13 @@ QMapData::Node *QMapData::node_create(Node *update[], int offset)
update[level] = e;
}
+ ++randomBits;
+ if (level == 3 && !insertInOrder)
+ randomBits = qrand();
+
void *concreteNode = qMalloc(offset + sizeof(Node) + level * sizeof(Node *));
+ Q_CHECK_PTR(concreteNode);
+
Node *abstractNode = reinterpret_cast<Node *>(reinterpret_cast<char *>(concreteNode) + offset);
abstractNode->backward = update[0];
@@ -146,7 +161,7 @@ uint QMapData::adjust_ptr(Node *node)
void QMapData::dump()
{
- qDebug("Map data (ref = %d, size = %d, randomBits = %#.8x)", ref.atomic, size, randomBits);
+ qDebug("Map data (ref = %d, size = %d, randomBits = %#.8x)", int(ref), size, randomBits);
QString preOutput;
QVector<QString> output(topLevel + 1);
@@ -158,12 +173,12 @@ void QMapData::dump()
Node *update[LastLevel + 1];
for (int i = 0; i <= topLevel; ++i) {
- str.sprintf("%d: [%.8x] -", i, adjust_ptr(forward[i]));
+ str.sprintf("%d: [%.8x] -", i, adjust_ptr(reinterpret_cast<Node *>(forward[i])));
output[i] += str;
- update[i] = forward[i];
+ update[i] = reinterpret_cast<Node *>(forward[i]);
}
- Node *node = forward[0];
+ Node *node = reinterpret_cast<Node *>(forward[0]);
while (node != e) {
int level = 0;
while (level < topLevel && update[level + 1] == node)
@@ -178,13 +193,13 @@ void QMapData::dump()
update[i] = node->forward[i];
}
for (int j = level + 1; j <= topLevel; ++j)
- output[j] += "---------------";
+ output[j] += QLatin1String("---------------");
node = node->forward[0];
}
- qDebug(preOutput.ascii());
+ qDebug("%s", preOutput.ascii());
for (int i = 0; i <= topLevel; ++i)
- qDebug(output[i].ascii());
+ qDebug("%s", output[i].ascii());
}
#endif
@@ -194,7 +209,7 @@ void QMapData::dump()
\ingroup tools
\ingroup shared
- \mainclass
+
\reentrant
QMap\<Key, T\> is one of Qt's generic \l{container classes}. It
@@ -1317,7 +1332,7 @@ void QMapData::dump()
\ingroup tools
\ingroup shared
- \mainclass
+
\reentrant
QMultiMap\<Key, T\> is one of Qt's generic \l{container classes}.
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index b55a046..0c197f6 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -416,9 +416,29 @@ Q_INLINE_TEMPLATE typename QMapData::Node *
QMap<Key, T>::node_create(QMapData *adt, QMapData::Node *aupdate[], const Key &akey, const T &avalue)
{
QMapData::Node *abstractNode = adt->node_create(aupdate, payload());
- Node *concreteNode = concrete(abstractNode);
- new (&concreteNode->key) Key(akey);
- new (&concreteNode->value) T(avalue);
+ QT_TRY {
+ Node *concreteNode = concrete(abstractNode);
+ new (&concreteNode->key) Key(akey);
+ QT_TRY {
+ new (&concreteNode->value) T(avalue);
+ } QT_CATCH(...) {
+ concreteNode->key.~Key();
+ QT_RETHROW;
+ }
+ } QT_CATCH(...) {
+ adt->node_delete(aupdate, payload(), abstractNode);
+ QT_RETHROW;
+ }
+
+ // clean up the update array for further insertions
+ /*
+ for (int i = 0; i <= d->topLevel; ++i) {
+ if ( aupdate[i]==reinterpret_cast<QMapData::Node *>(adt) || aupdate[i]->forward[i] != abstractNode)
+ break;
+ aupdate[i] = abstractNode;
+ }
+*/
+
return abstractNode;
}
@@ -704,8 +724,13 @@ Q_OUTOFLINE_TEMPLATE void QMap<Key, T>::detach_helper()
QMapData::Node *cur = e->forward[0];
update[0] = x.e;
while (cur != e) {
- Node *concreteNode = concrete(cur);
- node_create(x.d, update, concreteNode->key, concreteNode->value);
+ QT_TRY {
+ Node *concreteNode = concrete(cur);
+ node_create(x.d, update, concreteNode->key, concreteNode->value);
+ } QT_CATCH(...) {
+ freeData(x.d);
+ QT_RETHROW;
+ }
cur = cur->forward[0];
}
x.d->insertInOrder = false;
@@ -923,7 +948,8 @@ public:
inline QMultiMap operator+(const QMultiMap &other) const
{ QMultiMap result = *this; result += other; return result; }
-#ifndef Q_NO_USING_KEYWORD
+#if !defined(Q_NO_USING_KEYWORD) && !defined(Q_CC_RVCT)
+ // RVCT compiler doesn't handle using-keyword right when used functions are overloaded in child class
using QMap<Key, T>::contains;
using QMap<Key, T>::remove;
using QMap<Key, T>::count;
@@ -990,10 +1016,15 @@ Q_INLINE_TEMPLATE int QMultiMap<Key, T>::remove(const Key &key, const T &value)
{
int n = 0;
typename QMap<Key, T>::iterator i(find(key));
- typename QMap<Key, T>::const_iterator end(QMap<Key, T>::constEnd());
+ typename QMap<Key, T>::iterator end(QMap<Key, T>::end());
while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
if (i.value() == value) {
+#if defined(Q_CC_RVCT)
+ // RVCT has problems with scoping, apparently.
+ i = QMap<Key, T>::erase(i);
+#else
i = erase(i);
+#endif
++n;
} else {
++i;
diff --git a/src/corelib/tools/qpair.qdoc b/src/corelib/tools/qpair.qdoc
new file mode 100644
index 0000000..2bb0754
--- /dev/null
+++ b/src/corelib/tools/qpair.qdoc
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QPair
+ \brief The QPair class is a template class that stores a pair of items.
+
+ \ingroup tools
+
+ QPair\<T1, T2\> can be used in your application if the STL \c
+ pair type is not available. It stores one value of type T1 and
+ one value of type T2. It can be used as a return value for a
+ function that needs to return two values, or as the value type of
+ a \l{generic container}.
+
+ Here's an example of a QPair that stores one QString and one \c
+ double value:
+
+ \snippet doc/src/snippets/code/doc_src_qpair.qdoc 0
+
+ The components are accessible as public data members called \l
+ first and \l second. For example:
+
+ \snippet doc/src/snippets/code/doc_src_qpair.qdoc 1
+
+ QPair's template data types (T1 and T2) must be \l{assignable
+ data types}. You cannot, for example, store a QWidget as a value;
+ instead, store a QWidget *. A few functions have additional
+ requirements; these requirements are documented on a per-function
+ basis.
+
+ \sa {Generic Containers}
+*/
+
+/*! \typedef QPair::first_type
+
+ The type of the first element in the pair (T1).
+
+ \sa first
+*/
+
+/*! \typedef QPair::second_type
+
+ The type of the second element in the pair (T2).
+
+ \sa second
+*/
+
+/*! \variable QPair::first
+
+ The first element in the pair.
+*/
+
+/*! \variable QPair::second
+
+ The second element in the pair.
+*/
+
+/*! \fn QPair::QPair()
+
+ Constructs an empty pair. The \c first and \c second elements are
+ initialized with \l{default-constructed values}.
+*/
+
+/*!
+ \fn QPair::QPair(const T1 &value1, const T2 &value2)
+
+ Constructs a pair and initializes the \c first element with \a
+ value1 and the \c second element with \a value2.
+
+ \sa qMakePair()
+*/
+
+/*!
+ \fn QPair<T1, T2> &QPair::operator=(const QPair<T1, T2> &other)
+
+ Assigns \a other to this pair.
+*/
+
+/*! \fn bool operator==(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
+
+ \relates QPair
+
+ Returns true if \a p1 is equal to \a p2; otherwise returns false.
+ Two pairs compare equal if their \c first data members compare
+ equal and if their \c second data members compare equal.
+
+ This function requires the T1 and T2 types to have an
+ implementation of \c operator==().
+*/
+
+/*! \fn bool operator!=(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
+
+ \relates QPair
+
+ Returns true if \a p1 is not equal to \a p2; otherwise returns
+ false. Two pairs compare as not equal if their \c first data
+ members are not equal or if their \c second data members are not
+ equal.
+
+ This function requires the T1 and T2 types to have an
+ implementation of \c operator==().
+*/
+
+/*! \fn bool operator<(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
+
+ \relates QPair
+
+ Returns true if \a p1 is less than \a p2; otherwise returns
+ false. The comparison is done on the \c first members of \a p1
+ and \a p2; if they compare equal, the \c second members are
+ compared to break the tie.
+
+ This function requires the T1 and T2 types to have an
+ implementation of \c operator<().
+*/
+
+/*! \fn bool operator>(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
+
+ \relates QPair
+
+ Returns true if \a p1 is greater than \a p2; otherwise returns
+ false. The comparison is done on the \c first members of \a p1
+ and \a p2; if they compare equal, the \c second members are
+ compared to break the tie.
+
+ This function requires the T1 and T2 types to have an
+ implementation of \c operator<().
+*/
+
+/*! \fn bool operator<=(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
+
+ \relates QPair
+
+ Returns true if \a p1 is less than or equal to \a p2; otherwise
+ returns false. The comparison is done on the \c first members of
+ \a p1 and \a p2; if they compare equal, the \c second members are
+ compared to break the tie.
+
+ This function requires the T1 and T2 types to have an
+ implementation of \c operator<().
+*/
+
+/*! \fn bool operator>=(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
+
+ \relates QPair
+
+ Returns true if \a p1 is greater than or equal to \a p2;
+ otherwise returns false. The comparison is done on the \c first
+ members of \a p1 and \a p2; if they compare equal, the \c second
+ members are compared to break the tie.
+
+ This function requires the T1 and T2 types to have an
+ implementation of \c operator<().
+*/
+
+/*!
+ \fn QPair<T1, T2> qMakePair(const T1 &value1, const T2 &value2)
+
+ \relates QPair
+
+ Returns a QPair\<T1, T2\> that contains \a value1 and \a value2.
+ Example:
+
+ \snippet doc/src/snippets/code/doc_src_qpair.qdoc 2
+
+ This is equivalent to QPair<T1, T2>(\a value1, \a value2), but
+ usually requires less typing.
+*/
+
+/*! \fn QDataStream &operator>>(QDataStream &in, QPair<T1, T2> &pair)
+
+ \relates QPair
+
+ Reads a pair from stream \a in into \a pair.
+
+ This function requires the T1 and T2 types to implement \c operator>>().
+
+ \sa {Format of the QDataStream operators}
+*/
+
+/*! \fn QDataStream &operator<<(QDataStream &out, const QPair<T1, T2> &pair)
+
+ \relates QPair
+
+ Writes the pair \a pair to stream \a out.
+
+ This function requires the T1 and T2 types to implement \c operator<<().
+
+ \sa {Format of the QDataStream operators}
+*/
diff --git a/src/corelib/tools/qpodlist_p.h b/src/corelib/tools/qpodlist_p.h
index ddd3d9e..d907f41 100644
--- a/src/corelib/tools/qpodlist_p.h
+++ b/src/corelib/tools/qpodlist_p.h
@@ -53,9 +53,7 @@
// We mean it.
//
-#include <QtCore/qcontainerfwd.h>
-#include <QtCore/qglobal.h>
-#include <new>
+#include <QtCore/qvarlengtharray.h>
QT_BEGIN_HEADER
@@ -63,87 +61,29 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Core)
-template<class T, int Prealloc>
-class QPodList
+template <typename T, int Prealloc>
+class QPodList : public QVarLengthArray<T, Prealloc>
{
+ using QVarLengthArray<T, Prealloc>::s;
+ using QVarLengthArray<T, Prealloc>::a;
+ using QVarLengthArray<T, Prealloc>::ptr;
+ using QVarLengthArray<T, Prealloc>::realloc;
public:
- inline explicit QPodList(int size = 0);
+ inline explicit QPodList(int size = 0)
+ : QVarLengthArray<T, Prealloc>(size)
+ {}
- inline QPodList(const QPodList<T, Prealloc> &other)
- : a(Prealloc), s(0), ptr(reinterpret_cast<T *>(array))
+ inline void insert(int idx, const T &t)
{
- append(other.constData(), other.size());
- }
-
- inline ~QPodList() {
- if (ptr != reinterpret_cast<T *>(array))
- qFree(ptr);
- }
- inline QPodList<T, Prealloc> &operator=(const QPodList<T, Prealloc> &other)
- {
- if (this != &other) {
- clear();
- append(other.constData(), other.size());
- }
- return *this;
- }
-
- inline int size() const { return s; }
- inline int count() const { return s; }
- inline bool isEmpty() const { return (s == 0); }
- inline void resize(int size);
- inline void clear() { resize(0); }
-
- inline int capacity() const { return a; }
- inline void reserve(int size);
-
- inline T &operator[](int idx) {
- Q_ASSERT(idx >= 0 && idx < s);
- return ptr[idx];
- }
- inline const T &operator[](int idx) const {
- Q_ASSERT(idx >= 0 && idx < s);
- return ptr[idx];
- }
-
- inline const T &at(int idx) const {
- Q_ASSERT(idx >= 0 && idx < s);
- return ptr[idx];
- }
-
- inline const T &first() const {
- return at(0);
- }
-
- inline T& append() {
- const int idx = s++;
- if (s == a)
- realloc(s, s<<1);
- return ptr[idx];
- }
- inline void append(const T &t) {
- append() = t;
- }
-
- inline T& insert(int idx) {
- Q_ASSERT(idx >= 0 && idx <= s);
const int sz = s++;
if (s == a)
- realloc(s, s<<1);
+ realloc(s, s << 1);
::memmove(ptr + idx + 1, ptr + idx, (sz - idx) * sizeof(T));
- return ptr[idx];
- }
- inline void insert(int idx, const T &t) {
- insert(idx) = t;
+ ptr[idx] = t;
}
- inline void removeAt(int idx) {
- Q_ASSERT(idx >= 0 && idx < s);
- ::memmove(ptr + idx, ptr + idx + 1, (s - idx - 1) * sizeof(T));
- --s;
- }
-
- inline void removeAll(const T &t) {
+ inline void removeAll(const T &t)
+ {
int i = 0;
for (int j = 0; j < s; ++j) {
if (ptr[j] != t)
@@ -152,110 +92,22 @@ public:
s = i;
}
- inline int indexOf(const T &t, int from = 0) const {
- if (from < 0)
- from = qMax(from + s, 0);
- if (from < s) {
- const T *n = ptr + from - 1;
- const T *e = ptr + s;
- while (++n != e)
- if (*n == t)
- return n - ptr;
- }
- return -1;
- }
-
- inline bool contains(const T &t) const {
- return indexOf(t) >= 0;
+ inline void removeAt(int idx)
+ {
+ Q_ASSERT(idx >= 0 && idx < s);
+ ::memmove(ptr + idx, ptr + idx + 1, (s - idx - 1) * sizeof(T));
+ --s;
}
- inline T takeFirst() {
+ inline T takeFirst()
+ {
Q_ASSERT(s > 0);
T tmp = ptr[0];
removeAt(0);
return tmp;
}
-
- inline T *data() { return ptr; }
- inline const T *data() const { return ptr; }
- inline const T * constData() const { return ptr; }
-
-private:
- void append(const T *buf, int size);
- void realloc(int size, int alloc);
-
- int a;
- int s;
- T *ptr;
- union {
- // ### Qt 5: Use 'Prealloc * sizeof(T)' as array size
- char array[sizeof(qint64) * (((Prealloc * sizeof(T)) / sizeof(qint64)) + 1)];
- qint64 q_for_alignment_1;
- double q_for_alignment_2;
- };
};
-template <class T, int Prealloc>
-Q_INLINE_TEMPLATE QPodList<T, Prealloc>::QPodList(int asize)
- : s(asize) {
- if (s > Prealloc) {
- ptr = reinterpret_cast<T *>(qMalloc(s * sizeof(T)));
- a = s;
- } else {
- ptr = reinterpret_cast<T *>(array);
- a = Prealloc;
- }
-}
-
-template <class T, int Prealloc>
-Q_INLINE_TEMPLATE void QPodList<T, Prealloc>::resize(int asize)
-{ realloc(asize, qMax(asize, a)); }
-
-template <class T, int Prealloc>
-Q_INLINE_TEMPLATE void QPodList<T, Prealloc>::reserve(int asize)
-{ if (asize > a) realloc(s, asize); }
-
-template <class T, int Prealloc>
-Q_OUTOFLINE_TEMPLATE void QPodList<T, Prealloc>::append(const T *abuf, int asize)
-{
- Q_ASSERT(abuf);
- if (asize <= 0)
- return;
-
- const int idx = s;
- const int news = s + asize;
- if (news >= a)
- realloc(news, news<<1);
- else
- s = news;
-
- qMemCopy(&ptr[idx], abuf, asize * sizeof(T));
-}
-
-template <class T, int Prealloc>
-Q_OUTOFLINE_TEMPLATE void QPodList<T, Prealloc>::realloc(int asize, int aalloc)
-{
- Q_ASSERT(aalloc >= asize);
- T *oldPtr = ptr;
- int osize = s;
- s = asize;
-
- if (aalloc != a) {
- ptr = reinterpret_cast<T *>(qMalloc(aalloc * sizeof(T)));
- if (ptr) {
- a = aalloc;
- qMemCopy(ptr, oldPtr, osize * sizeof(T));
- } else {
- ptr = oldPtr;
- s = 0;
- asize = 0;
- }
- }
-
- if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
- qFree(oldPtr);
-}
-
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/corelib/tools/qpoint.cpp b/src/corelib/tools/qpoint.cpp
index cd94aec..f3af5f3 100644
--- a/src/corelib/tools/qpoint.cpp
+++ b/src/corelib/tools/qpoint.cpp
@@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QPoint
- \ingroup multimedia
+ \ingroup painting
\brief The QPoint class defines a point in the plane using integer
precision.
@@ -373,14 +373,14 @@ QDebug operator<<(QDebug dbg, const QPoint &p) {
QDebug operator<<(QDebug d, const QPointF &p)
{
- d.nospace() << "QPointF(" << p.x() << ", " << p.y() << ")";
+ d.nospace() << "QPointF(" << p.x() << ", " << p.y() << ')';
return d;
}
#endif
/*!
\class QPointF
- \ingroup multimedia
+ \ingroup painting
\brief The QPointF class defines a point in the plane using
floating point precision.
@@ -442,6 +442,21 @@ QDebug operator<<(QDebug d, const QPointF &p)
otherwise returns false.
*/
+
+/*!
+ \since 4.6
+
+ Returns the sum of the absolute values of x() and y(),
+ traditionally known as the "Manhattan length" of the vector from
+ the origin to the point.
+
+ \sa QPoint::manhattanLength()
+*/
+qreal QPointF::manhattanLength() const
+{
+ return qAbs(x())+qAbs(y());
+}
+
/*!
\fn qreal QPointF::x() const
diff --git a/src/corelib/tools/qpoint.h b/src/corelib/tools/qpoint.h
index 9bee5ab..3e71055 100644
--- a/src/corelib/tools/qpoint.h
+++ b/src/corelib/tools/qpoint.h
@@ -192,6 +192,8 @@ public:
QPointF(const QPoint &p);
QPointF(qreal xpos, qreal ypos);
+ qreal manhattanLength() const;
+
bool isNull() const;
qreal x() const;
@@ -300,12 +302,12 @@ inline QPointF &QPointF::operator*=(qreal c)
inline bool operator==(const QPointF &p1, const QPointF &p2)
{
- return qFuzzyCompare(p1.xp, p2.xp) && qFuzzyCompare(p1.yp, p2.yp);
+ return qFuzzyIsNull(p1.xp - p2.xp) && qFuzzyIsNull(p1.yp - p2.yp);
}
inline bool operator!=(const QPointF &p1, const QPointF &p2)
{
- return !qFuzzyCompare(p1.xp, p2.xp) || !qFuzzyCompare(p1.yp, p2.yp);
+ return !qFuzzyIsNull(p1.xp - p2.xp) || !qFuzzyIsNull(p1.yp - p2.yp);
}
inline const QPointF operator+(const QPointF &p1, const QPointF &p2)
diff --git a/src/corelib/tools/qqueue.cpp b/src/corelib/tools/qqueue.cpp
index 4edbdf2..2903dbe 100644
--- a/src/corelib/tools/qqueue.cpp
+++ b/src/corelib/tools/qqueue.cpp
@@ -45,7 +45,7 @@
\ingroup tools
\ingroup shared
- \mainclass
+
\reentrant
QQueue\<T\> is one of Qt's generic \l{container classes}. It
diff --git a/src/corelib/tools/qrect.cpp b/src/corelib/tools/qrect.cpp
index 443bcc1..b54ec31 100644
--- a/src/corelib/tools/qrect.cpp
+++ b/src/corelib/tools/qrect.cpp
@@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QRect
- \ingroup multimedia
+ \ingroup painting
\brief The QRect class defines a rectangle in the plane using
integer precision.
@@ -1324,7 +1324,7 @@ QDebug operator<<(QDebug dbg, const QRect &r) {
/*!
\class QRectF
- \ingroup multimedia
+ \ingroup painting
\brief The QRectF class defines a rectangle in the plane using floating
point precision.
diff --git a/src/corelib/tools/qregexp.cpp b/src/corelib/tools/qregexp.cpp
index 5d4b232..2572443 100644
--- a/src/corelib/tools/qregexp.cpp
+++ b/src/corelib/tools/qregexp.cpp
@@ -52,6 +52,7 @@
#include "qstringlist.h"
#include "qstringmatcher.h"
#include "qvector.h"
+#include "private/qfunctions_p.h"
#include <limits.h>
@@ -70,6 +71,8 @@ int qFindString(const QChar *haystack, int haystackLen, int from,
#define RXERR_LEFTDELIM QT_TRANSLATE_NOOP("QRegExp", "missing left delim")
#define RXERR_END QT_TRANSLATE_NOOP("QRegExp", "unexpected end")
#define RXERR_LIMIT QT_TRANSLATE_NOOP("QRegExp", "met internal limit")
+#define RXERR_INTERVAL QT_TRANSLATE_NOOP("QRegExp", "invalid interval")
+#define RXERR_CATEGORY QT_TRANSLATE_NOOP("QRegExp", "invalid category")
/*
WARNING! Be sure to read qregexp.tex before modifying this file.
@@ -81,9 +84,8 @@ int qFindString(const QChar *haystack, int haystackLen, int from,
\brief The QRegExp class provides pattern matching using regular expressions.
\ingroup tools
- \ingroup misc
\ingroup shared
- \mainclass
+
\keyword regular expression
A regular expression, or "regexp", is a pattern for matching
@@ -686,6 +688,10 @@ int qFindString(const QChar *haystack, int haystackLen, int from,
{tools/regexp}{Regular Expression Example}
*/
+#if defined(Q_OS_VXWORKS) && defined(EOS)
+# undef EOS
+#endif
+
const int NumBadChars = 64;
#define BadChar(ch) ((ch).unicode() % NumBadChars)
@@ -827,7 +833,7 @@ struct QRegExpEngineKey
}
};
-bool operator==(const QRegExpEngineKey &key1, const QRegExpEngineKey &key2)
+Q_STATIC_GLOBAL_OPERATOR bool operator==(const QRegExpEngineKey &key1, const QRegExpEngineKey &key2)
{
return key1.pattern == key2.pattern && key1.patternSyntax == key2.patternSyntax
&& key1.cs == key2.cs;
@@ -1116,6 +1122,7 @@ private:
bool valid; // is the regular expression valid?
Qt::CaseSensitivity cs; // case sensitive?
bool greedyQuantifiers; // RegExp2?
+ bool xmlSchemaExtensions;
#ifndef QT_NO_REGEXP_BACKREF
int nbrefs; // number of back-references
#endif
@@ -1193,6 +1200,8 @@ private:
friend class Box;
+ void setupCategoriesRangeMap();
+
/*
This is the lexical analyzer for regular expressions.
*/
@@ -1216,7 +1225,7 @@ private:
int yyPos; // the position of the next character to read
int yyLen; // the length of yyIn
int yyCh; // the last character read
- QRegExpCharClass *yyCharClass; // attribute for Tok_CharClass tokens
+ QScopedPointer<QRegExpCharClass> yyCharClass; // attribute for Tok_CharClass tokens
int yyMinRep; // attribute for Tok_Quantifier
int yyMaxRep; // ditto
QString yyError; // syntax error or overflow during parsing?
@@ -1232,6 +1241,7 @@ private:
int yyTok; // the last token read
bool yyMayCapture; // set this to false to disable capturing
+ QHash<QByteArray, QPair<int, int> > categoriesRangeMap; // fast lookup hash for xml schema extensions
friend struct QRegExpMatchState;
};
@@ -1252,25 +1262,35 @@ struct QRegExpLookahead
};
#endif
-QRegExpEngine::QRegExpEngine(const QRegExpEngineKey &key)
- : cs(key.cs), greedyQuantifiers(key.patternSyntax == QRegExp::RegExp2)
-{
- setup();
+/*! \internal
+ convert the pattern string to the RegExp syntax.
- QString rx;
-
- switch (key.patternSyntax) {
- case QRegExp::Wildcard:
+ This is also used by QScriptEngine::newRegExp to convert to a pattern that JavaScriptCore can understan
+ */
+Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &pattern, QRegExp::PatternSyntax patternSyntax)
+{
+ switch (patternSyntax) {
#ifndef QT_NO_REGEXP_WILDCARD
- rx = wc2rx(key.pattern);
-#endif
+ case QRegExp::Wildcard:
+ return wc2rx(pattern);
break;
+#endif
case QRegExp::FixedString:
- rx = QRegExp::escape(key.pattern);
+ return QRegExp::escape(pattern);
break;
+ case QRegExp::W3CXmlSchema11:
default:
- rx = key.pattern;
+ return pattern;
}
+}
+
+QRegExpEngine::QRegExpEngine(const QRegExpEngineKey &key)
+ : cs(key.cs), greedyQuantifiers(key.patternSyntax == QRegExp::RegExp2),
+ xmlSchemaExtensions(key.patternSyntax == QRegExp::W3CXmlSchema11)
+{
+ setup();
+
+ QString rx = qt_regexp_toCanonical(key.pattern, key.patternSyntax);
valid = (parse(rx.unicode(), rx.length()) == rx.length());
if (!valid) {
@@ -1297,14 +1317,19 @@ void QRegExpMatchState::prepareForMatch(QRegExpEngine *eng)
int ns = eng->s.size(); // number of states
int ncap = eng->ncap;
#ifndef QT_NO_REGEXP_OPTIM
- slideTabSize = qMax(eng->minl + 1, 16);
+ int newSlideTabSize = qMax(eng->minl + 1, 16);
#else
- slideTabSize = 0;
+ int newSlideTabSize = 0;
#endif
int numCaptures = eng->numCaptures();
- capturedSize = 2 + 2 * numCaptures;
- bigArray = (int *)realloc(bigArray, ((3 + 4 * ncap) * ns + 4 * ncap + slideTabSize + capturedSize)*sizeof(int));
+ int newCapturedSize = 2 + 2 * numCaptures;
+ bigArray = q_check_ptr((int *)realloc(bigArray, ((3 + 4 * ncap) * ns + 4 * ncap + newSlideTabSize + newCapturedSize)*sizeof(int)));
+
+ // set all internal variables only _after_ bigArray is realloc'ed
+ // to prevent a broken regexp in oom case
+ slideTabSize = newSlideTabSize;
+ capturedSize = newCapturedSize;
inNextStack = bigArray;
memset(inNextStack, -1, ns * sizeof(int));
curStack = inNextStack + ns;
@@ -1479,9 +1504,8 @@ int QRegExpEngine::anchorAlternation(int a, int b)
return Anchor_Alternation | (n - 1);
#endif
- aa.resize(n + 1);
- aa[n].a = a;
- aa[n].b = b;
+ QRegExpAnchorAlternation element = {a, b};
+ aa.append(element);
return Anchor_Alternation | n;
}
@@ -2621,6 +2645,152 @@ void QRegExpEngine::Box::addAnchorsToEngine(const Box &to) const
}
}
+void QRegExpEngine::setupCategoriesRangeMap()
+{
+ categoriesRangeMap.insert("IsBasicLatin", qMakePair(0x0000, 0x007F));
+ categoriesRangeMap.insert("IsLatin-1Supplement", qMakePair(0x0080, 0x00FF));
+ categoriesRangeMap.insert("IsLatinExtended-A", qMakePair(0x0100, 0x017F));
+ categoriesRangeMap.insert("IsLatinExtended-B", qMakePair(0x0180, 0x024F));
+ categoriesRangeMap.insert("IsIPAExtensions", qMakePair(0x0250, 0x02AF));
+ categoriesRangeMap.insert("IsSpacingModifierLetters", qMakePair(0x02B0, 0x02FF));
+ categoriesRangeMap.insert("IsCombiningDiacriticalMarks", qMakePair(0x0300, 0x036F));
+ categoriesRangeMap.insert("IsGreek", qMakePair(0x0370, 0x03FF));
+ categoriesRangeMap.insert("IsCyrillic", qMakePair(0x0400, 0x04FF));
+ categoriesRangeMap.insert("IsCyrillicSupplement", qMakePair(0x0500, 0x052F));
+ categoriesRangeMap.insert("IsArmenian", qMakePair(0x0530, 0x058F));
+ categoriesRangeMap.insert("IsHebrew", qMakePair(0x0590, 0x05FF));
+ categoriesRangeMap.insert("IsArabic", qMakePair(0x0600, 0x06FF));
+ categoriesRangeMap.insert("IsSyriac", qMakePair(0x0700, 0x074F));
+ categoriesRangeMap.insert("IsArabicSupplement", qMakePair(0x0750, 0x077F));
+ categoriesRangeMap.insert("IsThaana", qMakePair(0x0780, 0x07BF));
+ categoriesRangeMap.insert("IsDevanagari", qMakePair(0x0900, 0x097F));
+ categoriesRangeMap.insert("IsBengali", qMakePair(0x0980, 0x09FF));
+ categoriesRangeMap.insert("IsGurmukhi", qMakePair(0x0A00, 0x0A7F));
+ categoriesRangeMap.insert("IsGujarati", qMakePair(0x0A80, 0x0AFF));
+ categoriesRangeMap.insert("IsOriya", qMakePair(0x0B00, 0x0B7F));
+ categoriesRangeMap.insert("IsTamil", qMakePair(0x0B80, 0x0BFF));
+ categoriesRangeMap.insert("IsTelugu", qMakePair(0x0C00, 0x0C7F));
+ categoriesRangeMap.insert("IsKannada", qMakePair(0x0C80, 0x0CFF));
+ categoriesRangeMap.insert("IsMalayalam", qMakePair(0x0D00, 0x0D7F));
+ categoriesRangeMap.insert("IsSinhala", qMakePair(0x0D80, 0x0DFF));
+ categoriesRangeMap.insert("IsThai", qMakePair(0x0E00, 0x0E7F));
+ categoriesRangeMap.insert("IsLao", qMakePair(0x0E80, 0x0EFF));
+ categoriesRangeMap.insert("IsTibetan", qMakePair(0x0F00, 0x0FFF));
+ categoriesRangeMap.insert("IsMyanmar", qMakePair(0x1000, 0x109F));
+ categoriesRangeMap.insert("IsGeorgian", qMakePair(0x10A0, 0x10FF));
+ categoriesRangeMap.insert("IsHangulJamo", qMakePair(0x1100, 0x11FF));
+ categoriesRangeMap.insert("IsEthiopic", qMakePair(0x1200, 0x137F));
+ categoriesRangeMap.insert("IsEthiopicSupplement", qMakePair(0x1380, 0x139F));
+ categoriesRangeMap.insert("IsCherokee", qMakePair(0x13A0, 0x13FF));
+ categoriesRangeMap.insert("IsUnifiedCanadianAboriginalSyllabics", qMakePair(0x1400, 0x167F));
+ categoriesRangeMap.insert("IsOgham", qMakePair(0x1680, 0x169F));
+ categoriesRangeMap.insert("IsRunic", qMakePair(0x16A0, 0x16FF));
+ categoriesRangeMap.insert("IsTagalog", qMakePair(0x1700, 0x171F));
+ categoriesRangeMap.insert("IsHanunoo", qMakePair(0x1720, 0x173F));
+ categoriesRangeMap.insert("IsBuhid", qMakePair(0x1740, 0x175F));
+ categoriesRangeMap.insert("IsTagbanwa", qMakePair(0x1760, 0x177F));
+ categoriesRangeMap.insert("IsKhmer", qMakePair(0x1780, 0x17FF));
+ categoriesRangeMap.insert("IsMongolian", qMakePair(0x1800, 0x18AF));
+ categoriesRangeMap.insert("IsLimbu", qMakePair(0x1900, 0x194F));
+ categoriesRangeMap.insert("IsTaiLe", qMakePair(0x1950, 0x197F));
+ categoriesRangeMap.insert("IsNewTaiLue", qMakePair(0x1980, 0x19DF));
+ categoriesRangeMap.insert("IsKhmerSymbols", qMakePair(0x19E0, 0x19FF));
+ categoriesRangeMap.insert("IsBuginese", qMakePair(0x1A00, 0x1A1F));
+ categoriesRangeMap.insert("IsPhoneticExtensions", qMakePair(0x1D00, 0x1D7F));
+ categoriesRangeMap.insert("IsPhoneticExtensionsSupplement", qMakePair(0x1D80, 0x1DBF));
+ categoriesRangeMap.insert("IsCombiningDiacriticalMarksSupplement", qMakePair(0x1DC0, 0x1DFF));
+ categoriesRangeMap.insert("IsLatinExtendedAdditional", qMakePair(0x1E00, 0x1EFF));
+ categoriesRangeMap.insert("IsGreekExtended", qMakePair(0x1F00, 0x1FFF));
+ categoriesRangeMap.insert("IsGeneralPunctuation", qMakePair(0x2000, 0x206F));
+ categoriesRangeMap.insert("IsSuperscriptsandSubscripts", qMakePair(0x2070, 0x209F));
+ categoriesRangeMap.insert("IsCurrencySymbols", qMakePair(0x20A0, 0x20CF));
+ categoriesRangeMap.insert("IsCombiningMarksforSymbols", qMakePair(0x20D0, 0x20FF));
+ categoriesRangeMap.insert("IsLetterlikeSymbols", qMakePair(0x2100, 0x214F));
+ categoriesRangeMap.insert("IsNumberForms", qMakePair(0x2150, 0x218F));
+ categoriesRangeMap.insert("IsArrows", qMakePair(0x2190, 0x21FF));
+ categoriesRangeMap.insert("IsMathematicalOperators", qMakePair(0x2200, 0x22FF));
+ categoriesRangeMap.insert("IsMiscellaneousTechnical", qMakePair(0x2300, 0x23FF));
+ categoriesRangeMap.insert("IsControlPictures", qMakePair(0x2400, 0x243F));
+ categoriesRangeMap.insert("IsOpticalCharacterRecognition", qMakePair(0x2440, 0x245F));
+ categoriesRangeMap.insert("IsEnclosedAlphanumerics", qMakePair(0x2460, 0x24FF));
+ categoriesRangeMap.insert("IsBoxDrawing", qMakePair(0x2500, 0x257F));
+ categoriesRangeMap.insert("IsBlockElements", qMakePair(0x2580, 0x259F));
+ categoriesRangeMap.insert("IsGeometricShapes", qMakePair(0x25A0, 0x25FF));
+ categoriesRangeMap.insert("IsMiscellaneousSymbols", qMakePair(0x2600, 0x26FF));
+ categoriesRangeMap.insert("IsDingbats", qMakePair(0x2700, 0x27BF));
+ categoriesRangeMap.insert("IsMiscellaneousMathematicalSymbols-A", qMakePair(0x27C0, 0x27EF));
+ categoriesRangeMap.insert("IsSupplementalArrows-A", qMakePair(0x27F0, 0x27FF));
+ categoriesRangeMap.insert("IsBraillePatterns", qMakePair(0x2800, 0x28FF));
+ categoriesRangeMap.insert("IsSupplementalArrows-B", qMakePair(0x2900, 0x297F));
+ categoriesRangeMap.insert("IsMiscellaneousMathematicalSymbols-B", qMakePair(0x2980, 0x29FF));
+ categoriesRangeMap.insert("IsSupplementalMathematicalOperators", qMakePair(0x2A00, 0x2AFF));
+ categoriesRangeMap.insert("IsMiscellaneousSymbolsandArrows", qMakePair(0x2B00, 0x2BFF));
+ categoriesRangeMap.insert("IsGlagolitic", qMakePair(0x2C00, 0x2C5F));
+ categoriesRangeMap.insert("IsCoptic", qMakePair(0x2C80, 0x2CFF));
+ categoriesRangeMap.insert("IsGeorgianSupplement", qMakePair(0x2D00, 0x2D2F));
+ categoriesRangeMap.insert("IsTifinagh", qMakePair(0x2D30, 0x2D7F));
+ categoriesRangeMap.insert("IsEthiopicExtended", qMakePair(0x2D80, 0x2DDF));
+ categoriesRangeMap.insert("IsSupplementalPunctuation", qMakePair(0x2E00, 0x2E7F));
+ categoriesRangeMap.insert("IsCJKRadicalsSupplement", qMakePair(0x2E80, 0x2EFF));
+ categoriesRangeMap.insert("IsKangxiRadicals", qMakePair(0x2F00, 0x2FDF));
+ categoriesRangeMap.insert("IsIdeographicDescriptionCharacters", qMakePair(0x2FF0, 0x2FFF));
+ categoriesRangeMap.insert("IsCJKSymbolsandPunctuation", qMakePair(0x3000, 0x303F));
+ categoriesRangeMap.insert("IsHiragana", qMakePair(0x3040, 0x309F));
+ categoriesRangeMap.insert("IsKatakana", qMakePair(0x30A0, 0x30FF));
+ categoriesRangeMap.insert("IsBopomofo", qMakePair(0x3100, 0x312F));
+ categoriesRangeMap.insert("IsHangulCompatibilityJamo", qMakePair(0x3130, 0x318F));
+ categoriesRangeMap.insert("IsKanbun", qMakePair(0x3190, 0x319F));
+ categoriesRangeMap.insert("IsBopomofoExtended", qMakePair(0x31A0, 0x31BF));
+ categoriesRangeMap.insert("IsCJKStrokes", qMakePair(0x31C0, 0x31EF));
+ categoriesRangeMap.insert("IsKatakanaPhoneticExtensions", qMakePair(0x31F0, 0x31FF));
+ categoriesRangeMap.insert("IsEnclosedCJKLettersandMonths", qMakePair(0x3200, 0x32FF));
+ categoriesRangeMap.insert("IsCJKCompatibility", qMakePair(0x3300, 0x33FF));
+ categoriesRangeMap.insert("IsCJKUnifiedIdeographsExtensionA", qMakePair(0x3400, 0x4DB5));
+ categoriesRangeMap.insert("IsYijingHexagramSymbols", qMakePair(0x4DC0, 0x4DFF));
+ categoriesRangeMap.insert("IsCJKUnifiedIdeographs", qMakePair(0x4E00, 0x9FFF));
+ categoriesRangeMap.insert("IsYiSyllables", qMakePair(0xA000, 0xA48F));
+ categoriesRangeMap.insert("IsYiRadicals", qMakePair(0xA490, 0xA4CF));
+ categoriesRangeMap.insert("IsModifierToneLetters", qMakePair(0xA700, 0xA71F));
+ categoriesRangeMap.insert("IsSylotiNagri", qMakePair(0xA800, 0xA82F));
+ categoriesRangeMap.insert("IsHangulSyllables", qMakePair(0xAC00, 0xD7A3));
+ categoriesRangeMap.insert("IsPrivateUse", qMakePair(0xE000, 0xF8FF));
+ categoriesRangeMap.insert("IsCJKCompatibilityIdeographs", qMakePair(0xF900, 0xFAFF));
+ categoriesRangeMap.insert("IsAlphabeticPresentationForms", qMakePair(0xFB00, 0xFB4F));
+ categoriesRangeMap.insert("IsArabicPresentationForms-A", qMakePair(0xFB50, 0xFDFF));
+ categoriesRangeMap.insert("IsVariationSelectors", qMakePair(0xFE00, 0xFE0F));
+ categoriesRangeMap.insert("IsVerticalForms", qMakePair(0xFE10, 0xFE1F));
+ categoriesRangeMap.insert("IsCombiningHalfMarks", qMakePair(0xFE20, 0xFE2F));
+ categoriesRangeMap.insert("IsCJKCompatibilityForms", qMakePair(0xFE30, 0xFE4F));
+ categoriesRangeMap.insert("IsSmallFormVariants", qMakePair(0xFE50, 0xFE6F));
+ categoriesRangeMap.insert("IsArabicPresentationForms-B", qMakePair(0xFE70, 0xFEFF));
+ categoriesRangeMap.insert("IsHalfwidthandFullwidthForms", qMakePair(0xFF00, 0xFFEF));
+ categoriesRangeMap.insert("IsSpecials", qMakePair(0xFFF0, 0xFFFF));
+ categoriesRangeMap.insert("IsLinearBSyllabary", qMakePair(0x10000, 0x1007F));
+ categoriesRangeMap.insert("IsLinearBIdeograms", qMakePair(0x10080, 0x100FF));
+ categoriesRangeMap.insert("IsAegeanNumbers", qMakePair(0x10100, 0x1013F));
+ categoriesRangeMap.insert("IsAncientGreekNumbers", qMakePair(0x10140, 0x1018F));
+ categoriesRangeMap.insert("IsOldItalic", qMakePair(0x10300, 0x1032F));
+ categoriesRangeMap.insert("IsGothic", qMakePair(0x10330, 0x1034F));
+ categoriesRangeMap.insert("IsUgaritic", qMakePair(0x10380, 0x1039F));
+ categoriesRangeMap.insert("IsOldPersian", qMakePair(0x103A0, 0x103DF));
+ categoriesRangeMap.insert("IsDeseret", qMakePair(0x10400, 0x1044F));
+ categoriesRangeMap.insert("IsShavian", qMakePair(0x10450, 0x1047F));
+ categoriesRangeMap.insert("IsOsmanya", qMakePair(0x10480, 0x104AF));
+ categoriesRangeMap.insert("IsCypriotSyllabary", qMakePair(0x10800, 0x1083F));
+ categoriesRangeMap.insert("IsKharoshthi", qMakePair(0x10A00, 0x10A5F));
+ categoriesRangeMap.insert("IsByzantineMusicalSymbols", qMakePair(0x1D000, 0x1D0FF));
+ categoriesRangeMap.insert("IsMusicalSymbols", qMakePair(0x1D100, 0x1D1FF));
+ categoriesRangeMap.insert("IsAncientGreekMusicalNotation", qMakePair(0x1D200, 0x1D24F));
+ categoriesRangeMap.insert("IsTaiXuanJingSymbols", qMakePair(0x1D300, 0x1D35F));
+ categoriesRangeMap.insert("IsMathematicalAlphanumericSymbols", qMakePair(0x1D400, 0x1D7FF));
+ categoriesRangeMap.insert("IsCJKUnifiedIdeographsExtensionB", qMakePair(0x20000, 0x2A6DF));
+ categoriesRangeMap.insert("IsCJKCompatibilityIdeographsSupplement", qMakePair(0x2F800, 0x2FA1F));
+ categoriesRangeMap.insert("IsTags", qMakePair(0xE0000, 0xE007F));
+ categoriesRangeMap.insert("IsVariationSelectorsSupplement", qMakePair(0xE0100, 0xE01EF));
+ categoriesRangeMap.insert("IsSupplementaryPrivateUseArea-A", qMakePair(0xF0000, 0xFFFFF));
+ categoriesRangeMap.insert("IsSupplementaryPrivateUseArea-B", qMakePair(0x100000, 0x10FFFF));
+}
+
int QRegExpEngine::getChar()
{
return (yyPos == yyLen) ? EOS : yyIn[yyPos++].unicode();
@@ -2713,6 +2883,177 @@ int QRegExpEngine::getEscape()
yyCharClass->addCategories(0x000f807e);
yyCharClass->addSingleton(0x005f); // '_'
return Tok_CharClass;
+ case 'I':
+ if (xmlSchemaExtensions) {
+ yyCharClass->setNegative(!yyCharClass->negative());
+ // fall through
+ }
+ case 'i':
+ if (xmlSchemaExtensions) {
+ yyCharClass->addCategories(0x000f807e);
+ yyCharClass->addSingleton(0x003a); // ':'
+ yyCharClass->addSingleton(0x005f); // '_'
+ yyCharClass->addRange(0x0041, 0x005a); // [A-Z]
+ yyCharClass->addRange(0x0061, 0x007a); // [a-z]
+ yyCharClass->addRange(0xc0, 0xd6);
+ yyCharClass->addRange(0xd8, 0xf6);
+ yyCharClass->addRange(0xf8, 0x2ff);
+ yyCharClass->addRange(0x370, 0x37d);
+ yyCharClass->addRange(0x37f, 0x1fff);
+ yyCharClass->addRange(0x200c, 0x200d);
+ yyCharClass->addRange(0x2070, 0x218f);
+ yyCharClass->addRange(0x2c00, 0x2fef);
+ yyCharClass->addRange(0x3001, 0xd7ff);
+ yyCharClass->addRange(0xf900, 0xfdcf);
+ yyCharClass->addRange(0xfdf0, 0xfffd);
+ yyCharClass->addRange((ushort)0x10000, (ushort)0xeffff);
+ }
+ return Tok_CharClass;
+ case 'C':
+ if (xmlSchemaExtensions) {
+ yyCharClass->setNegative(!yyCharClass->negative());
+ // fall through
+ }
+ case 'c':
+ if (xmlSchemaExtensions) {
+ yyCharClass->addCategories(0x000f807e);
+ yyCharClass->addSingleton(0x002d); // '-'
+ yyCharClass->addSingleton(0x002e); // '.'
+ yyCharClass->addSingleton(0x003a); // ':'
+ yyCharClass->addSingleton(0x005f); // '_'
+ yyCharClass->addSingleton(0xb7);
+ yyCharClass->addRange(0x0030, 0x0039); // [0-9]
+ yyCharClass->addRange(0x0041, 0x005a); // [A-Z]
+ yyCharClass->addRange(0x0061, 0x007a); // [a-z]
+ yyCharClass->addRange(0xc0, 0xd6);
+ yyCharClass->addRange(0xd8, 0xf6);
+ yyCharClass->addRange(0xf8, 0x2ff);
+ yyCharClass->addRange(0x370, 0x37d);
+ yyCharClass->addRange(0x37f, 0x1fff);
+ yyCharClass->addRange(0x200c, 0x200d);
+ yyCharClass->addRange(0x2070, 0x218f);
+ yyCharClass->addRange(0x2c00, 0x2fef);
+ yyCharClass->addRange(0x3001, 0xd7ff);
+ yyCharClass->addRange(0xf900, 0xfdcf);
+ yyCharClass->addRange(0xfdf0, 0xfffd);
+ yyCharClass->addRange((ushort)0x10000, (ushort)0xeffff);
+ yyCharClass->addRange(0x0300, 0x036f);
+ yyCharClass->addRange(0x203f, 0x2040);
+ }
+ return Tok_CharClass;
+ case 'P':
+ if (xmlSchemaExtensions) {
+ yyCharClass->setNegative(!yyCharClass->negative());
+ // fall through
+ }
+ case 'p':
+ if (xmlSchemaExtensions) {
+ if (yyCh != '{') {
+ error(RXERR_CHARCLASS);
+ return Tok_CharClass;
+ }
+
+ QByteArray category;
+ yyCh = getChar();
+ while (yyCh != '}') {
+ if (yyCh == EOS) {
+ error(RXERR_END);
+ return Tok_CharClass;
+ }
+ category.append(yyCh);
+ yyCh = getChar();
+ }
+ yyCh = getChar(); // skip closing '}'
+
+ if (category == "M") {
+ yyCharClass->addCategories(0x0000000e);
+ } else if (category == "Mn") {
+ yyCharClass->addCategories(0x00000002);
+ } else if (category == "Mc") {
+ yyCharClass->addCategories(0x00000004);
+ } else if (category == "Me") {
+ yyCharClass->addCategories(0x00000008);
+ } else if (category == "N") {
+ yyCharClass->addCategories(0x00000070);
+ } else if (category == "Nd") {
+ yyCharClass->addCategories(0x00000010);
+ } else if (category == "Nl") {
+ yyCharClass->addCategories(0x00000020);
+ } else if (category == "No") {
+ yyCharClass->addCategories(0x00000040);
+ } else if (category == "Z") {
+ yyCharClass->addCategories(0x00000380);
+ } else if (category == "Zs") {
+ yyCharClass->addCategories(0x00000080);
+ } else if (category == "Zl") {
+ yyCharClass->addCategories(0x00000100);
+ } else if (category == "Zp") {
+ yyCharClass->addCategories(0x00000200);
+ } else if (category == "C") {
+ yyCharClass->addCategories(0x00006c00);
+ } else if (category == "Cc") {
+ yyCharClass->addCategories(0x00000400);
+ } else if (category == "Cf") {
+ yyCharClass->addCategories(0x00000800);
+ } else if (category == "Cs") {
+ yyCharClass->addCategories(0x00001000);
+ } else if (category == "Co") {
+ yyCharClass->addCategories(0x00002000);
+ } else if (category == "Cn") {
+ yyCharClass->addCategories(0x00004000);
+ } else if (category == "L") {
+ yyCharClass->addCategories(0x000f8000);
+ } else if (category == "Lu") {
+ yyCharClass->addCategories(0x00008000);
+ } else if (category == "Ll") {
+ yyCharClass->addCategories(0x00010000);
+ } else if (category == "Lt") {
+ yyCharClass->addCategories(0x00020000);
+ } else if (category == "Lm") {
+ yyCharClass->addCategories(0x00040000);
+ } else if (category == "Lo") {
+ yyCharClass->addCategories(0x00080000);
+ } else if (category == "P") {
+ yyCharClass->addCategories(0x4f580780);
+ } else if (category == "Pc") {
+ yyCharClass->addCategories(0x00100000);
+ } else if (category == "Pd") {
+ yyCharClass->addCategories(0x00200000);
+ } else if (category == "Ps") {
+ yyCharClass->addCategories(0x00400000);
+ } else if (category == "Pe") {
+ yyCharClass->addCategories(0x00800000);
+ } else if (category == "Pi") {
+ yyCharClass->addCategories(0x01000000);
+ } else if (category == "Pf") {
+ yyCharClass->addCategories(0x02000000);
+ } else if (category == "Po") {
+ yyCharClass->addCategories(0x04000000);
+ } else if (category == "S") {
+ yyCharClass->addCategories(0x78000000);
+ } else if (category == "Sm") {
+ yyCharClass->addCategories(0x08000000);
+ } else if (category == "Sc") {
+ yyCharClass->addCategories(0x10000000);
+ } else if (category == "Sk") {
+ yyCharClass->addCategories(0x20000000);
+ } else if (category == "So") {
+ yyCharClass->addCategories(0x40000000);
+ } else if (category.startsWith("Is")) {
+ if (categoriesRangeMap.isEmpty())
+ setupCategoriesRangeMap();
+
+ if (categoriesRangeMap.contains(category)) {
+ const QPair<int, int> range = categoriesRangeMap.value(category);
+ yyCharClass->addRange(range.first, range.second);
+ } else {
+ error(RXERR_CATEGORY);
+ }
+ } else {
+ error(RXERR_CATEGORY);
+ }
+ }
+ return Tok_CharClass;
#endif
#ifndef QT_NO_REGEXP_ESCAPE
case 'x':
@@ -2789,7 +3130,7 @@ void QRegExpEngine::startTokenizer(const QChar *rx, int len)
yyPos = 0;
yyLen = len;
yyCh = getChar();
- yyCharClass = new QRegExpCharClass;
+ yyCharClass.reset(new QRegExpCharClass);
yyMinRep = 0;
yyMaxRep = 0;
yyError = QString();
@@ -2934,7 +3275,7 @@ int QRegExpEngine::getToken()
yyMaxRep = getRep(InftyRep);
}
if (yyMaxRep < yyMinRep)
- qSwap(yyMinRep, yyMaxRep);
+ error(RXERR_INTERVAL);
if (yyCh != '}')
error(RXERR_REPETITION);
yyCh = getChar();
@@ -2983,8 +3324,7 @@ int QRegExpEngine::parse(const QChar *pattern, int len)
#endif
box.cat(middleBox);
box.cat(rightBox);
- delete yyCharClass;
- yyCharClass = 0;
+ yyCharClass.reset(0);
#ifndef QT_NO_REGEXP_CAPTURE
for (int i = 0; i < nf; ++i) {
@@ -3281,10 +3621,15 @@ static void derefEngine(QRegExpEngine *eng, const QRegExpEngineKey &key)
#if !defined(QT_NO_REGEXP_OPTIM)
if (globalEngineCache()) {
QMutexLocker locker(mutex());
- globalEngineCache()->insert(key, eng, 4 + key.pattern.length() / 4);
- }
- else
+ QT_TRY {
+ globalEngineCache()->insert(key, eng, 4 + key.pattern.length() / 4);
+ } QT_CATCH(const std::bad_alloc &) {
+ // in case of an exception (e.g. oom), just delete the engine
+ delete eng;
+ }
+ } else {
delete eng;
+ }
#else
Q_UNUSED(key);
delete eng;
@@ -3374,6 +3719,9 @@ static void invalidateEngine(QRegExpPrivate *priv)
equivalent to using the RegExp pattern on a string in
which all metacharacters are escaped using escape().
+ \value W3CXmlSchema11 The pattern is a regular expression as
+ defined by the W3C XML Schema 1.1 specification.
+
\sa setPatternSyntax()
*/
@@ -4065,6 +4413,6 @@ QDataStream &operator>>(QDataStream &in, QRegExp &regExp)
regExp = newRegExp;
return in;
}
-#endif
+#endif // QT_NO_DATASTREAM
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qregexp.h b/src/corelib/tools/qregexp.h
index d2bdd7e..30f0949 100644
--- a/src/corelib/tools/qregexp.h
+++ b/src/corelib/tools/qregexp.h
@@ -61,7 +61,7 @@ class QStringList;
class Q_CORE_EXPORT QRegExp
{
public:
- enum PatternSyntax { RegExp, Wildcard, FixedString, RegExp2 };
+ enum PatternSyntax { RegExp, Wildcard, FixedString, RegExp2, W3CXmlSchema11 };
enum CaretMode { CaretAtZero, CaretAtOffset, CaretWontMatch };
QRegExp();
diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h
index 75cbb1f..544ea1a 100644
--- a/src/corelib/tools/qringbuffer_p.h
+++ b/src/corelib/tools/qringbuffer_p.h
@@ -58,7 +58,7 @@
QT_BEGIN_NAMESPACE
-class Q_CORE_EXPORT QRingBuffer
+class QRingBuffer
{
public:
inline QRingBuffer(int growth = 4096) : basicBlockSize(growth) {
@@ -74,6 +74,52 @@ public:
return buffers.isEmpty() ? 0 : (buffers.first().constData() + head);
}
+ // access the bytes at a specified position
+ // the out-variable length will contain the amount of bytes readable
+ // from there, e.g. the amount still the same QByteArray
+ inline const char *readPointerAtPosition(qint64 pos, qint64 &length) const {
+ if (buffers.isEmpty()) {
+ length = 0;
+ return 0;
+ }
+
+ if (pos >= bufferSize) {
+ length = 0;
+ return 0;
+ }
+
+ // special case: it is in the first buffer
+ int nextDataBlockSizeValue = nextDataBlockSize();
+ if (pos - head < nextDataBlockSizeValue) {
+ length = nextDataBlockSizeValue - pos;
+ return buffers.at(0).constData() + head + pos;
+ }
+
+ // special case: we only had one buffer and tried to read over it
+ if (buffers.length() == 1) {
+ length = 0;
+ return 0;
+ }
+
+ // skip the first
+ pos -= nextDataBlockSizeValue;
+
+ // normal case: it is somewhere in the second to the-one-before-the-tailBuffer
+ for (int i = 1; i < tailBuffer; i++) {
+ if (pos >= buffers[i].size()) {
+ pos -= buffers[i].size();
+ continue;
+ }
+
+ length = buffers[i].length() - pos;
+ return buffers[i].constData() + pos;
+ }
+
+ // it is in the tail buffer
+ length = tail - pos;
+ return buffers[tailBuffer].constData() + pos;
+ }
+
inline void free(int bytes) {
bufferSize -= bytes;
if (bufferSize < 0)
@@ -199,9 +245,7 @@ public:
inline void clear() {
if(!buffers.isEmpty()) {
- QByteArray tmp = buffers[0];
- buffers.clear();
- buffers << tmp;
+ buffers.erase(buffers.begin() + 1, buffers.end());
if (buffers.at(0).size() != basicBlockSize)
buffers[0].resize(basicBlockSize);
}
@@ -255,6 +299,54 @@ public:
return read(size());
}
+ // read an unspecified amount (will read the first buffer)
+ inline QByteArray read() {
+ if (bufferSize == 0)
+ return QByteArray();
+
+ // multiple buffers, just take the first one
+ if (head == 0 && tailBuffer != 0) {
+ QByteArray qba = buffers.takeFirst();
+ --tailBuffer;
+ bufferSize -= qba.length();
+ return qba;
+ }
+
+ // one buffer with good value for head. Just take it.
+ if (head == 0 && tailBuffer == 0) {
+ QByteArray qba = buffers.takeFirst();
+ qba.resize(tail);
+ buffers << QByteArray();
+ bufferSize = 0;
+ tail = 0;
+ return qba;
+ }
+
+ // Bad case: We have to memcpy.
+ // We can avoid by initializing the QRingBuffer with basicBlockSize of 0
+ // and only using this read() function.
+ QByteArray qba(readPointer(), nextDataBlockSize());
+ buffers.removeFirst();
+ head = 0;
+ if (tailBuffer == 0) {
+ buffers << QByteArray();
+ tail = 0;
+ } else {
+ --tailBuffer;
+ }
+ bufferSize -= qba.length();
+ return qba;
+ }
+
+ // append a new buffer to the end
+ inline void append(const QByteArray &qba) {
+ buffers[tailBuffer].resize(tail);
+ buffers << qba;
+ ++tailBuffer;
+ tail = qba.length();
+ bufferSize += qba.length();
+ }
+
inline QByteArray peek(int maxLength) const {
int bytesToRead = qMin(size(), maxLength);
if(maxLength <= 0)
@@ -309,7 +401,7 @@ public:
private:
QList<QByteArray> buffers;
int head, tail;
- int tailBuffer;
+ int tailBuffer; // always buffers.size() - 1
int basicBlockSize;
int bufferSize;
};
diff --git a/src/corelib/tools/qscopedpointer.cpp b/src/corelib/tools/qscopedpointer.cpp
new file mode 100644
index 0000000..5296bae
--- /dev/null
+++ b/src/corelib/tools/qscopedpointer.cpp
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscopedpointer.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QScopedPointer
+ \brief The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon destruction.
+ \since 4.6
+ \reentrant
+ \ingroup misc
+
+ Managing heap allocated objects manually is hard and error prone, with the
+ common result that code leaks memory and is hard to maintain.
+ QScopedPointer is a small utility class that heavily simplifies this by
+ assigning stack-based memory ownership to heap allocations, more generally
+ called resource acquisition is initialization(RAII).
+
+ QScopedPointer guarantees that the object pointed to will get deleted when
+ the current scope dissapears.
+
+ Consider this function which does heap allocations, and have various exit points:
+
+ \snippet doc/src/snippets/code/src_corelib_tools_qscopedpointer.cpp 0
+
+ It's encumbered by the manual delete calls. With QScopedPointer, the code
+ can be simplified to:
+
+ \snippet doc/src/snippets/code/src_corelib_tools_qscopedpointer.cpp 1
+
+ The code the compiler generates for QScopedPointer is the same as when
+ writing it manually. Code that makes use of \a delete are candidates for
+ QScopedPointer usage (and if not, possibly another type of smart pointer
+ such as QSharedPointer). QScopedPointer intentionally has no copy
+ constructor or assignment operator, such that ownership and lifetime is
+ clearly communicated.
+
+ The const qualification on a regular C++ pointer can also be expressed with
+ a QScopedPointer:
+
+ \snippet doc/src/snippets/code/src_corelib_tools_qscopedpointer.cpp 2
+
+ \section1 Custom cleanup handlers
+
+ Arrays as well as pointers that have been allocated with \c malloc must
+ not be deleted using \c delete. QScopedPointer's second template parameter
+ can be used for custom cleanup handlers.
+
+ The following custom cleanup handlers exist:
+
+ \list
+ \i QScopedPointerDeleter - the default, deletes the pointer using \c delete
+ \i QScopedPointerArrayDeleter - deletes the pointer using \c{delete []}. Use
+ this handler for pointers that were allocated with \c{new []}.
+ \i QScopedPointerPodDeleter - deletes the pointer using \c{free()}. Use this
+ handler for pointers that were allocated with \c{malloc()}.
+ \endlist
+
+ You can pass your own classes as handlers, provided that they have a public
+ static function \c{void cleanup(T *pointer)}.
+
+ \snippet doc/src/snippets/code/src_corelib_tools_qscopedpointer.cpp 5
+
+ \section1 Forward Declared Pointers
+
+ Classes that are forward declared can be used within QScopedPointer, as
+ long as the destructor of the forward declared class is available whenever
+ a QScopedPointer needs to clean up.
+
+ Concretely, this means that all classes containing a QScopedPointer that
+ points to a forward declared class must have non-inline constructors,
+ destructors and assignment operators:
+
+ \snippet doc/src/snippets/code/src_corelib_tools_qscopedpointer.cpp 4
+
+ Otherwise, the compiler output a warning about not being able to destruct
+ \c MyPrivateClass.
+
+ \sa QSharedPointer
+*/
+
+/*!
+ \fn QScopedPointer::QScopedPointer(T *p = 0)
+
+ Constructs this QScopedPointer instance and sets its pointer to \a p.
+*/
+
+/*!
+ \fn QScopedPointer::~QScopedPointer()
+
+ Destroys this QScopedPointer object. Delete the object its pointer points
+ to.
+*/
+
+/*!
+ \fn T *QScopedPointer::data() const
+
+ Returns the value of the pointer referenced by this object. QScopedPointer
+ still owns the object pointed to.
+*/
+
+/*!
+ \fn T &QScopedPointer::operator*() const
+
+ Provides access to the scoped pointer's object.
+
+ If the contained pointer is \c null, behavior is undefined.
+ \sa isNull()
+*/
+
+/*!
+ \fn T *QScopedPointer::operator->() const
+
+ Provides access to the scoped pointer's object.
+
+ If the contained pointer is \c null, behavior is undefined.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn QScopedPointer::operator bool() const
+
+ Returns \c true if this object is not \c null. This function is suitable
+ for use in \tt if-constructs, like:
+
+ \snippet doc/src/snippets/code/src_corelib_tools_qscopedpointer.cpp 3
+
+ \sa isNull()
+*/
+
+/*!
+ \fn bool QScopedPointer::operator==(const QScopedPointer<T, Cleanup> &other) const
+
+ Equality operator. Returns true if the scoped pointer \a other
+ is pointing to the same object as this pointer, otherwise returns false.
+*/
+
+
+/*!
+ \fn bool QScopedPointer::operator!=(const QScopedPointer<T, Cleanup> &other) const
+
+ Inequality operator. Returns true if the scoped pointer \a other
+ is not pointing to the same object as this pointer, otherwise returns false.
+*/
+
+/*!
+ \fn bool QScopedPointer::isNull() const
+
+ Returns \c true if this object is holding a pointer that is \c null.
+*/
+
+/*!
+ \fn void QScopedPointer::reset(T *other = 0)
+
+ Deletes the existing object it is pointing to if any, and sets its pointer to
+ \a other. QScopedPointer now owns \a other and will delete it in its
+ destructor.
+*/
+
+/*!
+ \fn T *QScopedPointer::take()
+
+ Returns the value of the pointer referenced by this object. The pointer of this
+ QScopedPointer object will be reset to \c null.
+
+ Callers of this function take ownership of the pointer.
+*/
+
+/*! \fn bool QScopedPointer::operator!() const
+
+ Returns \c true if the pointer referenced by this object is \c null, otherwise
+ returns \c false.
+
+ \sa isNull()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qscopedpointer.h b/src/corelib/tools/qscopedpointer.h
new file mode 100644
index 0000000..f801366
--- /dev/null
+++ b/src/corelib/tools/qscopedpointer.h
@@ -0,0 +1,307 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCOPEDPOINTER_H
+#define QSCOPEDPOINTER_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+QT_MODULE(Core)
+
+template <typename T>
+struct QScopedPointerDeleter
+{
+ static inline void cleanup(T *pointer)
+ {
+ // Enforce a complete type.
+ // If you get a compile error here, read the secion on forward declared
+ // classes in the QScopedPointer documentation.
+ typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ];
+ (void) sizeof(IsIncompleteType);
+
+ delete pointer;
+ }
+};
+
+template <typename T>
+struct QScopedPointerArrayDeleter
+{
+ static inline void cleanup(T *pointer)
+ {
+ // Enforce a complete type.
+ // If you get a compile error here, read the secion on forward declared
+ // classes in the QScopedPointer documentation.
+ typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ];
+ (void) sizeof(IsIncompleteType);
+
+ delete [] pointer;
+ }
+};
+
+struct QScopedPointerPodDeleter
+{
+ static inline void cleanup(void *pointer) { if (pointer) qFree(pointer); }
+};
+
+template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
+class QScopedPointer
+{
+#ifndef Q_CC_NOKIAX86
+ typedef T *QScopedPointer:: *RestrictedBool;
+#endif
+public:
+ explicit inline QScopedPointer(T *p = 0) : d(p)
+ {
+ }
+
+ inline ~QScopedPointer()
+ {
+ T *oldD = this->d;
+ Cleanup::cleanup(oldD);
+ this->d = 0;
+ }
+
+ inline T &operator*() const
+ {
+ Q_ASSERT(d);
+ return *d;
+ }
+
+ inline T *operator->() const
+ {
+ Q_ASSERT(d);
+ return d;
+ }
+
+ inline bool operator==(const QScopedPointer<T, Cleanup> &other) const
+ {
+ return d == other.d;
+ }
+
+ inline bool operator!=(const QScopedPointer<T, Cleanup> &other) const
+ {
+ return d != other.d;
+ }
+
+ inline bool operator!() const
+ {
+ return !d;
+ }
+
+#if defined(Q_CC_NOKIAX86) || defined(Q_QDOC)
+ inline operator bool() const
+ {
+ return isNull() ? 0 : &QScopedPointer::d;
+ }
+#else
+ inline operator RestrictedBool() const
+ {
+ return isNull() ? 0 : &QScopedPointer::d;
+ }
+#endif
+
+ inline T *data() const
+ {
+ return d;
+ }
+
+ inline bool isNull() const
+ {
+ return !d;
+ }
+
+ inline void reset(T *other = 0)
+ {
+ if (d == other)
+ return;
+ T *oldD = d;
+ d = other;
+ Cleanup::cleanup(oldD);
+ }
+
+ inline T *take()
+ {
+ T *oldD = d;
+ d = 0;
+ return oldD;
+ }
+
+ inline void swap(QScopedPointer<T, Cleanup> &other)
+ {
+ qSwap(d, other.d);
+ }
+
+ typedef T *pointer;
+
+protected:
+ T *d;
+
+private:
+ Q_DISABLE_COPY(QScopedPointer)
+};
+
+template <class T, class Cleanup>
+Q_INLINE_TEMPLATE void qSwap(QScopedPointer<T, Cleanup> &p1, QScopedPointer<T, Cleanup> &p2)
+{ p1.swap(p2); }
+
+template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> >
+class QScopedArrayPointer : public QScopedPointer<T, Cleanup>
+{
+public:
+ explicit inline QScopedArrayPointer(T *p = 0)
+ : QScopedPointer<T, Cleanup>(p)
+ {
+ }
+
+ inline T &operator[](int i)
+ {
+ return this->d[i];
+ }
+
+ inline const T &operator[](int i) const
+ {
+ return this->d[i];
+ }
+
+ inline bool operator==(const QScopedArrayPointer<T, Cleanup> &other) const
+ {
+ return this->d == other.d;
+ }
+
+ inline bool operator!=(const QScopedArrayPointer<T, Cleanup> &other) const
+ {
+ return this->d != other.d;
+ }
+
+private:
+ Q_DISABLE_COPY(QScopedArrayPointer)
+};
+
+/* Internal helper class - exposes the data through data_ptr (legacy from QShared).
+ Required for some internal Qt classes, do not use otherwise. */
+template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
+class QCustomScopedPointer : public QScopedPointer<T, Cleanup>
+{
+public:
+ explicit inline QCustomScopedPointer(T *p = 0)
+ : QScopedPointer<T, Cleanup>(p)
+ {
+ }
+
+ inline T *&data_ptr()
+ {
+ return this->d;
+ }
+
+ inline bool operator==(const QCustomScopedPointer<T, Cleanup> &other) const
+ {
+ return this->d == other.d;
+ }
+
+ inline bool operator!=(const QCustomScopedPointer<T, Cleanup> &other) const
+ {
+ return this->d != other.d;
+ }
+
+private:
+ Q_DISABLE_COPY(QCustomScopedPointer)
+};
+
+/* Internal helper class - a handler for QShared* classes, to be used in QCustomScopedPointer */
+template <typename T>
+class QScopedPointerSharedDeleter
+{
+public:
+ static inline void cleanup(T *d)
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ }
+};
+
+/* Internal.
+ This class is basically a scoped pointer pointing to a ref-counted object
+ */
+template <typename T>
+class QScopedSharedPointer : public QCustomScopedPointer<T, QScopedPointerSharedDeleter<T> >
+{
+public:
+ explicit inline QScopedSharedPointer(T *p = 0)
+ : QCustomScopedPointer<T, QScopedPointerSharedDeleter<T> >(p)
+ {
+ }
+
+ inline void detach()
+ {
+ qAtomicDetach(this->d);
+ }
+
+ inline void assign(T *other)
+ {
+ if (this->d == other)
+ return;
+ if (other)
+ other->ref.ref();
+ T *oldD = this->d;
+ this->d = other;
+ QScopedPointerSharedDeleter<T>::cleanup(oldD);
+ }
+
+ inline bool operator==(const QScopedSharedPointer<T> &other) const
+ {
+ return this->d == other.d;
+ }
+
+ inline bool operator!=(const QScopedSharedPointer<T> &other) const
+ {
+ return this->d != other.d;
+ }
+
+private:
+ Q_DISABLE_COPY(QScopedSharedPointer)
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // QSCOPEDPOINTER_H
diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h
index 0497782..18083d7 100644
--- a/src/corelib/tools/qset.h
+++ b/src/corelib/tools/qset.h
@@ -85,6 +85,8 @@ public:
inline bool contains(const T &value) const { return q_hash.contains(value); }
+ bool contains(const QSet<T> &set) const;
+
class const_iterator;
class iterator
@@ -274,6 +276,18 @@ Q_INLINE_TEMPLATE QSet<T> &QSet<T>::subtract(const QSet<T> &other)
return *this;
}
+template <class T>
+Q_INLINE_TEMPLATE bool QSet<T>::contains(const QSet<T> &other) const
+{
+ typename QSet<T>::const_iterator i = other.constBegin();
+ while (i != other.constEnd()) {
+ if (!contains(*i))
+ return false;
+ ++i;
+ }
+ return true;
+}
+
template <typename T>
Q_OUTOFLINE_TEMPLATE QList<T> QSet<T>::toList() const
{
diff --git a/src/corelib/tools/qset.qdoc b/src/corelib/tools/qset.qdoc
new file mode 100644
index 0000000..6e83b43
--- /dev/null
+++ b/src/corelib/tools/qset.qdoc
@@ -0,0 +1,953 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QSet
+ \brief The QSet class is a template class that provides a hash-table-based set.
+
+ \ingroup tools
+ \ingroup shared
+ \reentrant
+
+
+ QSet<T> is one of Qt's generic \l{container classes}. It stores
+ values in an unspecified order and provides very fast lookup of
+ the values. Internally, QSet<T> is implemented as a QHash.
+
+ Here's an example QSet with QString values:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 0
+
+ To insert a value into the set, use insert():
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 1
+
+ Another way to insert items into the set is to use operator<<():
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 2
+
+ To test whether an item belongs to the set or not, use contains():
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 3
+
+ If you want to navigate through all the values stored in a QSet,
+ you can use an iterator. QSet supports both \l{Java-style
+ iterators} (QSetIterator and QMutableSetIterator) and \l{STL-style
+ iterators} (QSet::iterator and QSet::const_iterator). Here's how
+ to iterate over a QSet<QWidget *> using a Java-style iterator:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 4
+
+ Here's the same code, but using an STL-style iterator:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 5
+
+ QSet is unordered, so an iterator's sequence cannot be assumed to
+ be predictable. If ordering by key is required, use a QMap.
+
+ To navigate through a QSet, you can also use \l{foreach}:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 6
+
+ Items can be removed from the set using remove(). There is also a
+ clear() function that removes all items.
+
+ QSet's value data type must be an \l{assignable data type}. You
+ cannot, for example, store a QWidget as a value; instead, store a
+ QWidget *. In addition, the type must provide \c operator==(), and
+ there must also be a global qHash() function that returns a hash
+ value for an argument of the key's type. See the QHash
+ documentation for a list of types supported by qHash().
+
+ Internally, QSet uses a hash table to perform lookups. The hash
+ table automatically grows and shrinks to provide fast lookups
+ without wasting memory. You can still control the size of the hash
+ table by calling reserve(), if you already know approximately how
+ many elements the QSet will contain, but this isn't necessary to
+ obtain good performance. You can also call capacity() to retrieve
+ the hash table's size.
+
+ \sa QSetIterator, QMutableSetIterator, QHash, QMap
+*/
+
+/*!
+ \fn QSet::QSet()
+
+ Constructs an empty set.
+
+ \sa clear()
+*/
+
+/*!
+ \fn QSet::QSet(const QSet<T> &other)
+
+ Constructs a copy of \a other.
+
+ This operation occurs in \l{constant time}, because QSet is
+ \l{implicitly shared}. This makes returning a QSet from a
+ function very fast. If a shared instance is modified, it will be
+ copied (copy-on-write), and this takes \l{linear time}.
+
+ \sa operator=()
+*/
+
+/*!
+ \fn QSet<T> &QSet::operator=(const QSet<T> &other)
+
+ Assigns the \a other set to this set and returns a reference to
+ this set.
+*/
+
+/*!
+ \fn bool QSet::operator==(const QSet<T> &other) const
+
+ Returns true if the \a other set is equal to this set; otherwise
+ returns false.
+
+ Two sets are considered equal if they contain the same elements.
+
+ This function requires the value type to implement \c operator==().
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QSet::operator!=(const QSet<T> &other) const
+
+ Returns true if the \a other set is not equal to this set; otherwise
+ returns false.
+
+ Two sets are considered equal if they contain the same elements.
+
+ This function requires the value type to implement \c operator==().
+
+ \sa operator==()
+*/
+
+/*!
+ \fn int QSet::size() const
+
+ Returns the number of items in the set.
+
+ \sa isEmpty(), count()
+*/
+
+/*!
+ \fn bool QSet::isEmpty() const
+
+ Returns true if the set contains no elements; otherwise returns
+ false.
+
+ \sa size()
+*/
+
+/*!
+ \fn int QSet::capacity() const
+
+ Returns the number of buckets in the set's internal hash
+ table.
+
+ The sole purpose of this function is to provide a means of fine
+ tuning QSet's memory usage. In general, you will rarely ever need
+ to call this function. If you want to know how many items are in
+ the set, call size().
+
+ \sa reserve(), squeeze()
+*/
+
+/*! \fn void QSet::reserve(int size)
+
+ Ensures that the set's internal hash table consists of at
+ least \a size buckets.
+
+ This function is useful for code that needs to build a huge set
+ and wants to avoid repeated reallocation. For example:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 7
+
+ Ideally, \a size should be slightly more than the maximum number
+ of elements expected in the set. \a size doesn't have to be prime,
+ because QSet will use a prime number internally anyway. If \a size
+ is an underestimate, the worst that will happen is that the QSet
+ will be a bit slower.
+
+ In general, you will rarely ever need to call this function.
+ QSet's internal hash table automatically shrinks or grows to
+ provide good performance without wasting too much memory.
+
+ \sa squeeze(), capacity()
+*/
+
+/*!
+ \fn void QSet::squeeze()
+
+ Reduces the size of the set's internal hash table to save
+ memory.
+
+ The sole purpose of this function is to provide a means of fine
+ tuning QSet's memory usage. In general, you will rarely ever
+ need to call this function.
+
+ \sa reserve(), capacity()
+*/
+
+/*!
+ \fn void QSet::detach()
+
+ \internal
+
+ Detaches this set from any other sets with which it may share
+ data.
+
+ \sa isDetached()
+*/
+
+/*! \fn bool QSet::isDetached() const
+
+ \internal
+
+ Returns true if the set's internal data isn't shared with any
+ other set object; otherwise returns false.
+
+ \sa detach()
+*/
+
+/*!
+ \fn void QSet::setSharable(bool sharable)
+ \internal
+*/
+
+/*!
+ \fn void QSet::clear()
+
+ Removes all elements from the set.
+
+ \sa remove()
+*/
+
+/*!
+ \fn bool QSet::remove(const T &value)
+
+ Removes any occurrence of item \a value from the set. Returns
+ true if an item was actually removed; otherwise returns false.
+
+ \sa contains(), insert()
+*/
+
+/*!
+ \fn QSet::iterator QSet::erase(iterator pos)
+ \since 4.2
+
+ Removes the item at the iterator position \a pos from the set, and
+ returns an iterator positioned at the next item in the set.
+
+ Unlike remove(), this function never causes QSet to rehash its
+ internal data structure. This means that it can safely be called
+ while iterating, and won't affect the order of items in the set.
+
+ \sa remove(), find()
+*/
+
+/*! \fn QSet::const_iterator QSet::find(const T &value) const
+ \since 4.2
+
+ Returns a const iterator positioned at the item \a value in the
+ set. If the set contains no item \a value, the function returns
+ constEnd().
+
+ \sa constFind(), contains()
+*/
+
+/*! \fn QSet::iterator QSet::find(const T &value)
+ \since 4.2
+ \overload
+
+ Returns a non-const iterator positioned at the item \a value in
+ the set. If the set contains no item \a value, the function
+ returns end().
+*/
+
+/*! \fn QSet::const_iterator QSet::constFind(const T &value) const
+ \since 4.2
+
+ Returns a const iterator positioned at the item \a value in the
+ set. If the set contains no item \a value, the function returns
+ constEnd().
+
+ \sa find(), contains()
+*/
+
+/*!
+ \fn bool QSet::contains(const T &value) const
+
+ Returns true if the set contains item \a value; otherwise returns
+ false.
+
+ \sa insert(), remove(), find()
+*/
+
+/*!
+ \fn bool QSet::contains(const QSet<T> &other) const
+ \since 4.6
+
+ Returns true if the set contains all items from the \a other set;
+ otherwise returns false.
+
+ \sa insert(), remove(), find()
+*/
+
+/*! \fn QSet::const_iterator QSet::begin() const
+
+ Returns a const \l{STL-style iterator} positioned at the first
+ item in the set.
+
+ \sa constBegin(), end()
+*/
+
+/*! \fn QSet::iterator QSet::begin()
+ \since 4.2
+ \overload
+
+ Returns a non-const \l{STL-style iterator} positioned at the first
+ item in the set.
+*/
+
+/*! \fn QSet::const_iterator QSet::constBegin() const
+
+ Returns a const \l{STL-style iterator} positioned at the first
+ item in the set.
+
+ \sa begin(), constEnd()
+*/
+
+/*! \fn QSet::const_iterator QSet::end() const
+
+ Returns a const \l{STL-style iterator} positioned at the imaginary
+ item after the last item in the set.
+
+ \sa constEnd(), begin()
+*/
+
+/*! \fn QSet::iterator QSet::end()
+ \since 4.2
+ \overload
+
+ Returns a non-const \l{STL-style iterator} pointing to the
+ imaginary item after the last item in the set.
+*/
+
+/*! \fn QSet::const_iterator QSet::constEnd() const
+
+ Returns a const \l{STL-style iterator} pointing to the imaginary
+ item after the last item in the set.
+
+ \sa constBegin(), end()
+*/
+
+/*!
+ \typedef QSet::Iterator
+ \since 4.2
+
+ Qt-style synonym for QSet::iterator.
+*/
+
+/*!
+ \typedef QSet::ConstIterator
+
+ Qt-style synonym for QSet::const_iterator.
+*/
+
+/*!
+ \typedef QSet::const_pointer
+
+ Typedef for const T *. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QSet::const_reference
+
+ Typedef for const T &. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QSet::difference_type
+
+ Typedef for const ptrdiff_t. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QSet::key_type
+
+ Typedef for T. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QSet::pointer
+
+ Typedef for T *. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QSet::reference
+
+ Typedef for T &. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QSet::size_type
+
+ Typedef for int. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QSet::value_type
+
+ Typedef for T. Provided for STL compatibility.
+*/
+
+/*!
+ \fn QSet::const_iterator QSet::insert(const T &value)
+
+ Inserts item \a value into the set, if \a value isn't already
+ in the set, and returns an iterator pointing at the inserted
+ item.
+
+ \sa operator<<(), remove(), contains()
+*/
+
+/*!
+ \fn QSet<T> &QSet::unite(const QSet<T> &other)
+
+ Each item in the \a other set that isn't already in this set is
+ inserted into this set. A reference to this set is returned.
+
+ \sa operator|=(), intersect(), subtract()
+*/
+
+/*!
+ \fn QSet<T> &QSet::intersect(const QSet<T> &other)
+
+ Removes all items from this set that are not contained in the
+ \a other set. A reference to this set is returned.
+
+ \sa operator&=(), unite(), subtract()
+*/
+
+/*!
+ \fn QSet<T> &QSet::subtract(const QSet<T> &other)
+
+ Removes all items from this set that are contained in the
+ \a other set. Returns a reference to this set.
+
+ \sa operator-=(), unite(), intersect()
+*/
+
+/*!
+ \fn bool QSet::empty() const
+
+ Returns true if the set is empty. This function is provided
+ for STL compatibility. It is equivalent to isEmpty().
+*/
+
+/*!
+ \fn bool QSet::count() const
+
+ Same as size().
+*/
+
+/*!
+ \fn QSet<T> &QSet::operator<<(const T &value)
+ \fn QSet<T> &QSet::operator+=(const T &value)
+ \fn QSet<T> &QSet::operator|=(const T &value)
+
+ Inserts a new item \a value and returns a reference to the set.
+ If \a value already exists in the set, the set is left unchanged.
+
+ \sa insert()
+*/
+
+/*!
+ \fn QSet<T> &QSet::operator-=(const T &value)
+
+ Removes the occurrence of item \a value from the set, if
+ it is found, and returns a reference to the set. If the
+ \a value is not contained the set, nothing is removed.
+
+ \sa remove()
+*/
+
+/*!
+ \fn QSet<T> &QSet::operator|=(const QSet<T> &other)
+ \fn QSet<T> &QSet::operator+=(const QSet<T> &other)
+
+ Same as unite(\a other).
+
+ \sa operator|(), operator&=(), operator-=()
+*/
+
+/*!
+ \fn QSet<T> &QSet::operator&=(const QSet<T> &other)
+
+ Same as intersect(\a other).
+
+ \sa operator&(), operator|=(), operator-=()
+*/
+
+/*!
+ \fn QSet<T> &QSet::operator&=(const T &value)
+
+ \overload
+
+ Same as intersect(\e{other}), if we consider \e{other} to be a set
+ that contains the singleton \a value.
+*/
+
+
+/*!
+ \fn QSet<T> &QSet::operator-=(const QSet<T> &other)
+
+ Same as subtract(\a{other}).
+
+ \sa operator-(), operator|=(), operator&=()
+*/
+
+/*!
+ \fn QSet<T> QSet::operator|(const QSet<T> &other) const
+ \fn QSet<T> QSet::operator+(const QSet<T> &other) const
+
+ Returns a new QSet that is the union of this set and the
+ \a other set.
+
+ \sa unite(), operator|=(), operator&(), operator-()
+*/
+
+/*!
+ \fn QSet<T> QSet::operator&(const QSet<T> &other) const
+
+ Returns a new QSet that is the intersection of this set and the
+ \a other set.
+
+ \sa intersect(), operator&=(), operator|(), operator-()
+*/
+
+/*!
+ \fn QSet<T> QSet::operator-(const QSet<T> &other) const
+
+ Returns a new QSet that is the set difference of this set and
+ the \a other set, i.e., this set - \a other set.
+
+ \sa subtract(), operator-=(), operator|(), operator&()
+*/
+
+/*!
+ \fn QSet<T> QSet::operator-(const QSet<T> &other)
+ \fn QSet<T> QSet::operator|(const QSet<T> &other)
+ \fn QSet<T> QSet::operator+(const QSet<T> &other)
+ \fn QSet<T> QSet::operator&(const QSet<T> &other)
+ \internal
+
+ These will go away in Qt 5.
+*/
+
+/*!
+ \class QSet::iterator
+ \since 4.2
+ \brief The QSet::iterator class provides an STL-style non-const iterator for QSet.
+
+ QSet features both \l{STL-style iterators} and
+ \l{Java-style iterators}. The STL-style iterators are more
+ low-level and more cumbersome to use; on the other hand, they are
+ slightly faster and, for developers who already know STL, have
+ the advantage of familiarity.
+
+ QSet<T>::iterator allows you to iterate over a QSet and to remove
+ items (using QSet::erase()) while you iterate. (QSet doesn't let
+ you \e modify a value through an iterator, because that
+ would potentially require moving the value in the internal hash
+ table used by QSet.) If you want to iterate over a const QSet,
+ you should use QSet::const_iterator. It is generally good
+ practice to use QSet::const_iterator on a non-const QSet as well,
+ unless you need to change the QSet through the iterator. Const
+ iterators are slightly faster, and can improve code readability.
+
+ QSet\<T\>::iterator allows you to iterate over a QSet\<T\> and
+ modify it as you go (using QSet::erase()). However,
+
+ The default QSet::iterator constructor creates an uninitialized
+ iterator. You must initialize it using a function like
+ QSet::begin(), QSet::end(), or QSet::insert() before you can
+ start iterating. Here's a typical loop that prints all the items
+ stored in a set:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 8
+
+ Here's a loop that removes certain items (all those that start
+ with 'J') from a set while iterating:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 9
+
+ STL-style iterators can be used as arguments to \l{generic
+ algorithms}. For example, here's how to find an item in the set
+ using the qFind() algorithm:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 10
+
+ Multiple iterators can be used on the same set. However, you may
+ not attempt to modify the container while iterating on it.
+
+ \sa QSet::const_iterator, QMutableSetIterator
+*/
+
+/*!
+ \class QSet::const_iterator
+ \brief The QSet::const_iterator class provides an STL-style const iterator for QSet.
+ \since 4.2
+
+ QSet features both \l{STL-style iterators} and
+ \l{Java-style iterators}. The STL-style iterators are more
+ low-level and more cumbersome to use; on the other hand, they are
+ slightly faster and, for developers who already know STL, have
+ the advantage of familiarity.
+
+ QSet\<Key, T\>::const_iterator allows you to iterate over a QSet.
+ If you want to modify the QSet as you iterate over it, you must
+ use QSet::iterator instead. It is generally good practice to use
+ QSet::const_iterator on a non-const QSet as well, unless you need
+ to change the QSet through the iterator. Const iterators are
+ slightly faster, and can improve code readability.
+
+ The default QSet::const_iterator constructor creates an
+ uninitialized iterator. You must initialize it using a function
+ like QSet::begin(), QSet::end(), or QSet::insert() before you can
+ start iterating. Here's a typical loop that prints all the items
+ stored in a set:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 11
+
+ STL-style iterators can be used as arguments to \l{generic
+ algorithms}. For example, here's how to find an item in the set
+ using the qFind() algorithm:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 12
+
+ Multiple iterators can be used on the same set. However, you may
+ not attempt to modify the container while iterating on it.
+
+ \sa QSet::iterator, QSetIterator
+*/
+
+/*!
+ \fn QSet::iterator::iterator()
+ \fn QSet::const_iterator::const_iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like operator*() and operator++() should not be called
+ on an uninitialized iterator. Use operator=() to assign a value
+ to it before using it.
+
+ \sa QSet::begin(), QSet::end()
+*/
+
+/*!
+ \fn QSet::iterator::iterator(typename Hash::iterator i)
+ \fn QSet::const_iterator::const_iterator(typename Hash::const_iterator i)
+
+ \internal
+*/
+
+/*!
+ \typedef QSet::iterator::iterator_category
+ \typedef QSet::const_iterator::iterator_category
+
+ Synonyms for \e {std::bidirectional_iterator_tag} indicating
+ these iterators are bidirectional iterators.
+ */
+
+/*!
+ \typedef QSet::iterator::difference_type
+ \typedef QSet::const_iterator::difference_type
+
+ \internal
+*/
+
+/*!
+ \typedef QSet::iterator::value_type
+ \typedef QSet::const_iterator::value_type
+
+ \internal
+*/
+
+/*!
+ \typedef QSet::iterator::pointer
+ \typedef QSet::const_iterator::pointer
+
+ \internal
+*/
+
+/*!
+ \typedef QSet::iterator::reference
+ \typedef QSet::const_iterator::reference
+
+ \internal
+*/
+
+/*!
+ \fn QSet::iterator::iterator(const iterator &other)
+ \fn QSet::const_iterator::const_iterator(const const_iterator &other)
+
+ Constructs a copy of \a other.
+*/
+
+/*!
+ \fn QSet::const_iterator::const_iterator(const iterator &other)
+ \since 4.2
+ \overload
+
+ Constructs a copy of \a other.
+*/
+
+/*!
+ \fn QSet::iterator &QSet::iterator::operator=(const iterator &other)
+ \fn QSet::const_iterator &QSet::const_iterator::operator=(const const_iterator &other)
+
+ Assigns \a other to this iterator.
+*/
+
+/*!
+ \fn const T &QSet::iterator::operator*() const
+ \fn const T &QSet::const_iterator::operator*() const
+
+ Returns a reference to the current item.
+
+ \sa operator->()
+*/
+
+/*!
+ \fn const T *QSet::iterator::operator->() const
+ \fn const T *QSet::const_iterator::operator->() const
+
+ Returns a pointer to the current item.
+
+ \sa operator*()
+*/
+
+/*!
+ \fn bool QSet::iterator::operator==(const iterator &other) const
+ \fn bool QSet::const_iterator::operator==(const const_iterator &other) const
+
+ Returns true if \a other points to the same item as this
+ iterator; otherwise returns false.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QSet::iterator::operator==(const const_iterator &other) const
+ \fn bool QSet::iterator::operator!=(const const_iterator &other) const
+
+ \overload
+*/
+
+/*!
+ \fn bool QSet::iterator::operator!=(const iterator &other) const
+ \fn bool QSet::const_iterator::operator!=(const const_iterator &other) const
+
+ Returns true if \a other points to a different item than this
+ iterator; otherwise returns false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn QSet::iterator &QSet::iterator::operator++()
+ \fn QSet::const_iterator &QSet::const_iterator::operator++()
+
+ The prefix ++ operator (\c{++it}) advances the iterator to the
+ next item in the set and returns an iterator to the new current
+ item.
+
+ Calling this function on QSet::constEnd() leads to
+ undefined results.
+
+ \sa operator--()
+*/
+
+/*!
+ \fn QSet::iterator QSet::iterator::operator++(int)
+ \fn QSet::const_iterator QSet::const_iterator::operator++(int)
+
+ \overload
+
+ The postfix ++ operator (\c{it++}) advances the iterator to the
+ next item in the set and returns an iterator to the previously
+ current item.
+*/
+
+/*!
+ \fn QSet::iterator &QSet::iterator::operator--()
+ \fn QSet::const_iterator &QSet::const_iterator::operator--()
+
+ The prefix -- operator (\c{--it}) makes the preceding item
+ current and returns an iterator to the new current item.
+
+ Calling this function on QSet::begin() leads to undefined
+ results.
+
+ \sa operator++()
+*/
+
+/*!
+ \fn QSet::iterator QSet::iterator::operator--(int)
+ \fn QSet::const_iterator QSet::const_iterator::operator--(int)
+
+ \overload
+
+ The postfix -- operator (\c{it--}) makes the preceding item
+ current and returns an iterator to the previously current item.
+*/
+
+/*!
+ \fn QSet::iterator QSet::iterator::operator+(int j) const
+ \fn QSet::const_iterator QSet::const_iterator::operator+(int j) const
+
+ Returns an iterator to the item at \a j positions forward from
+ this iterator. (If \a j is negative, the iterator goes backward.)
+
+ This operation can be slow for large \a j values.
+
+ \sa operator-()
+*/
+
+/*!
+ \fn QSet::iterator QSet::iterator::operator-(int j) const
+ \fn QSet::const_iterator QSet::const_iterator::operator-(int j) const
+
+ Returns an iterator to the item at \a j positions backward from
+ this iterator. (If \a j is negative, the iterator goes forward.)
+
+ This operation can be slow for large \a j values.
+
+ \sa operator+()
+*/
+
+/*!
+ \fn QSet::iterator &QSet::iterator::operator+=(int j)
+ \fn QSet::const_iterator &QSet::const_iterator::operator+=(int j)
+
+ Advances the iterator by \a j items. (If \a j is negative, the
+ iterator goes backward.)
+
+ This operation can be slow for large \a j values.
+
+ \sa operator-=(), operator+()
+*/
+
+/*!
+ \fn QSet::iterator &QSet::iterator::operator-=(int j)
+ \fn QSet::const_iterator &QSet::const_iterator::operator-=(int j)
+
+ Makes the iterator go back by \a j items. (If \a j is negative,
+ the iterator goes forward.)
+
+ This operation can be slow for large \a j values.
+
+ \sa operator+=(), operator-()
+*/
+
+/*! \fn QList<T> QSet<T>::toList() const
+
+ Returns a new QList containing the elements in the set. The
+ order of the elements in the QList is undefined.
+
+ Example:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 13
+
+ \sa fromList(), QList::fromSet(), qSort()
+*/
+
+/*! \fn QList<T> QSet<T>::values() const
+
+ Returns a new QList containing the elements in the set. The
+ order of the elements in the QList is undefined.
+
+ This is the same as toList().
+
+ \sa fromList(), QList::fromSet(), qSort()
+*/
+
+
+/*! \fn QSet<T> QSet<T>::fromList(const QList<T> &list)
+
+ Returns a new QSet object containing the data contained in \a
+ list. Since QSet doesn't allow duplicates, the resulting QSet
+ might be smaller than the \a list, because QList can contain
+ duplicates.
+
+ Example:
+
+ \snippet doc/src/snippets/code/doc_src_qset.qdoc 14
+
+ \sa toList(), QList::toSet()
+*/
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &out, const QSet<T> &set)
+ \relates QSet
+
+ Writes the \a set to stream \a out.
+
+ This function requires the value type to implement \c operator<<().
+
+ \sa \link datastreamformat.html Format of the QDataStream operators \endlink
+*/
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &in, QSet<T> &set)
+ \relates QSet
+
+ Reads a set from stream \a in into \a set.
+
+ This function requires the value type to implement \c operator>>().
+
+ \sa \link datastreamformat.html Format of the QDataStream operators \endlink
+*/
diff --git a/src/corelib/tools/qshareddata.cpp b/src/corelib/tools/qshareddata.cpp
index 3cb11bd..3d1a339 100644
--- a/src/corelib/tools/qshareddata.cpp
+++ b/src/corelib/tools/qshareddata.cpp
@@ -44,507 +44,512 @@
QT_BEGIN_NAMESPACE
/*!
- \class QSharedData
- \brief The QSharedData class is a base class for shared data objects.
- \reentrant
- \ingroup misc
+ \class QSharedData
+ \brief The QSharedData class is a base class for shared data objects.
+ \reentrant
- QSharedData is designed to be used with QSharedDataPointer or
- QExplicitlySharedDataPointer to implement custom \l{implicitly
- shared} or \l {explicitly shared} classes. QSharedData provides
- \l{thread-safe} reference counting.
+ QSharedData is designed to be used with QSharedDataPointer or
+ QExplicitlySharedDataPointer to implement custom \l{implicitly
+ shared} or explicitly shared classes. QSharedData provides
+ \l{thread-safe} reference counting.
- See QSharedDataPointer and QExplicitlySharedDataPointer for details.
+ See QSharedDataPointer and QExplicitlySharedDataPointer for details.
*/
/*! \fn QSharedData::QSharedData()
- Constructs a QSharedData object with a reference count of 0.
+ Constructs a QSharedData object with a reference count of 0.
*/
/*! \fn QSharedData::QSharedData(const QSharedData& other)
- Constructs a QSharedData object with reference count 0.
- \a other is ignored.
+ Constructs a QSharedData object with reference count 0.
+ \a other is ignored.
*/
/*!
- \class QSharedDataPointer
- \brief The QSharedDataPointer class represents a pointer to an implicitly shared object.
- \since 4.0
- \reentrant
- \ingroup misc
- \mainclass
+ \class QSharedDataPointer
+ \brief The QSharedDataPointer class represents a pointer to an implicitly shared object.
+ \since 4.0
+ \reentrant
- QSharedDataPointer\<T\> makes writing your own \l {implicitly
- shared} classes easy. QSharedDataPointer implements \l {thread-safe}
- reference counting, ensuring that adding QSharedDataPointers to your
- \l {reentrant} classes won't make them non-reentrant.
+ QSharedDataPointer\<T\> makes writing your own \l {implicitly
+ shared} classes easy. QSharedDataPointer implements \l {thread-safe}
+ reference counting, ensuring that adding QSharedDataPointers to your
+ \l {reentrant} classes won't make them non-reentrant.
- \l {Implicit sharing} is used by many Qt classes to combine the
- speed and memory efficiency of pointers with the ease of use of
- classes. See the \l{Shared Classes} page for more information.
+ \l {Implicit sharing} is used by many Qt classes to combine the
+ speed and memory efficiency of pointers with the ease of use of
+ classes. See the \l{Shared Classes} page for more information.
- \target Employee example
- Suppose you want to make an \c Employee class implicitly shared. The
- procedure is:
+ \target Employee example
+ Suppose you want to make an \c Employee class implicitly shared. The
+ procedure is:
- \list
+ \list
- \o Define the class \c Employee to have a single data member of
+ \o Define the class \c Employee to have a single data member of
type \c {QSharedDataPointer<EmployeeData>}.
- \o Define the \c EmployeeData class derived from \l QSharedData to
+ \o Define the \c EmployeeData class derived from \l QSharedData to
contain all the data members you would normally have put in the
\c Employee class.
- \endlist
-
- To show this in practice, we review the source code for the
- implicitly shared \c Employee class. In the header file we define the
- two classes \c Employee and \c EmployeeData.
-
- \snippet doc/src/snippets/sharedemployee/employee.h 0
-
- In class \c Employee, note the single data member, a \e {d pointer}
- of type \c {QSharedDataPointer<EmployeeData>}. All accesses of
- employee data must go through the \e {d pointer's} \c
- {operator->()}. For write accesses, \c {operator->()} will
- automatically call detach(), which creates a copy of the shared data
- object if the shared data object's reference count is greater than
- 1. This ensures that writes to one \c Employee object don't affect
- any other \c Employee objects that share the same \c EmployeeData
- object.
-
- Class \c EmployeeData inherits QSharedData, which provides the
- \e{behind the scenes} reference counter. \c EmployeeData has a default
- constructor, a copy constructor, and a destructor. Normally, trivial
- implementations of these are all that is needed in the \e {data}
- class for an implicitly shared class.
-
- Implementing the two constructors for class \c Employee is also
- straightforward. Both create a new instance of \c EmployeeData
- and assign it to the \e{d pointer} .
-
- \snippet doc/src/snippets/sharedemployee/employee.h 1
- \codeline
- \snippet doc/src/snippets/sharedemployee/employee.h 2
-
- Note that class \c Employee also has a trivial copy constructor
- defined, which is not strictly required in this case.
-
- \snippet doc/src/snippets/sharedemployee/employee.h 7
-
- The copy constructor is not strictly required here, because class \c
- EmployeeData is included in the same file as class \c Employee
- (\c{employee.h}). However, including the private subclass of
- QSharedData in the same file as the public class containing the
- QSharedDataPointer is not typical. Normally, the idea is to hide the
- private subclass of QSharedData from the user by putting it in a
- separate file which would not be included in the public file. In
- this case, we would normally put class \c EmployeeData in a separate
- file, which would \e{not} be included in \c{employee.h}. Instead, we
- would just predeclare the private subclass \c EmployeeData in \c
- {employee.h} this way:
-
- \code
- class EmployeeData;
- \endcode
-
- If we had done it that way here, the copy constructor shown would be
- required. Since the copy constructor is trivial, you might as well
- just always include it.
-
- Behind the scenes, QSharedDataPointer automatically increments the
- reference count whenever an \c Employee object is copied, assigned,
- or passed as a parameter. It decrements the reference count whenever
- an \c Employee object is deleted or goes out of scope. The shared
- \c EmployeeData object is deleted automatically if and when the
- reference count reaches 0.
-
- In a non-const member function of \c Employee, whenever the \e {d
- pointer} is dereferenced, QSharedDataPointer automatically calls
- detach() to ensure that the function operates on its own copy of the
- data.
-
- \snippet doc/src/snippets/sharedemployee/employee.h 3
- \codeline
- \snippet doc/src/snippets/sharedemployee/employee.h 4
-
- Note that if detach() is called more than once in a member function
- due to multiple dereferences of the \e {d pointer}, detach() will
- only create a copy of the shared data the first time it is called,
- if at all, because on the second and subsequent calls of detach(),
- the reference count will be 1 again.
-
- But note that in the second \c Employee constructor, which takes an
- employee ID and a name, both setId() and setName() are called, but
- they don't cause \e{copy on write}, because the reference count for
- the newly constructed \c EmployeeData object has just been set to 1.
-
- In \c Employee's \e const member functions, dereferencing the \e {d
- pointer} does \e not cause detach() to be called.
-
- \snippet doc/src/snippets/sharedemployee/employee.h 5
- \codeline
- \snippet doc/src/snippets/sharedemployee/employee.h 6
-
- Notice that there is no need to implement a copy constructor or an
- assignment operator for the \c Employee class, because the copy
- constructor and assignment operator provided by the C++ compiler
- will do the \e{member by member} shallow copy required. The only
- member to copy is the \e {d pointer}, which is a QSharedDataPointer,
- whose \c {operator=()} just increments the reference count of the
- shared \c EmployeeData object.
-
- \target Implicit vs Explicit Sharing
- \section1 Implicit vs Explicit Sharing
-
- Implicit sharing might not be right for the \c Employee class.
- Consider a simple example that creates two instances of the
- implicitly shared \c Employee class.
-
- \snippet doc/src/snippets/sharedemployee/main.cpp 0
-
- After the second employee e2 is created and e1 is assigned to it,
- both \c e1 and \c e2 refer to Albrecht Durer, employee 1001. Both \c
- Employee objects point to the same instance of \c EmployeeData,
- which has reference count 2. Then \c {e1.setName("Hans Holbein")} is
- called to change the employee name, but because the reference count
- is greater than 1, a \e{copy on write} is performed before the name
- is changed. Now \c e1 and \c e2 point to different \c EmployeeData
- objects. They have different names, but both have ID 1001, which is
- probably not what you want. You can, of course, just continue with
- \c {e1.setId(1002)}, if you really mean to create a second, unique
- employee, but if you only want to change the employee's name
- everywhere, consider using \l {QExplicitlySharedDataPointer}
- {explicit sharing} in the \c Employee class instead of implicit
- sharing.
-
- If you declare the \e {d pointer} in the \c Employee class to be
- \c {QExplicitlySharedDataPointer<EmployeeData>}, then explicit
- sharing is used and \e{copy on write} operations are not performed
- automatically (i.e. detach() is not called in non-const
- functions). In that case, after \c {e1.setName("Hans Holbein")}, the
- employee's name has been changed, but both e1 and e2 still refer to
- the same instance of \c EmployeeData, so there is only one employee
- with ID 1001.
-
- In the member function documentation, \e{d pointer} always refers
- to the internal pointer to the shared data object.
-
- \sa QSharedData, QExplicitlySharedDataPointer
+ \endlist
+
+ To show this in practice, we review the source code for the
+ implicitly shared \c Employee class. In the header file we define the
+ two classes \c Employee and \c EmployeeData.
+
+ \snippet doc/src/snippets/sharedemployee/employee.h 0
+
+ In class \c Employee, note the single data member, a \e {d pointer}
+ of type \c {QSharedDataPointer<EmployeeData>}. All accesses of
+ employee data must go through the \e {d pointer's} \c
+ {operator->()}. For write accesses, \c {operator->()} will
+ automatically call detach(), which creates a copy of the shared data
+ object if the shared data object's reference count is greater than
+ 1. This ensures that writes to one \c Employee object don't affect
+ any other \c Employee objects that share the same \c EmployeeData
+ object.
+
+ Class \c EmployeeData inherits QSharedData, which provides the
+ \e{behind the scenes} reference counter. \c EmployeeData has a default
+ constructor, a copy constructor, and a destructor. Normally, trivial
+ implementations of these are all that is needed in the \e {data}
+ class for an implicitly shared class.
+
+ Implementing the two constructors for class \c Employee is also
+ straightforward. Both create a new instance of \c EmployeeData
+ and assign it to the \e{d pointer} .
+
+ \snippet doc/src/snippets/sharedemployee/employee.h 1
+ \codeline
+ \snippet doc/src/snippets/sharedemployee/employee.h 2
+
+ Note that class \c Employee also has a trivial copy constructor
+ defined, which is not strictly required in this case.
+
+ \snippet doc/src/snippets/sharedemployee/employee.h 7
+
+ The copy constructor is not strictly required here, because class \c
+ EmployeeData is included in the same file as class \c Employee
+ (\c{employee.h}). However, including the private subclass of
+ QSharedData in the same file as the public class containing the
+ QSharedDataPointer is not typical. Normally, the idea is to hide the
+ private subclass of QSharedData from the user by putting it in a
+ separate file which would not be included in the public file. In
+ this case, we would normally put class \c EmployeeData in a separate
+ file, which would \e{not} be included in \c{employee.h}. Instead, we
+ would just predeclare the private subclass \c EmployeeData in \c
+ {employee.h} this way:
+
+ \code
+ class EmployeeData;
+ \endcode
+
+ If we had done it that way here, the copy constructor shown would be
+ required. Since the copy constructor is trivial, you might as well
+ just always include it.
+
+ Behind the scenes, QSharedDataPointer automatically increments the
+ reference count whenever an \c Employee object is copied, assigned,
+ or passed as a parameter. It decrements the reference count whenever
+ an \c Employee object is deleted or goes out of scope. The shared
+ \c EmployeeData object is deleted automatically if and when the
+ reference count reaches 0.
+
+ In a non-const member function of \c Employee, whenever the \e {d
+ pointer} is dereferenced, QSharedDataPointer automatically calls
+ detach() to ensure that the function operates on its own copy of the
+ data.
+
+ \snippet doc/src/snippets/sharedemployee/employee.h 3
+ \codeline
+ \snippet doc/src/snippets/sharedemployee/employee.h 4
+
+ Note that if detach() is called more than once in a member function
+ due to multiple dereferences of the \e {d pointer}, detach() will
+ only create a copy of the shared data the first time it is called,
+ if at all, because on the second and subsequent calls of detach(),
+ the reference count will be 1 again.
+
+ But note that in the second \c Employee constructor, which takes an
+ employee ID and a name, both setId() and setName() are called, but
+ they don't cause \e{copy on write}, because the reference count for
+ the newly constructed \c EmployeeData object has just been set to 1.
+
+ In \c Employee's \e const member functions, dereferencing the \e {d
+ pointer} does \e not cause detach() to be called.
+
+ \snippet doc/src/snippets/sharedemployee/employee.h 5
+ \codeline
+ \snippet doc/src/snippets/sharedemployee/employee.h 6
+
+ Notice that there is no need to implement a copy constructor or an
+ assignment operator for the \c Employee class, because the copy
+ constructor and assignment operator provided by the C++ compiler
+ will do the \e{member by member} shallow copy required. The only
+ member to copy is the \e {d pointer}, which is a QSharedDataPointer,
+ whose \c {operator=()} just increments the reference count of the
+ shared \c EmployeeData object.
+
+ \target Implicit vs Explicit Sharing
+ \section1 Implicit vs Explicit Sharing
+
+ Implicit sharing might not be right for the \c Employee class.
+ Consider a simple example that creates two instances of the
+ implicitly shared \c Employee class.
+
+ \snippet doc/src/snippets/sharedemployee/main.cpp 0
+
+ After the second employee e2 is created and e1 is assigned to it,
+ both \c e1 and \c e2 refer to Albrecht Durer, employee 1001. Both \c
+ Employee objects point to the same instance of \c EmployeeData,
+ which has reference count 2. Then \c {e1.setName("Hans Holbein")} is
+ called to change the employee name, but because the reference count
+ is greater than 1, a \e{copy on write} is performed before the name
+ is changed. Now \c e1 and \c e2 point to different \c EmployeeData
+ objects. They have different names, but both have ID 1001, which is
+ probably not what you want. You can, of course, just continue with
+ \c {e1.setId(1002)}, if you really mean to create a second, unique
+ employee, but if you only want to change the employee's name
+ everywhere, consider using \l {QExplicitlySharedDataPointer}
+ {explicit sharing} in the \c Employee class instead of implicit
+ sharing.
+
+ If you declare the \e {d pointer} in the \c Employee class to be
+ \c {QExplicitlySharedDataPointer<EmployeeData>}, then explicit
+ sharing is used and \e{copy on write} operations are not performed
+ automatically (i.e. detach() is not called in non-const
+ functions). In that case, after \c {e1.setName("Hans Holbein")}, the
+ employee's name has been changed, but both e1 and e2 still refer to
+ the same instance of \c EmployeeData, so there is only one employee
+ with ID 1001.
+
+ In the member function documentation, \e{d pointer} always refers
+ to the internal pointer to the shared data object.
+
+ \sa QSharedData, QExplicitlySharedDataPointer, QScopedPointer, QSharedPointer
*/
/*! \fn T& QSharedDataPointer::operator*()
- Provides access to the shared data object's members.
- This function calls detach().
+ Provides access to the shared data object's members.
+ This function calls detach().
*/
/*! \fn const T& QSharedDataPointer::operator*() const
- Provides const access to the shared data object's members.
- This function does \e not call detach().
+ Provides const access to the shared data object's members.
+ This function does \e not call detach().
*/
/*! \fn T* QSharedDataPointer::operator->()
- Provides access to the shared data object's members.
- This function calls detach().
+ Provides access to the shared data object's members.
+ This function calls detach().
*/
/*! \fn const T* QSharedDataPointer::operator->() const
- Provides const access to the shared data object's members.
- This function does \e not call detach().
+ Provides const access to the shared data object's members.
+ This function does \e not call detach().
*/
/*! \fn QSharedDataPointer::operator T*()
- Returns a pointer to the shared data object.
- This function calls detach().
+ Returns a pointer to the shared data object.
+ This function calls detach().
- \sa data(), constData()
+ \sa data(), constData()
*/
/*! \fn QSharedDataPointer::operator const T*() const
- Returns a pointer to the shared data object.
- This function does \e not call detach().
+ Returns a pointer to the shared data object.
+ This function does \e not call detach().
*/
/*! \fn T* QSharedDataPointer::data()
- Returns a pointer to the shared data object.
- This function calls detach().
+ Returns a pointer to the shared data object.
+ This function calls detach().
- \sa constData()
+ \sa constData()
*/
/*! \fn const T* QSharedDataPointer::data() const
- Returns a pointer to the shared data object.
- This function does \e not call detach().
+ Returns a pointer to the shared data object.
+ This function does \e not call detach().
*/
/*! \fn const T* QSharedDataPointer::constData() const
- Returns a const pointer to the shared data object.
- This function does \e not call detach().
+ Returns a const pointer to the shared data object.
+ This function does \e not call detach().
- \sa data()
+ \sa data()
*/
+/*! \fn void QSharedDataPointer::swap(QSharedDataPointer &other)
+ Swap this instance's shared data pointer with the shared
+ data pointer in \a other.
+ */
+
/*! \fn bool QSharedDataPointer::operator==(const QSharedDataPointer<T>& other) const
- Returns true if \a other and \e this have the same \e{d pointer}.
- This function does \e not call detach().
+ Returns true if \a other and \e this have the same \e{d pointer}.
+ This function does \e not call detach().
*/
/*! \fn bool QSharedDataPointer::operator!=(const QSharedDataPointer<T>& other) const
- Returns true if \a other and \e this do \e not have the same
- \e{d pointer}. This function does \e not call detach().
+ Returns true if \a other and \e this do \e not have the same
+ \e{d pointer}. This function does \e not call detach().
*/
/*! \fn QSharedDataPointer::QSharedDataPointer()
- Constructs a QSharedDataPointer initialized with a null \e{d pointer}.
+ Constructs a QSharedDataPointer initialized with a null \e{d pointer}.
*/
/*! \fn QSharedDataPointer::~QSharedDataPointer()
- Decrements the reference count of the shared data object.
- If the reference count becomes 0, the shared data object
- is deleted. \e This is then destroyed.
+ Decrements the reference count of the shared data object.
+ If the reference count becomes 0, the shared data object
+ is deleted. \e This is then destroyed.
*/
/*! \fn QSharedDataPointer::QSharedDataPointer(T* sharedData)
- Constructs a QSharedDataPointer with \e{d pointer} set to
- \a sharedData and increments \a{sharedData}'s reference count.
+ Constructs a QSharedDataPointer with \e{d pointer} set to
+ \a sharedData and increments \a{sharedData}'s reference count.
*/
/*! \fn QSharedDataPointer::QSharedDataPointer(const QSharedDataPointer<T>& other)
- Sets the \e{d pointer} of \e this to the \e{d pointer} in
- \a other and increments the reference count of the shared
- data object.
+ Sets the \e{d pointer} of \e this to the \e{d pointer} in
+ \a other and increments the reference count of the shared
+ data object.
*/
/*! \fn QSharedDataPointer<T>& QSharedDataPointer::operator=(const QSharedDataPointer<T>& other)
- Sets the \e{d pointer} of \e this to the \e{d pointer} of
- \a other and increments the reference count of the shared
- data object. The reference count of the old shared data
- object of \e this is decremented. If the reference count
- of the old shared data object becomes 0, the old shared
- data object is deleted.
+ Sets the \e{d pointer} of \e this to the \e{d pointer} of
+ \a other and increments the reference count of the shared
+ data object. The reference count of the old shared data
+ object of \e this is decremented. If the reference count
+ of the old shared data object becomes 0, the old shared
+ data object is deleted.
*/
/*! \fn QSharedDataPointer& QSharedDataPointer::operator=(T* sharedData)
- Sets the \e{d pointer} og \e this to \a sharedData and increments
- \a{sharedData}'s reference count. The reference count of the old
- shared data object of \e this is decremented. If the reference
- count of the old shared data object becomes 0, the old shared data
- object is deleted.
+ Sets the \e{d pointer} og \e this to \a sharedData and increments
+ \a{sharedData}'s reference count. The reference count of the old
+ shared data object of \e this is decremented. If the reference
+ count of the old shared data object becomes 0, the old shared data
+ object is deleted.
*/
/*! \fn bool QSharedDataPointer::operator!() const
- Returns true if the \e{d pointer} of \e this is null.
+ Returns true if the \e{d pointer} of \e this is null.
*/
/*! \fn void QSharedDataPointer::detach()
- If the shared data object's reference count is greater than 1, this
- function creates a deep copy of the shared data object and sets the
- \e{d pointer} of \e this to the copy.
-
- This function is called automatically by non-const member
- functions of QSharedDataPointer if \e{copy on write} is
- required. You don't need to call it yourself.
+ If the shared data object's reference count is greater than 1, this
+ function creates a deep copy of the shared data object and sets the
+ \e{d pointer} of \e this to the copy.
+
+ This function is called automatically by non-const member
+ functions of QSharedDataPointer if \e{copy on write} is
+ required. You don't need to call it yourself.
*/
/*! \fn T *QSharedDataPointer::clone()
\since 4.5
- Creates and returns a deep copy of the current data. This function
- is called by detach() when the reference count is greater than 1 in
- order to create the new copy. This function uses the \e {operator
- new} and calls the copy constructor of the type T.
+ Creates and returns a deep copy of the current data. This function
+ is called by detach() when the reference count is greater than 1 in
+ order to create the new copy. This function uses the \e {operator
+ new} and calls the copy constructor of the type T.
- This function is provided so that you may support "virtual copy
- constructors" for your own types. In order to so, you should declare
- a template-specialization of this function for your own type, like
- the example below:
+ This function is provided so that you may support "virtual copy
+ constructors" for your own types. In order to so, you should declare
+ a template-specialization of this function for your own type, like
+ the example below:
- \code
+ \code
template<>
EmployeeData *QSharedDataPointer<EmployeeData>::clone()
{
return d->clone();
}
- \endcode
+ \endcode
- In the example above, the template specialization for the clone()
- function calls the \e {EmployeeData::clone()} virtual function. A
- class derived from EmployeeData could override that function and
- return the proper polymorphic type.
+ In the example above, the template specialization for the clone()
+ function calls the \e {EmployeeData::clone()} virtual function. A
+ class derived from EmployeeData could override that function and
+ return the proper polymorphic type.
*/
/*!
- \class QExplicitlySharedDataPointer
- \brief The QExplicitlySharedDataPointer class represents a pointer to an explicitly shared object.
- \since 4.4
- \reentrant
- \ingroup misc
- \mainclass
-
- QExplicitlySharedDataPointer\<T\> makes writing your own explicitly
- shared classes easy. QExplicitlySharedDataPointer implements
- \l {thread-safe} reference counting, ensuring that adding
- QExplicitlySharedDataPointers to your \l {reentrant} classes won't
- make them non-reentrant.
-
- Except for one big difference, QExplicitlySharedDataPointer is just
- like QSharedDataPointer. The big difference is that member functions
- of QExplicitlySharedDataPointer \e{do not} do the automatic
- \e{copy on write} operation (detach()) that non-const members of
- QSharedDataPointer do before allowing the shared data object to be
- modified. There is a detach() function available, but if you really
- want to detach(), you have to call it yourself. This means that
- QExplicitlySharedDataPointers behave like regular C++ pointers,
- except that by doing reference counting and not deleting the shared
- data object until the reference count is 0, they avoid the dangling
- pointer problem.
-
- It is instructive to compare QExplicitlySharedDataPointer with
- QSharedDataPointer by way of an example. Consider the \l {Employee
- example} in QSharedDataPointer, modified to use explicit sharing as
- explained in the discussion \l {Implicit vs Explicit Sharing}.
-
- Note that if you use this class but find you are calling detach() a
- lot, you probably should be using QSharedDataPointer instead.
-
- In the member function documentation, \e{d pointer} always refers
- to the internal pointer to the shared data object.
-
- \sa QSharedData, QSharedDataPointer
+ \class QExplicitlySharedDataPointer
+ \brief The QExplicitlySharedDataPointer class represents a pointer to an explicitly shared object.
+ \since 4.4
+ \reentrant
+
+ QExplicitlySharedDataPointer\<T\> makes writing your own explicitly
+ shared classes easy. QExplicitlySharedDataPointer implements
+ \l {thread-safe} reference counting, ensuring that adding
+ QExplicitlySharedDataPointers to your \l {reentrant} classes won't
+ make them non-reentrant.
+
+ Except for one big difference, QExplicitlySharedDataPointer is just
+ like QSharedDataPointer. The big difference is that member functions
+ of QExplicitlySharedDataPointer \e{do not} do the automatic
+ \e{copy on write} operation (detach()) that non-const members of
+ QSharedDataPointer do before allowing the shared data object to be
+ modified. There is a detach() function available, but if you really
+ want to detach(), you have to call it yourself. This means that
+ QExplicitlySharedDataPointers behave like regular C++ pointers,
+ except that by doing reference counting and not deleting the shared
+ data object until the reference count is 0, they avoid the dangling
+ pointer problem.
+
+ It is instructive to compare QExplicitlySharedDataPointer with
+ QSharedDataPointer by way of an example. Consider the \l {Employee
+ example} in QSharedDataPointer, modified to use explicit sharing as
+ explained in the discussion \l {Implicit vs Explicit Sharing}.
+
+ Note that if you use this class but find you are calling detach() a
+ lot, you probably should be using QSharedDataPointer instead.
+
+ In the member function documentation, \e{d pointer} always refers
+ to the internal pointer to the shared data object.
+
+ \sa QSharedData, QSharedDataPointer
*/
/*! \fn T& QExplicitlySharedDataPointer::operator*() const
- Provides access to the shared data object's members.
+ Provides access to the shared data object's members.
*/
/*! \fn T* QExplicitlySharedDataPointer::operator->()
- Provides access to the shared data object's members.
+ Provides access to the shared data object's members.
*/
/*! \fn const T* QExplicitlySharedDataPointer::operator->() const
- Provides const access to the shared data object's members.
+ Provides const access to the shared data object's members.
*/
/*! \fn T* QExplicitlySharedDataPointer::data() const
- Returns a pointer to the shared data object.
+ Returns a pointer to the shared data object.
*/
/*! \fn const T* QExplicitlySharedDataPointer::constData() const
- Returns a const pointer to the shared data object.
+ Returns a const pointer to the shared data object.
- \sa data()
+ \sa data()
*/
+/*! \fn void QExplicitlySharedDataPointer::swap(QExplicitlySharedDataPointer &other)
+ Swap this instance's explicitly shared data pointer with
+ the explicitly shared data pointer in \a other.
+ */
+
/*! \fn bool QExplicitlySharedDataPointer::operator==(const QExplicitlySharedDataPointer<T>& other) const
- Returns true if \a other and \e this have the same \e{d pointer}.
+ Returns true if \a other and \e this have the same \e{d pointer}.
*/
/*! \fn bool QExplicitlySharedDataPointer::operator==(const T* ptr) const
- Returns true if the \e{d pointer} of \e this is \a ptr.
+ Returns true if the \e{d pointer} of \e this is \a ptr.
*/
/*! \fn bool QExplicitlySharedDataPointer::operator!=(const QExplicitlySharedDataPointer<T>& other) const
- Returns true if \a other and \e this do \e not have the same
- \e{d pointer}.
+ Returns true if \a other and \e this do \e not have the same
+ \e{d pointer}.
*/
/*! \fn bool QExplicitlySharedDataPointer::operator!=(const T* ptr) const
- Returns true if the \e{d pointer} of \e this is \e not \a ptr.
+ Returns true if the \e{d pointer} of \e this is \e not \a ptr.
*/
/*! \fn QExplicitlySharedDataPointer::QExplicitlySharedDataPointer()
- Constructs a QExplicitlySharedDataPointer initialized with a null
- \e{d pointer}.
+ Constructs a QExplicitlySharedDataPointer initialized with a null
+ \e{d pointer}.
*/
/*! \fn QExplicitlySharedDataPointer::~QExplicitlySharedDataPointer()
- Decrements the reference count of the shared data object.
- If the reference count becomes 0, the shared data object
- is deleted. \e This is then destroyed.
+ Decrements the reference count of the shared data object.
+ If the reference count becomes 0, the shared data object
+ is deleted. \e This is then destroyed.
*/
/*! \fn QExplicitlySharedDataPointer::QExplicitlySharedDataPointer(T* sharedData)
- Constructs a QExplicitlySharedDataPointer with \e{d pointer}
- set to \a sharedData and increments \a{sharedData}'s reference
- count.
+ Constructs a QExplicitlySharedDataPointer with \e{d pointer}
+ set to \a sharedData and increments \a{sharedData}'s reference
+ count.
*/
/*! \fn QExplicitlySharedDataPointer::QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<T>& other)
- This standard copy constructor sets the \e {d pointer} of \e this to
- the \e {d pointer} in \a other and increments the reference count of
- the shared data object.
+ This standard copy constructor sets the \e {d pointer} of \e this to
+ the \e {d pointer} in \a other and increments the reference count of
+ the shared data object.
*/
/*! \fn QExplicitlySharedDataPointer::QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X>& other)
- This copy constructor is different in that it allows \a other to be
- a different type of explicitly shared data pointer but one that has
- a compatible shared data object. It performs a static cast of the
- \e{d pointer} in \a other and sets the \e {d pointer} of \e this to
- the converted \e{d pointer}. It increments the reference count of
- the shared data object.
- */
+ This copy constructor is different in that it allows \a other to be
+ a different type of explicitly shared data pointer but one that has
+ a compatible shared data object. It performs a static cast of the
+ \e{d pointer} in \a other and sets the \e {d pointer} of \e this to
+ the converted \e{d pointer}. It increments the reference count of
+ the shared data object.
+*/
/*! \fn QExplicitlySharedDataPointer<T>& QExplicitlySharedDataPointer::operator=(const QExplicitlySharedDataPointer<T>& other)
- Sets the \e{d pointer} of \e this to the \e{d pointer} of
- \a other and increments the reference count of the shared
- data object. The reference count of the old shared data
- object of \e this is decremented. If the reference count
- of the old shared data object becomes 0, the old shared
- data object is deleted.
+ Sets the \e{d pointer} of \e this to the \e{d pointer} of
+ \a other and increments the reference count of the shared
+ data object. The reference count of the old shared data
+ object of \e this is decremented. If the reference count
+ of the old shared data object becomes 0, the old shared
+ data object is deleted.
*/
/*! \fn QExplicitlySharedDataPointer& QExplicitlySharedDataPointer::operator=(T* sharedData)
- Sets the \e{d pointer} of \e this to \a sharedData and
- increments \a{sharedData}'s reference count. The reference
- count of the old shared data object of \e this is decremented.
- If the reference count of the old shared data object becomes
- 0, the old shared data object is deleted.
+ Sets the \e{d pointer} of \e this to \a sharedData and
+ increments \a{sharedData}'s reference count. The reference
+ count of the old shared data object of \e this is decremented.
+ If the reference count of the old shared data object becomes
+ 0, the old shared data object is deleted.
*/
/*! \fn void QExplicitlySharedDataPointer::reset()
- Resets \e this to be null. i.e., this function sets the
- \e{d pointer} of \e this to 0, but first it decrements
- the reference count of the shared data object and deletes
- the shared data object if the reference count became 0.
+ Resets \e this to be null. i.e., this function sets the
+ \e{d pointer} of \e this to 0, but first it decrements
+ the reference count of the shared data object and deletes
+ the shared data object if the reference count became 0.
*/
/*! \fn QExplicitlySharedDataPointer::operator bool () const
- Returns true if the \e{d pointer} of \e this is \e not null.
+ Returns true if the \e{d pointer} of \e this is \e not null.
*/
/*! \fn bool QExplicitlySharedDataPointer::operator!() const
- Returns true if the \e{d pointer} of \e this is null.
+ Returns true if the \e{d pointer} of \e this is null.
*/
/*! \fn void QExplicitlySharedDataPointer::detach()
- If the shared data object's reference count is greater than 1, this
- function creates a deep copy of the shared data object and sets the
- \e{d pointer} of \e this to the copy.
+ If the shared data object's reference count is greater than 1, this
+ function creates a deep copy of the shared data object and sets the
+ \e{d pointer} of \e this to the copy.
- Because QExplicitlySharedDataPointer does not do the automatic
- \e{copy on write} operations that members of QSharedDataPointer do,
- detach() is \e not called automatically anywhere in the member
- functions of this class. If you find that you are calling detach()
- everywhere in your code, consider using QSharedDataPointer instead.
+ Because QExplicitlySharedDataPointer does not do the automatic
+ \e{copy on write} operations that members of QSharedDataPointer do,
+ detach() is \e not called automatically anywhere in the member
+ functions of this class. If you find that you are calling detach()
+ everywhere in your code, consider using QSharedDataPointer instead.
*/
/*! \fn T *QExplicitlySharedDataPointer::clone()
\since 4.5
- Creates and returns a deep copy of the current data. This function
- is called by detach() when the reference count is greater than 1 in
- order to create the new copy. This function uses the \e {operator
- new} and calls the copy constructor of the type T.
+ Creates and returns a deep copy of the current data. This function
+ is called by detach() when the reference count is greater than 1 in
+ order to create the new copy. This function uses the \e {operator
+ new} and calls the copy constructor of the type T.
- See QSharedDataPointer::clone() for an explanation of how to use it.
+ See QSharedDataPointer::clone() for an explanation of how to use it.
*/
/*!
- \typedef QExplicitlySharedDataPointer::Type
+ \typedef QExplicitlySharedDataPointer::Type
- This is the type of the shared data object. The \e{d pointer}
- points to an object of this type.
- */
+ This is the type of the shared data object. The \e{d pointer}
+ points to an object of this type.
+*/
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h
index 019ddd9..003d187 100644
--- a/src/corelib/tools/qshareddata.h
+++ b/src/corelib/tools/qshareddata.h
@@ -69,6 +69,9 @@ private:
template <class T> class QSharedDataPointer
{
public:
+ typedef T Type;
+ typedef T *pointer;
+
inline void detach() { if (d && d->ref != 1) detach_helper(); }
inline T &operator*() { detach(); return *d; }
inline const T &operator*() const { return *d; }
@@ -111,6 +114,9 @@ public:
inline bool operator!() const { return !d; }
+ inline void swap(QSharedDataPointer &other)
+ { qSwap(d, other.d); }
+
protected:
T *clone();
@@ -124,6 +130,7 @@ template <class T> class QExplicitlySharedDataPointer
{
public:
typedef T Type;
+ typedef T *pointer;
inline T &operator*() const { return *d; }
inline T *operator->() { return d; }
@@ -186,6 +193,9 @@ public:
inline bool operator!() const { return !d; }
+ inline void swap(QExplicitlySharedDataPointer &other)
+ { qSwap(d, other.d); }
+
protected:
T *clone();
@@ -235,6 +245,14 @@ template <class T>
Q_INLINE_TEMPLATE QExplicitlySharedDataPointer<T>::QExplicitlySharedDataPointer(T *adata) : d(adata)
{ if (d) d->ref.ref(); }
+template <class T>
+Q_INLINE_TEMPLATE void qSwap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2)
+{ p1.swap(p2); }
+
+template <class T>
+Q_INLINE_TEMPLATE void qSwap(QExplicitlySharedDataPointer<T> &p1, QExplicitlySharedDataPointer<T> &p2)
+{ p1.swap(p2); }
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp
index 8cf7ad7..7811710 100644
--- a/src/corelib/tools/qsharedpointer.cpp
+++ b/src/corelib/tools/qsharedpointer.cpp
@@ -50,7 +50,6 @@
\since 4.5
\reentrant
- \ingroup misc
The QSharedPointer is an automatic, shared pointer in C++. It
behaves exactly like a normal pointer for normal purposes,
@@ -98,17 +97,264 @@
access made to the data being guarded: if it's a non-const access,
it creates a copy atomically for the operation to complete.
- QExplicitlySharedDataPointer behaves like QSharedDataPointer,
- except that it only detaches if
- QExplicitlySharedDataPointer::detach() is explicitly called.
-
- Finally, QPointer holds a pointer to a QObject-derived object, but
- it does so weakly. QPointer is similar, in that behaviour, to
- QWeakPointer: it does not allow you to prevent the object from
- being destroyed. All you can do is query whether it has been
- destroyed or not.
-
- \sa QSharedDataPointer, QWeakPointer
+ QExplicitlySharedDataPointer is a variant of QSharedDataPointer, except
+ that it only detaches if QExplicitlySharedDataPointer::detach() is
+ explicitly called (hence the name).
+
+ QScopedPointer simply holds a pointer to a heap allocated object and
+ deletes it in its destructor. This class is useful when an object needs to
+ be heap allocated and deleted, but no more. QScopedPointer is lightweight,
+ it makes no use of additional structure or reference counting.
+
+ Finally, QPointer holds a pointer to a QObject-derived object, but it
+ does so weakly. QPointer can be replaced by QWeakPointer in almost all
+ cases, since they have the same functionality. See
+ \l{QWeakPointer#tracking-qobject} for more information.
+
+ \section1 Optional pointer tracking
+
+ A feature of QSharedPointer that can be enabled at compile-time for
+ debugging purposes is a pointer tracking mechanism. When enabled,
+ QSharedPointer registers in a global set all the pointers that it tracks.
+ This allows one to catch mistakes like assigning the same pointer to two
+ QSharedPointer objects.
+
+ This function is enabled by defining the \tt{QT_SHAREDPOINTER_TRACK_POINTERS}
+ macro before including the QSharedPointer header.
+
+ It is safe to use this feature even with code compiled without the
+ feature. QSharedPointer will ensure that the pointer is removed from the
+ tracker even from code compiled without pointer tracking.
+
+ Note, however, that the pointer tracking feature has limitations on
+ multiple- or virtual-inheritance (that is, in cases where two different
+ pointer addresses can refer to the same object). In that case, if a
+ pointer is cast to a different type and its value changes,
+ QSharedPointer's pointer tracking mechanism mail fail to detect that the
+ object being tracked is the same.
+
+ \omit
+ \secton1 QSharedPointer internals
+
+ QSharedPointer is in reality implemented by two ancestor classes:
+ QtSharedPointer::Basic and QtSharedPointer::ExternalRefCount. The reason
+ for having that split is now mostly legacy: in the beginning,
+ QSharedPointer was meant to support both internal reference counting and
+ external reference counting.
+
+ QtSharedPointer::Basic implements the basic functionality that is shared
+ between internal- and external-reference counting. That is, it's mostly
+ the accessor functions into QSharedPointer. Those are all inherited by
+ QSharedPointer, which adds another level of shared functionality (the
+ constructors and assignment operators). The Basic class has one member
+ variable, which is the actual pointer being tracked.
+
+ QtSharedPointer::ExternalRefCount implements the actual reference
+ counting and introduces the d-pointer for QSharedPointer. That d-pointer
+ itself is shared with with other QSharedPointer objects as well as
+ QWeakPointer.
+
+ The reason for keeping the pointer value itself outside the d-pointer is
+ because of multiple inheritance needs. If you have two QSharedPointer
+ objects of different pointer types, but pointing to the same object in
+ memory, it could happen that the pointer values are different. The \tt
+ differentPointers autotest exemplifies this problem. The same thing could
+ happen in the case of virtual inheritance: a pointer of class matching
+ the virtual base has different address compared to the pointer of the
+ complete object. See the \tt virtualBaseDifferentPointers autotest for
+ this problem.
+
+ The d pointer is of type QtSharedPointer::ExternalRefCountData for simple
+ QSharedPointer objects, but could be of a derived type in some cases. It
+ is basically a reference-counted reference-counter.
+
+ \section2 d-pointer
+ \section3 QtSharedPointer::ExternalRefCountData
+
+ This class is basically a reference-counted reference-counter. It has two
+ members: \tt strongref and \tt weakref. The strong reference counter is
+ controlling the lifetime of the object tracked by QSharedPointer. a
+ positive value indicates that the object is alive. It's also the number
+ of QSharedObject instances that are attached to this Data.
+
+ When the strong reference count decreases to zero, the object is deleted
+ (see below for information on custom deleters). The strong reference
+ count can also exceptionally be -1, indicating that there are no
+ QSharedPointers attached to an object, which is tracked too. The only
+ case where this is possible is that of
+ \l{QWeakPointer#tracking-qobject}{QWeakPointers tracking a QObject}.
+
+ The weak reference count controls the lifetime of the d-pointer itself.
+ It can be thought of as an internal/intrusive reference count for
+ ExternalRefCountData itself. This count is equal to the number of
+ QSharedPointers and QWeakPointers that are tracking this object. (In case
+ the object tracked derives from QObject, this number is increased by 1,
+ since QObjectPrivate tracks it too).
+
+ ExternalRefCountData is a virtual class: it has a virtual destructor and
+ a virtual destroy() function. The destroy() function is supposed to
+ delete the object being tracked and return true if it does so. Otherwise,
+ it returns false to indicate that the caller must simply call delete.
+ This allows the normal use-case of QSharedPointer without custom deleters
+ to use only one 12- or 16-byte (depending on whether it's a 32- or 64-bit
+ architecture) external descriptor structure, without paying the price for
+ the custom deleter that it isn't using.
+
+ \section3 QtSharedPointer::ExternalRefCountDataWithDestroyFn
+
+ This class is not used directly, per se. It only exists to enable the two
+ classes that derive from it. It adds one member variable, which is a
+ pointer to a function (which returns void and takes an
+ ExternalRefCountData* as a parameter). It also overrides the destroy()
+ function: it calls that function pointer with \tt this as parameter, and
+ returns true.
+
+ That means when ExternalRefCountDataWithDestroyFn is used, the \tt
+ destroyer field must be set to a valid function that \b will delete the
+ object tracked.
+
+ This class also adds an operator delete function to ensure that simply
+ calls the global operator delete. That should be the behaviour in all
+ compilers already, but to be on the safe side, this class ensures that no
+ funny business happens.
+
+ On a 32-bit architecture, this class is 16 bytes in size, whereas it's 24
+ bytes on 64-bit. (On Itanium where function pointers contain the global
+ pointer, it can be 32 bytes).
+
+ \section3 QtSharedPointer::ExternalRefCountWithCustomDeleter
+
+ This class derives from ExternalRefCountDataWithDestroyFn and is a
+ template class. As template parameters, it has the type of the pointer
+ being tracked (\tt T) and a \tt Deleter, which is anything. It adds two
+ fields to its parent class, matching those template parameters: a member
+ of type \tt Deleter and a member of type \tt T*.
+
+ The purpose of this class is to store the pointer to be deleted and the
+ deleter code along with the d-pointer. This allows the last strong
+ reference to call any arbitrary function that disposes of the object. For
+ example, this allows calling QObject::deleteLater() on a given object.
+ The pointer to the object is kept here to avoid the extra cost of keeping
+ the deleter in the generic case.
+
+ This class is never instantiated directly: the constructors and
+ destructor are private. Only the create() function may be called to
+ return an object of this type. See below for construction details.
+
+ The size of this class depends on the size of \tt Deleter. If it's an
+ empty functor (i.e., no members), ABIs generally assign it the size of 1.
+ But given that it's followed by a pointer, up to 3 or 7 padding bytes may
+ be inserted: in that case, the size of this class is 16+4+4 = 24 bytes on
+ 32-bit architectures, or 24+8+8 = 40 bytes on 64-bit architectures (48
+ bytes on Itanium with global pointers stored). If \tt Deleter is a
+ function pointer, the size should be the same as the empty structure
+ case, except for Itanium where it may be 56 bytes due to another global
+ pointer. If \tt Deleter is a pointer to a member function (PMF), the size
+ will be even bigger and will depend on the ABI. For architectures using
+ the Itanium C++ ABI, a PMF is twice the size of a normal pointer, or 24
+ bytes on Itanium itself. In that case, the size of this structure will be
+ 16+8+4 = 28 bytes on 32-bit architectures, 24+16+8 = 48 bytes on 64-bit,
+ and 32+24+8 = 64 bytes on Itanium.
+
+ (Values for Itanium consider an LP64 architecture; for ILP32, pointers
+ are 32-bit in length, function pointers are 64-bit and PMF are 96-bit, so
+ the sizes are slightly less)
+
+ \section3 QtSharedPointer::ExternalRefCountWithContiguousData
+
+ This class also derives from ExternalRefCountDataWithDestroyFn and it is
+ also a template class. The template parameter is the type \tt T of the
+ class which QSharedPointer tracks. It adds only one member to its parent,
+ which is of type \tt T (the actual type, not a pointer to it).
+
+ The purpose of this class is to lay the \tt T object out next to the
+ reference counts, saving one memory allocation per shared pointer. This
+ is particularly interesting for small \tt T or for the cases when there
+ are few if any QWeakPointer tracking the object. This class exists to
+ implement the QSharedPointer::create() call.
+
+ Like ExternalRefCountWithCustomDeleter, this class is never instantiated
+ directly. This class also provides a create() member that returns the
+ pointer, and hides its constructors and destructor. (With C++0x, we'd
+ delete them).
+
+ The size of this class depends on the size of \tt T.
+
+ \section3 Instantiating ExternalRefCountWithCustomDeleter and ExternalRefCountWithContiguousData
+
+ Like explained above, these classes have private constructors. Moreover,
+ they are not defined anywhere, so trying to call \tt{new ClassType} would
+ result in a compilation or linker error. Instead, these classes must be
+ constructed via their create() methods.
+
+ Instead of instantiating the class by the normal way, the create() method
+ calls \tt{operator new} directly with the size of the class, then calls
+ the parent class's constructor only (ExternalRefCountDataWithDestroyFn).
+ This ensures that the inherited members are initialised properly, as well
+ as the virtual table pointer, which must point to
+ ExternalRefCountDataWithDestroyFn's virtual table. That way, we also
+ ensure that the virtual destructor being called is
+ ExternalRefCountDataWithDestroyFn's.
+
+ After initialising the base class, the
+ ExternalRefCountWithCustomDeleter::create() function initialises the new
+ members directly, by using the placement \tt{operator new}. In the case
+ of the ExternalRefCountWithContiguousData::create() function, the address
+ to the still-uninitialised \tt T member is saved for the callee to use.
+ The member is only initialised in QSharedPointer::create(), so that we
+ avoid having many variants of the internal functions according to the
+ arguments in use for calling the constructor.
+
+ When initialising the parent class, the create() functions pass the
+ address of the static deleter() member function. That is, when the
+ virtual destroy() is called by QSharedPointer, the deleter() functions
+ are called instead. These functiosn static_cast the ExternalRefCountData*
+ parameter to their own type and execute their deletion: for the
+ ExternalRefCountWithCustomDeleter::deleter() case, it runs the user's
+ custom deleter, then destroys the deleter; for
+ ExternalRefCountWithContiguousData::deleter, it simply calls the \tt T
+ destructor directly.
+
+ By not calling the constructor of the derived classes, we avoid
+ instantiating their virtual tables. Since these classes are
+ template-based, there would be one virtual table per \tt T and \tt
+ Deleter type. (This is what Qt 4.5 did)
+
+ Instead, only one non-inline function is required per template, which is
+ the deleter() static member. All the other functions can be inlined.
+ What's more, the address of deleter() is calculated only in code, which
+ can be resolved at link-time if the linker can determine that the
+ function lies in the current application or library module (since these
+ classes are not exported, that is the case for Windows or for builds with
+ \tt{-fvisibility=hidden}).
+
+ In contrast, a virtual table would require at least 3 relocations to be
+ resolved at module load-time, per module where these classes are used.
+ (In the Itanium C++ ABI, there would be more relocations, due to the
+ RTTI)
+
+ \section3 Modifications due to pointer-tracking
+
+ To ensure that pointers created with pointer-tracking enabled get
+ un-tracked when destroyed, even if destroyed by code compiled without the
+ feature, QSharedPointer modifies slightly the instructions of the
+ previous sections.
+
+ When ExternalRefCountWithCustomDeleter or
+ ExternalRefCountWithContiguousData are used, their create() functions
+ will set the ExternalRefCountDataWithDestroyFn::destroyer function
+ pointer to safetyCheckDeleter() instead. These static member functions
+ simply call internalSafetyCheckRemove2() before passing control to the
+ normal deleter() function.
+
+ If neither custom deleter nor QSharedPointer::create() are used, then
+ QSharedPointer uses a custom deleter of its own: the normalDeleter()
+ function, which simply calls \tt delete. By using a custom deleter, the
+ safetyCheckDeleter() procedure described above kicks in.
+
+ \endomit
+
+ \sa QSharedDataPointer, QWeakPointer, QScopedPointer
*/
/*!
@@ -116,21 +362,96 @@
\brief The QWeakPointer class holds a weak reference to a shared pointer
\since 4.5
\reentrant
- \ingroup misc
The QWeakPointer is an automatic weak reference to a
pointer in C++. It cannot be used to dereference the pointer
directly, but it can be used to verify if the pointer has been
deleted or not in another context.
- QWeakPointer objects can only be created by assignment
- from a QSharedPointer.
-
- To access the pointer that QWeakPointer is tracking, you
- must first create a QSharedPointer object and verify if the pointer
- is null or not.
-
- \sa QSharedPointer
+ QWeakPointer objects can only be created by assignment from a
+ QSharedPointer. The exception is pointers derived from QObject: in that
+ case, QWeakPointer serves as a replacement to QPointer.
+
+ It's important to note that QWeakPointer provides no automatic casting
+ operators to prevent mistakes from happening. Even though QWeakPointer
+ tracks a pointer, it should not be considered a pointer itself, since it
+ doesn't guarantee that the pointed object remains valid.
+
+ Therefore, to access the pointer that QWeakPointer is tracking, you must
+ first promote it to QSharedPointer and verify if the resulting object is
+ null or not. QSharedPointer guarantees that the object isn't deleted, so
+ if you obtain a non-null object, you may use the pointer. See
+ QWeakPointer::toStrongRef() for more an example.
+
+ QWeakPointer also provides the QWeakPointer::data() method that returns
+ the tracked pointer without ensuring that it remains valid. This function
+ is provided if you can guarantee by external means that the object will
+ not get deleted (or if you only need the pointer value) and the cost of
+ creating a QSharedPointer using toStrongRef() is too high.
+
+ That function can also be used to obtain the tracked pointer for
+ QWeakPointers that cannot be promoted to QSharedPointer, such as those
+ created directly from a QObject pointer (not via QSharedPointer).
+
+ \section1 Tracking QObject
+
+ QWeakPointer can be used to track deletion classes derives from QObject,
+ even if they are not managed by QSharedPointer. When used in that role,
+ QWeakPointer replaces the older QPointer in all use-cases. QWeakPointer
+ is also more efficient than QPointer, so it should be preferred in all
+ new code.
+
+ To do that, QWeakPointer provides a special constructor that is only
+ available if the template parameter \tt T is either QObject or a class
+ deriving from it. Trying to use that constructor if \tt T does not derive
+ from QObject will result in compilation errors.
+
+ To obtain the QObject being tracked by QWeakPointer, you must use the
+ QWeakPointer::data() function, but only if you can guarantee that the
+ object cannot get deleted by another context. It should be noted that
+ QPointer had the same constraint, so use of QWeakPointer forces you to
+ consider whether the pointer is still valid.
+
+ QObject-derived classes can only be deleted in the thread they have
+ affinity to (which is the thread they were created in or moved to, using
+ QObject::moveToThread()). In special, QWidget-derived classes cannot be
+ created in non-GUI threads nor moved there. Therefore, guaranteeing that
+ the tracked QObject has affinity to the current thread is enough to also
+ guarantee that it won't be deleted asynchronously.
+
+ Note that QWeakPointer's size and data layout do not match QPointer, so
+ it cannot replace that class in a binary-compatible manner.
+
+ Care must also be taken with QWeakPointers created directly from QObject
+ pointers when dealing with code that was compiled with Qt versions prior
+ to 4.6. Those versions may not track the reference counters correctly, so
+ QWeakPointers created from QObject should never be passed to code that
+ hasn't been recompiled.
+
+ \omit
+ \secton1 QWeakPointer internals
+
+ QWeakPointer shares most of its internal functionality with
+ \l{QSharedPointer#qsharedpointer-internals}{QSharedPointer}, so see that
+ class's internal documentation for more information.
+
+ QWeakPointer requires an external reference counter in order to operate.
+ Therefore, it is incompatible by design with \l QSharedData-derived
+ classes.
+
+ It has a special QObject constructor, which works by calling
+ QtSharedPointer::ExternalRefCountData::getAndRef, which retrieves the
+ d-pointer from QObjectPrivate. If one isn't set yet, that function
+ creates the d-pointer and atomically sets it.
+
+ If getAndRef needs to create a d-pointer, it sets the strongref to -1,
+ indicating that the QObject is not shared: QWeakPointer is used only to
+ determine whether the QObject has been deleted. In that case, it cannot
+ be upgraded to QSharedPointer (see the previous section).
+
+ \endomit
+
+ \sa QSharedPointer, QScopedPointer
*/
/*!
@@ -210,6 +531,8 @@
If \tt T is a derived type of the template parameter of this
class, QSharedPointer will perform an automatic cast. Otherwise,
you will get a compiler error.
+
+ \sa QWeakPointer::toStrongRef()
*/
/*!
@@ -340,10 +663,30 @@
*/
/*!
+ \fn QSharedPointer<X> QSharedPointer::objectCast() const
+ \since 4.6
+
+ Performs a \l qobject_cast() from this pointer's type to \tt X and
+ returns a QSharedPointer that shares the reference. If this
+ function is used to up-cast, then QSharedPointer will perform a \tt
+ qobject_cast, which means that if the object being pointed by this
+ QSharedPointer is not of type \tt X, the returned object will be
+ null.
+
+ Note: the template type \c X must have the same const and volatile
+ qualifiers as the template of this object, or the cast will
+ fail. Use constCast() if you need to drop those qualifiers.
+
+ \sa qSharedPointerObjectCast()
+*/
+
+/*!
\fn QWeakPointer<T> QSharedPointer::toWeakRef() const
Returns a weak reference object that shares the pointer referenced
by this object.
+
+ \sa QWeakPointer::QWeakPointer()
*/
/*!
@@ -390,6 +733,35 @@
*/
/*!
+ \fn QWeakPointer::QWeakPointer(const QObject *obj)
+ \since 4.6
+
+ Creates a QWeakPointer that holds a weak reference directly to the
+ QObject \a obj. This constructor is only available if the template type
+ \tt T is QObject or derives from it (otherwise a compilation error will
+ result).
+
+ You can use this constructor with any QObject, even if they were not
+ created with \l QSharedPointer.
+
+ Note that QWeakPointers created this way on arbitrary QObjects usually
+ cannot be promoted to QSharedPointer.
+
+ \sa QSharedPointer, QWeakPointer#tracking-qobject
+*/
+
+/*!
+ \fn QWeakPointer &QWeakPointer::operator=(const QObject *obj)
+ \since 4.6
+
+ Makes this QWeakPointer hold a weak reference to directly to the QObject
+ \a obj. This function is only available if the template type \tt T is
+ QObject or derives from it.
+
+ \sa QWeakPointer#tracking-qobject
+*/
+
+/*!
\fn QWeakPointer &QWeakPointer::operator=(const QWeakPointer<T> &other)
Makes this object share \a other's pointer. The current pointer
@@ -460,10 +832,78 @@
*/
/*!
+ \fn T *QWeakPointer::data() const
+ \since 4.6
+
+ Returns the value of the pointer being tracked by this QWeakPointer,
+ \b without ensuring that it cannot get deleted. To have that guarantee,
+ use toStrongRef(), which returns a QSharedPointer object. If this
+ function can determine that the pointer has already been deleted, it
+ returns 0.
+
+ It is ok to obtain the value of the pointer and using that value itself,
+ like for example in debugging statements:
+
+ \code
+ qDebug("Tracking %p", weakref.data());
+ \endcode
+
+ However, dereferencing the pointer is only allowed if you can guarantee
+ by external means that the pointer does not get deleted. For example,
+ if you can be certain that no other thread can delete it, nor the
+ functions that you may call.
+
+ If that is the case, then the following code is valid:
+
+ \code
+ // this pointer cannot be used in another thread
+ // so other threads cannot delete it
+ QWeakPointer<int> weakref = obtainReference();
+
+ Object *obj = weakref.data();
+ if (obj) {
+ // if the pointer wasn't deleted yet, we know it can't get
+ // deleted by our own code here nor the functions we call
+ otherFunction(obj);
+ }
+ \endcode
+
+ Use this function with care.
+
+ \sa isNull(), toStrongRef()
+*/
+
+/*!
\fn QSharedPointer<T> QWeakPointer::toStrongRef() const
Promotes this weak reference to a strong one and returns a
- QSharedPointer object holding that reference.
+ QSharedPointer object holding that reference. When promoting to
+ QSharedPointer, this function verifies if the object has been deleted
+ already or not. If it hasn't, this function increases the reference
+ count to the shared object, thus ensuring that it will not get
+ deleted.
+
+ Since this function can fail to obtain a valid strong reference to the
+ shared object, you should always verify if the conversion succeeded,
+ by calling QSharedPointer::isNull() on the returned object.
+
+ For example, the following code promotes a QWeakPointer that was held
+ to a strong reference and, if it succeeded, it prints the value of the
+ integer that was held:
+
+ \code
+ QWeakPointer<int> weakref;
+
+ // ...
+
+ QSharedPointer<int> strong = weakref.toStrongRef();
+ if (strong)
+ qDebug() << "The value is:" << *strong;
+ else
+ qDebug() << "The value has already been deleted";
+ \endcode
+
+ \sa QSharedPointer::QSharedPointer()
*/
/*!
@@ -718,6 +1158,47 @@
*/
/*!
+ \fn QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &other)
+ \relates QSharedPointer
+ \since 4.6
+
+ Returns a shared pointer to the pointer held by \a other, using a
+ \l qobject_cast() to type \tt X to obtain an internal pointer of the
+ appropriate type. If the \tt qobject_cast fails, the object
+ returned will be null.
+
+ Note that \tt X must have the same cv-qualifiers (\tt const and
+ \tt volatile) that \tt T has, or the code will fail to
+ compile. Use qSharedPointerConstCast to cast away the constness.
+
+ \sa QSharedPointer::objectCast(), qSharedPointerCast(), qSharedPointerConstCast()
+*/
+
+/*!
+ \fn QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<T> &other)
+ \relates QSharedPointer
+ \relates QWeakPointer
+ \since 4.6
+
+ Returns a shared pointer to the pointer held by \a other, using a
+ \l qobject_cast() to type \tt X to obtain an internal pointer of the
+ appropriate type. If the \tt qobject_cast fails, the object
+ returned will be null.
+
+ The \a other object is converted first to a strong reference. If
+ that conversion fails (because the object it's pointing to has
+ already been deleted), this function also returns a null
+ QSharedPointer.
+
+ Note that \tt X must have the same cv-qualifiers (\tt const and
+ \tt volatile) that \tt T has, or the code will fail to
+ compile. Use qSharedPointerConstCast to cast away the constness.
+
+ \sa QWeakPointer::toStrongRef(), qSharedPointerCast(), qSharedPointerConstCast()
+*/
+
+
+/*!
\fn QWeakPointer<X> qWeakPointerCast(const QWeakPointer<T> &other)
\relates QWeakPointer
@@ -733,6 +1214,63 @@
#include <qset.h>
#include <qmutex.h>
+#if !defined(QT_NO_QOBJECT)
+#include "private/qobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ This function is called for a just-created QObject \a obj, to enable
+ the use of QSharedPointer and QWeakPointer.
+
+ When QSharedPointer is active in a QObject, the object must not be deleted
+ directly: the lifetime is managed by the QSharedPointer object. In that case,
+ the deleteLater() and parent-child relationship in QObject only decrease
+ the strong reference count, instead of deleting the object.
+*/
+void QtSharedPointer::ExternalRefCountData::setQObjectShared(const QObject *obj, bool)
+{
+ Q_ASSERT(obj);
+ QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj));
+
+ if (d->sharedRefcount)
+ qFatal("QSharedPointer: pointer %p already has reference counting", obj);
+ d->sharedRefcount = this;
+
+ // QObject decreases the refcount too, so increase it up
+ weakref.ref();
+}
+
+QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::getAndRef(const QObject *obj)
+{
+ Q_ASSERT(obj);
+ QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj));
+ Q_ASSERT_X(!d->wasDeleted, "QWeakPointer", "Detected QWeakPointer creation in a QObject being deleted");
+
+ ExternalRefCountData *that = d->sharedRefcount;
+ if (that) {
+ that->weakref.ref();
+ return that;
+ }
+
+ // we can create the refcount data because it doesn't exist
+ ExternalRefCountData *x = new ExternalRefCountData(Qt::Uninitialized);
+ x->strongref = -1;
+ x->weakref = 2; // the QWeakPointer that called us plus the QObject itself
+ if (!d->sharedRefcount.testAndSetRelease(0, x)) {
+ delete x;
+ d->sharedRefcount->weakref.ref();
+ }
+ return d->sharedRefcount;
+}
+
+QT_END_NAMESPACE
+
+#endif
+
+
+
#if !defined(QT_NO_MEMBER_TEMPLATES)
//# define QT_SHARED_POINTER_BACKTRACE_SUPPORT
@@ -744,29 +1282,21 @@
# endif
# endif
-# if !defined(BACKTRACE_SUPPORTED)
-// Dummy implementation of the functions.
-// Using QHashDummyValue also means that the QHash below is actually a QSet
-typedef QT_PREPEND_NAMESPACE(QHashDummyValue) Backtrace;
-
-static inline Backtrace saveBacktrace() { return Backtrace(); }
-static inline void printBacktrace(Backtrace) { }
-
-# else
+# if defined(BACKTRACE_SUPPORTED)
# include <sys/types.h>
# include <execinfo.h>
# include <stdio.h>
# include <unistd.h>
# include <sys/wait.h>
-typedef QT_PREPEND_NAMESPACE(QByteArray) Backtrace;
+QT_BEGIN_NAMESPACE
-static inline Backtrace saveBacktrace() __attribute__((always_inline));
-static inline Backtrace saveBacktrace()
+static inline QByteArray saveBacktrace() __attribute__((always_inline));
+static inline QByteArray saveBacktrace()
{
static const int maxFrames = 32;
- Backtrace stacktrace;
+ QByteArray stacktrace;
stacktrace.resize(sizeof(void*) * maxFrames);
int stack_size = backtrace((void**)stacktrace.data(), maxFrames);
stacktrace.resize(sizeof(void*) * stack_size);
@@ -774,7 +1304,7 @@ static inline Backtrace saveBacktrace()
return stacktrace;
}
-static void printBacktrace(Backtrace stacktrace)
+static void printBacktrace(QByteArray stacktrace)
{
void *const *stack = (void *const *)stacktrace.constData();
int stack_size = stacktrace.size() / sizeof(void*);
@@ -821,29 +1351,58 @@ static void printBacktrace(Backtrace stacktrace)
waitpid(child, 0, 0);
}
}
+
+QT_END_NAMESPACE
+
# endif // BACKTRACE_SUPPORTED
namespace {
QT_USE_NAMESPACE
+ struct Data {
+ const volatile void *pointer;
+# ifdef BACKTRACE_SUPPORTED
+ QByteArray backtrace;
+# endif
+ };
+
class KnownPointers
{
public:
QMutex mutex;
- QHash<void *, Backtrace> values;
+ QHash<const void *, Data> dPointers;
+ QHash<const volatile void *, const void *> dataPointers;
};
}
-//Q_GLOBAL_STATIC(KnownPointers, knownPointers)
+Q_GLOBAL_STATIC(KnownPointers, knownPointers)
QT_BEGIN_NAMESPACE
+namespace QtSharedPointer {
+ Q_CORE_EXPORT void internalSafetyCheckAdd(const volatile void *);
+ Q_CORE_EXPORT void internalSafetyCheckRemove(const volatile void *);
+ Q_AUTOTEST_EXPORT void internalSafetyCheckCleanCheck();
+}
+
/*!
\internal
*/
void QtSharedPointer::internalSafetyCheckAdd(const volatile void *)
{
- // functionality is broken
- // fix requires Qt 4.6
+ // Qt 4.5 compatibility
+ // this function is broken by design, so it was replaced with internalSafetyCheckAdd2
+ //
+ // it's broken because we tracked the pointers added and
+ // removed from QSharedPointer, converted to void*.
+ // That is, this is supposed to track the "top-of-object" pointer in
+ // case of multiple inheritance.
+ //
+ // However, it doesn't work well in some compilers:
+ // if you create an object with a class of type A and the last reference
+ // is dropped of type B, then the value passed to internalSafetyCheckRemove could
+ // be different than was added. That would leave dangling addresses.
+ //
+ // So instead, we track the pointer by the d-pointer instead.
}
/*!
@@ -851,6 +1410,90 @@ void QtSharedPointer::internalSafetyCheckAdd(const volatile void *)
*/
void QtSharedPointer::internalSafetyCheckRemove(const volatile void *)
{
+ // Qt 4.5 compatibility
+ // see comments above
+}
+
+/*!
+ \internal
+*/
+void QtSharedPointer::internalSafetyCheckAdd2(const void *d_ptr, const volatile void *ptr)
+{
+ // see comments above for the rationale for this function
+ KnownPointers *const kp = knownPointers();
+ if (!kp)
+ return; // end-game: the application is being destroyed already
+
+ QMutexLocker lock(&kp->mutex);
+ Q_ASSERT(!kp->dPointers.contains(d_ptr));
+
+ //qDebug("Adding d=%p value=%p", d_ptr, ptr);
+
+ const void *other_d_ptr = kp->dataPointers.value(ptr, 0);
+ if (other_d_ptr) {
+# ifdef BACKTRACE_SUPPORTED
+ printBacktrace(knownPointers()->dPointers.value(other_d_ptr).backtrace);
+# endif
+ qFatal("QSharedPointer: internal self-check failed: pointer %p was already tracked "
+ "by another QSharedPointer object %p", ptr, other_d_ptr);
+ }
+
+ Data data;
+ data.pointer = ptr;
+# ifdef BACKTRACE_SUPPORTED
+ data.backtrace = saveBacktrace();
+# endif
+
+ kp->dPointers.insert(d_ptr, data);
+ kp->dataPointers.insert(ptr, d_ptr);
+ Q_ASSERT(kp->dPointers.size() == kp->dataPointers.size());
+}
+
+/*!
+ \internal
+*/
+void QtSharedPointer::internalSafetyCheckRemove2(const void *d_ptr)
+{
+ KnownPointers *const kp = knownPointers();
+ if (!kp)
+ return; // end-game: the application is being destroyed already
+
+ QMutexLocker lock(&kp->mutex);
+
+ QHash<const void *, Data>::iterator it = kp->dPointers.find(d_ptr);
+ if (it == kp->dPointers.end()) {
+ qFatal("QSharedPointer: internal self-check inconsistency: pointer %p was not tracked. "
+ "To use QT_SHAREDPOINTER_TRACK_POINTERS, you have to enable it throughout "
+ "in your code.", d_ptr);
+ }
+
+ QHash<const volatile void *, const void *>::iterator it2 = kp->dataPointers.find(it->pointer);
+ Q_ASSERT(it2 != kp->dataPointers.end());
+
+ //qDebug("Removing d=%p value=%p", d_ptr, it->pointer);
+
+ // remove entries
+ kp->dataPointers.erase(it2);
+ kp->dPointers.erase(it);
+ Q_ASSERT(kp->dPointers.size() == kp->dataPointers.size());
+}
+
+/*!
+ \internal
+ Called by the QSharedPointer autotest
+*/
+void QtSharedPointer::internalSafetyCheckCleanCheck()
+{
+# ifdef QT_BUILD_INTERNAL
+ KnownPointers *const kp = knownPointers();
+ Q_ASSERT_X(kp, "internalSafetyCheckSelfCheck()", "Called after global statics deletion!");
+
+ if (kp->dPointers.size() != kp->dataPointers.size())
+ qFatal("Internal consistency error: the number of pointers is not equal!");
+
+ if (!kp->dPointers.isEmpty())
+ qFatal("Pointer cleaning failed: %d entries remaining", kp->dPointers.size());
+# endif
}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qsharedpointer.h b/src/corelib/tools/qsharedpointer.h
index 98d2c9e..ac3032c 100644
--- a/src/corelib/tools/qsharedpointer.h
+++ b/src/corelib/tools/qsharedpointer.h
@@ -93,6 +93,7 @@ public:
template <class X> QSharedPointer<X> staticCast() const;
template <class X> QSharedPointer<X> dynamicCast() const;
template <class X> QSharedPointer<X> constCast() const;
+ template <class X> QSharedPointer<X> objectCast() const;
};
template <class T>
@@ -114,6 +115,10 @@ public:
QWeakPointer<T> operator=(const QWeakPointer<T> &other);
QWeakPointer<T> operator=(const QSharedPointer<T> &other);
+ QWeakPointer(const QObject *other);
+ QWeakPointer<T> operator=(const QObject *other);
+
+ T *data() const;
void clear();
QSharedPointer<T> toStrongRef() const;
@@ -136,6 +141,8 @@ template <class X, class T> QSharedPointer<X> qSharedPointerDynamicCast(const QS
template <class X, class T> QSharedPointer<X> qSharedPointerDynamicCast(const QWeakPointer<T> &src);
template <class X, class T> QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &src);
template <class X, class T> QSharedPointer<X> qSharedPointerConstCast(const QWeakPointer<T> &src);
+template <class X, class T> QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &src);
+template <class X, class T> QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<T> &src);
template <class X, class T> QWeakPointer<X> qWeakPointerCast(const QWeakPointer<T> &src);
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h
index 8dbccb1..a43fd9c 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -48,7 +48,9 @@
#pragma qt_sync_stop_processing
#endif
+#include <new>
#include <QtCore/qatomic.h>
+#include <QtCore/qobject.h> // for qobject_cast
QT_BEGIN_HEADER
@@ -83,17 +85,20 @@ QSharedPointer<X> qSharedPointerDynamicCast(const QSharedPointer<T> &ptr);
template <class X, class T>
QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &ptr);
+#ifndef QT_NO_QOBJECT
+template <class X, class T>
+QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &ptr);
+#endif
+
namespace QtSharedPointer {
template <class T> class InternalRefCount;
template <class T> class ExternalRefCount;
- template <class X, class T> QSharedPointer<X> qStrongRefFromWeakHelper(const QWeakPointer<T> &, X*);
- template <class X, class T> QSharedPointer<X> qSharedPointerCastHelper(const QSharedPointer<T> &src, X *);
- template <class X, class T> QSharedPointer<X> qSharedPointerConstCastHelper(const QSharedPointer<T> &src, X *);
+ template <class X, class Y> QSharedPointer<X> copyAndSetPointer(X * ptr, const QSharedPointer<Y> &src);
// used in debug mode to verify the reuse of pointers
- Q_CORE_EXPORT void internalSafetyCheckAdd(const volatile void *);
- Q_CORE_EXPORT void internalSafetyCheckRemove(const volatile void *);
+ Q_CORE_EXPORT void internalSafetyCheckAdd2(const void *, const volatile void *);
+ Q_CORE_EXPORT void internalSafetyCheckRemove2(const void *);
template <class T, typename Klass, typename RetVal>
inline void executeDeleter(T *t, RetVal (Klass:: *memberDeleter)())
@@ -101,50 +106,54 @@ namespace QtSharedPointer {
template <class T, typename Deleter>
inline void executeDeleter(T *t, Deleter d)
{ d(t); }
-
- //
- // Depending on its template parameter, QSharedPointer derives from either
- // QtSharedPointer::InternalRefCount or from QtSharedPointer::ExternalRefCount.
- // Both of these classes derive from QtSharedPointer::Basic, which provides common
- // operations,
- //
+ template <class T> inline void normalDeleter(T *t) { delete t; }
+
+ // this uses partial template specialization
+ // the only compilers that didn't support this were MSVC 6.0 and 2002
+ template <class T> struct RemovePointer;
+ template <class T> struct RemovePointer<T *> { typedef T Type; };
+ template <class T> struct RemovePointer<QSharedPointer<T> > { typedef T Type; };
+ template <class T> struct RemovePointer<QWeakPointer<T> > { typedef T Type; };
+
+ // This class provides the basic functionality of a pointer wrapper.
+ // Its existence is mostly legacy, since originally QSharedPointer
+ // could also be used for internally-refcounted objects.
template <class T>
class Basic
{
+#ifndef Q_CC_NOKIAX86
typedef T *Basic:: *RestrictedBool;
+#endif
public:
typedef T Type;
+ typedef T element_type;
+ typedef T value_type;
+ typedef value_type *pointer;
+ typedef const value_type *const_pointer;
+ typedef value_type &reference;
+ typedef const value_type &const_reference;
+ typedef ptrdiff_t difference_type;
inline T *data() const { return value; }
inline bool isNull() const { return !data(); }
+#ifndef Q_CC_NOKIAX86
inline operator RestrictedBool() const { return isNull() ? 0 : &Basic::value; }
+#else
+ inline operator bool() const { return isNull() ? 0 : &Basic::value; }
+#endif
inline bool operator !() const { return isNull(); }
inline T &operator*() const { return *data(); }
inline T *operator->() const { return data(); }
protected:
- inline Basic() : value(0 * sizeof(T)) { }
+ inline Basic(T *ptr = 0) : value(ptr) { }
+ inline Basic(Qt::Initialization) { }
// ~Basic();
- inline void verifyReconstruction(const T *ptr)
- {
- Q_ASSERT_X(!ptr || value != ptr, "QSharedPointer",
- "QSharedPointer violation: you cannot create two QSharedPointer objects "
- "from the same pointer");
-
- // make use of the "ptr" variable in the no-op statement below
- // since this function is in a public header, we don't
- // want warnings on "unused variables" to show up everywhere
- ptr = 0;
- }
-
inline void internalConstruct(T *ptr)
{
value = ptr;
}
- inline void internalDestroy()
- {
- }
#if defined(Q_NO_TEMPLATE_FRIENDS)
public:
@@ -155,64 +164,220 @@ namespace QtSharedPointer {
Type *value;
};
+ // This class is the d-pointer of QSharedPointer and QWeakPointer.
+ //
+ // It is a reference-counted reference counter. "strongref" is the inner
+ // reference counter, and it tracks the lifetime of the pointer itself.
+ // "weakref" is the outer reference counter and it tracks the lifetime of
+ // the ExternalRefCountData object.
struct ExternalRefCountData
{
- QAtomicInt weakref;
- QAtomicInt strongref;
+ QBasicAtomicInt weakref;
+ QBasicAtomicInt strongref;
- inline ExternalRefCountData() : weakref(1), strongref(1) { }
- virtual inline ~ExternalRefCountData() { Q_ASSERT(!weakref); Q_ASSERT(!strongref); }
+ inline ExternalRefCountData()
+ {
+ strongref = 1;
+ weakref = 1;
+ }
+ inline ExternalRefCountData(Qt::Initialization) { }
+ virtual inline ~ExternalRefCountData() { Q_ASSERT(!weakref); Q_ASSERT(strongref <= 0); }
+ // overridden by derived classes
+ // returns false to indicate caller should delete the pointer
+ // returns true in case it has already done so
virtual inline bool destroy() { return false; }
+
+#ifndef QT_NO_QOBJECT
+ Q_CORE_EXPORT static ExternalRefCountData *getAndRef(const QObject *);
+ Q_CORE_EXPORT void setQObjectShared(const QObject *, bool enable);
+#endif
+ inline void setQObjectShared(...) { }
};
+ // sizeof(ExternalRefCount) = 12 (32-bit) / 16 (64-bit)
- template <class T, typename Deleter>
- struct ExternalRefCountWithSpecializedDeleter: public ExternalRefCountData
+ // This class extends ExternalRefCountData with a pointer
+ // to a function, which is called by the destroy() function.
+ struct ExternalRefCountWithDestroyFn: public ExternalRefCountData
{
- T *ptr;
- Deleter deleter;
+ typedef void (*DestroyerFn)(ExternalRefCountData *);
+ DestroyerFn destroyer;
- inline ExternalRefCountWithSpecializedDeleter(T *p, Deleter d)
- : ptr(p), deleter(d)
+ inline ExternalRefCountWithDestroyFn(DestroyerFn d)
+ : destroyer(d)
{ }
- inline bool destroy() { executeDeleter(ptr, deleter); return true; }
+
+ inline bool destroy() { destroyer(this); return true; }
+ inline void operator delete(void *ptr) { ::operator delete(ptr); }
+ };
+ // sizeof(ExternalRefCountWithDestroyFn) = 16 (32-bit) / 24 (64-bit)
+
+ // This class extends ExternalRefCountWithDestroyFn and implements
+ // the static function that deletes the object. The pointer and the
+ // custom deleter are kept in the "extra" member.
+ template <class T, typename Deleter>
+ struct ExternalRefCountWithCustomDeleter: public ExternalRefCountWithDestroyFn
+ {
+ typedef ExternalRefCountWithCustomDeleter Self;
+ typedef ExternalRefCountWithDestroyFn BaseClass;
+
+ struct CustomDeleter
+ {
+ Deleter deleter;
+ T *ptr;
+
+ inline CustomDeleter(T *p, Deleter d) : deleter(d), ptr(p) {}
+ };
+ CustomDeleter extra;
+ // sizeof(CustomDeleter) = sizeof(Deleter) + sizeof(void*)
+ // for Deleter = function pointer: 8 (32-bit) / 16 (64-bit)
+ // for Deleter = PMF: 12 (32-bit) / 24 (64-bit) (GCC)
+
+ static inline void deleter(ExternalRefCountData *self)
+ {
+ Self *realself = static_cast<Self *>(self);
+ executeDeleter(realself->extra.ptr, realself->extra.deleter);
+
+ // delete the deleter too
+ realself->extra.~CustomDeleter();
+ }
+ static void safetyCheckDeleter(ExternalRefCountData *self)
+ {
+ internalSafetyCheckRemove2(self);
+ deleter(self);
+ }
+
+ static inline Self *create(T *ptr, Deleter userDeleter)
+ {
+# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
+ DestroyerFn destroy = &safetyCheckDeleter;
+# else
+ DestroyerFn destroy = &deleter;
+# endif
+ Self *d = static_cast<Self *>(::operator new(sizeof(Self)));
+
+ // initialize the two sub-objects
+ new (&d->extra) CustomDeleter(ptr, userDeleter);
+ new (d) BaseClass(destroy); // can't throw
+
+ return d;
+ }
+ private:
+ // prevent construction and the emission of virtual symbols
+ ExternalRefCountWithCustomDeleter();
+ ~ExternalRefCountWithCustomDeleter();
};
+ // This class extends ExternalRefCountWithDestroyFn and adds a "T"
+ // member. That way, when the create() function is called, we allocate
+ // memory for both QSharedPointer's d-pointer and the actual object being
+ // tracked.
+ template <class T>
+ struct ExternalRefCountWithContiguousData: public ExternalRefCountWithDestroyFn
+ {
+ typedef ExternalRefCountWithDestroyFn Parent;
+ T data;
+
+ static void deleter(ExternalRefCountData *self)
+ {
+ ExternalRefCountWithContiguousData *that =
+ static_cast<ExternalRefCountWithContiguousData *>(self);
+ that->data.~T();
+ }
+ static void safetyCheckDeleter(ExternalRefCountData *self)
+ {
+ internalSafetyCheckRemove2(self);
+ deleter(self);
+ }
+
+ static inline ExternalRefCountData *create(T **ptr)
+ {
+# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
+ DestroyerFn destroy = &safetyCheckDeleter;
+# else
+ DestroyerFn destroy = &deleter;
+# endif
+ ExternalRefCountWithContiguousData *d =
+ static_cast<ExternalRefCountWithContiguousData *>(::operator new(sizeof(ExternalRefCountWithContiguousData)));
+
+ // initialize the d-pointer sub-object
+ // leave d->data uninitialized
+ new (d) Parent(destroy); // can't throw
+
+ *ptr = &d->data;
+ return d;
+ }
+
+ private:
+ // prevent construction and the emission of virtual symbols
+ ExternalRefCountWithContiguousData();
+ ~ExternalRefCountWithContiguousData();
+ };
+
+ // This is the main body of QSharedPointer. It implements the
+ // external reference counting functionality.
template <class T>
class ExternalRefCount: public Basic<T>
{
- typedef ExternalRefCountData Data;
- typedef void (*DeleterFunction)(T *);
protected:
+ typedef ExternalRefCountData Data;
+
inline void ref() const { d->weakref.ref(); d->strongref.ref(); }
inline bool deref()
{
- if (!d->strongref.deref())
- this->internalDestroy();
+ if (!d->strongref.deref()) {
+ internalDestroy();
+ }
return d->weakref.deref();
}
inline void internalConstruct(T *ptr)
{
- Basic<T>::internalConstruct(ptr);
- Q_ASSERT(!d);
+#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
+ internalConstruct<void (*)(T *)>(ptr, normalDeleter);
+#else
if (ptr)
d = new Data;
+ else
+ d = 0;
+ internalFinishConstruction(ptr);
+#endif
}
template <typename Deleter>
inline void internalConstruct(T *ptr, Deleter deleter)
{
- Basic<T>::internalConstruct(ptr);
- Q_ASSERT(!d);
if (ptr)
- d = new ExternalRefCountWithSpecializedDeleter<T, Deleter>(ptr, deleter);
+ d = ExternalRefCountWithCustomDeleter<T, Deleter>::create(ptr, deleter);
+ else
+ d = 0;
+ internalFinishConstruction(ptr);
+ }
+
+ inline void internalCreate()
+ {
+ T *ptr;
+ d = ExternalRefCountWithContiguousData<T>::create(&ptr);
+ Basic<T>::internalConstruct(ptr);
+ }
+
+ inline void internalFinishConstruction(T *ptr)
+ {
+ Basic<T>::internalConstruct(ptr);
+ if (ptr) d->setQObjectShared(ptr, true);
+#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
+ if (ptr) internalSafetyCheckAdd2(d, ptr);
+#endif
}
inline ExternalRefCount() : d(0) { }
- inline ~ExternalRefCount() { if (d && !deref()) delete d; }
+ inline ExternalRefCount(Qt::Initialization i) : Basic<T>(i) { }
inline ExternalRefCount(const ExternalRefCount<T> &other) : Basic<T>(other), d(other.d)
{ if (d) ref(); }
+ template <class X>
+ inline ExternalRefCount(const ExternalRefCount<X> &other) : Basic<T>(other.value), d(other.d)
+ { if (d) ref(); }
+ inline ~ExternalRefCount() { if (d && !deref()) delete d; }
template <class X>
inline void internalCopy(const ExternalRefCount<X> &other)
@@ -222,32 +387,41 @@ namespace QtSharedPointer {
inline void internalDestroy()
{
- Basic<T>::internalDestroy();
if (!d->destroy())
delete this->value;
}
- private:
+ inline void internalSwap(ExternalRefCount &other)
+ {
+ qSwap(d, other.d);
+ qSwap(this->value, other.value);
+ }
+
#if defined(Q_NO_TEMPLATE_FRIENDS)
public:
#else
template <class X> friend class ExternalRefCount;
template <class X> friend class QWeakPointer;
- template <class X, class Y> friend QSharedPointer<X> qSharedPointerCastHelper(const QSharedPointer<Y> &src, X *);
- template <class X, class Y> friend QSharedPointer<X> qSharedPointerDynamicCastHelper(const QSharedPointer<Y> &src, X *);
- template <class X, class Y> friend QSharedPointer<X> qSharedPointerConstCastHelper(const QSharedPointer<Y> &src, X *);
- template <class X, class Y> friend QSharedPointer<X> QtSharedPointer::qStrongRefFromWeakHelper(const QWeakPointer<Y> &src, X *);
+ template <class X, class Y> friend QSharedPointer<X> copyAndSetPointer(X * ptr, const QSharedPointer<Y> &src);
#endif
inline void internalSet(Data *o, T *actual)
{
- if (d == o) return;
- if (o && !o->strongref)
- o = 0;
if (o) {
- verifyReconstruction(actual);
- o->weakref.ref();
- o->strongref.ref();
+ // increase the strongref, but never up from zero
+ // or less (-1 is used by QWeakPointer on untracked QObject)
+ register int tmp = o->strongref;
+ while (tmp > 0) {
+ // try to increment from "tmp" to "tmp + 1"
+ if (o->strongref.testAndSetRelaxed(tmp, tmp + 1))
+ break; // succeeded
+ tmp = o->strongref; // failed, try again
+ }
+
+ if (tmp > 0)
+ o->weakref.ref();
+ else
+ o = 0;
}
if (d && !deref())
delete d;
@@ -255,9 +429,6 @@ namespace QtSharedPointer {
this->value = d && d->strongref ? actual : 0;
}
-#if defined(QT_BUILD_INTERNAL)
- public:
-#endif
Data *d;
private:
@@ -273,41 +444,41 @@ public:
inline QSharedPointer() { }
// inline ~QSharedPointer() { }
- inline explicit QSharedPointer(T *ptr) { internalConstruct(ptr); }
+ inline explicit QSharedPointer(T *ptr) : BaseClass(Qt::Uninitialized)
+ { BaseClass::internalConstruct(ptr); }
template <typename Deleter>
- inline QSharedPointer(T *ptr, Deleter d) { internalConstruct(ptr, d); }
+ inline QSharedPointer(T *ptr, Deleter d) { BaseClass::internalConstruct(ptr, d); }
inline QSharedPointer(const QSharedPointer<T> &other) : BaseClass(other) { }
inline QSharedPointer<T> &operator=(const QSharedPointer<T> &other)
{
- internalCopy(other);
+ BaseClass::internalCopy(other);
return *this;
}
- inline QSharedPointer(const QWeakPointer<T> &other)
- { *this = QtSharedPointer::qStrongRefFromWeakHelper(other, static_cast<T*>(0)); }
- inline QSharedPointer<T> &operator=(const QWeakPointer<T> &other)
- { *this = QtSharedPointer::qStrongRefFromWeakHelper(other, static_cast<T*>(0)); return *this; }
-
template <class X>
- inline QSharedPointer(const QSharedPointer<X> &other) { *this = other; }
+ inline QSharedPointer(const QSharedPointer<X> &other) : BaseClass(other)
+ { }
template <class X>
inline QSharedPointer<T> &operator=(const QSharedPointer<X> &other)
{
QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X); // if you get an error in this line, the cast is invalid
- internalCopy(other);
+ BaseClass::internalCopy(other);
return *this;
}
template <class X>
- inline QSharedPointer(const QWeakPointer<X> &other)
- { *this = QtSharedPointer::qStrongRefFromWeakHelper(other, static_cast<T *>(0)); }
+ inline QSharedPointer(const QWeakPointer<X> &other) : BaseClass(Qt::Uninitialized)
+ { this->d = 0; *this = other; }
template <class X>
inline QSharedPointer<T> &operator=(const QWeakPointer<X> &other)
- { *this = qStrongRefFromWeakHelper(other, static_cast<T *>(0)); return *this; }
+ { BaseClass::internalSet(other.d, other.value); return *this; }
+
+ inline void swap(QSharedPointer &other)
+ { internalSwap(other); }
template <class X>
QSharedPointer<X> staticCast() const
@@ -327,24 +498,73 @@ public:
return qSharedPointerConstCast<X, T>(*this);
}
+#ifndef QT_NO_QOBJECT
+ template <class X>
+ QSharedPointer<X> objectCast() const
+ {
+ return qSharedPointerObjectCast<X, T>(*this);
+ }
+#endif
+
inline void clear() { *this = QSharedPointer<T>(); }
QWeakPointer<T> toWeakRef() const;
+
+protected:
+ inline explicit QSharedPointer(Qt::Initialization i) : BaseClass(i) {}
+
+public:
+ static inline QSharedPointer<T> create()
+ {
+ QSharedPointer<T> result(Qt::Uninitialized);
+ result.internalCreate();
+
+ // now initialize the data
+ new (result.data()) T();
+ result.internalFinishConstruction(result.data());
+ return result;
+ }
};
template <class T>
class QWeakPointer
{
+#ifndef Q_CC_NOKIAX86
typedef T *QWeakPointer:: *RestrictedBool;
+#endif
typedef QtSharedPointer::ExternalRefCountData Data;
public:
+ typedef T element_type;
+ typedef T value_type;
+ typedef value_type *pointer;
+ typedef const value_type *const_pointer;
+ typedef value_type &reference;
+ typedef const value_type &const_reference;
+ typedef ptrdiff_t difference_type;
+
inline bool isNull() const { return d == 0 || d->strongref == 0 || value == 0; }
+#ifndef Q_CC_NOKIAX86
inline operator RestrictedBool() const { return isNull() ? 0 : &QWeakPointer::value; }
+#else
+ inline operator bool() const { return isNull() ? 0 : &QWeakPointer::value; }
+#endif
inline bool operator !() const { return isNull(); }
+ inline T *data() const { return d == 0 || d->strongref == 0 ? 0 : value; }
inline QWeakPointer() : d(0), value(0) { }
inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; }
+
+#ifndef QT_NO_QOBJECT
+ // special constructor that is enabled only if X derives from QObject
+ template <class X>
+ inline QWeakPointer(X *ptr) : d(ptr ? d->getAndRef(ptr) : 0), value(ptr)
+ { }
+#endif
+ template <class X>
+ inline QWeakPointer &operator=(X *ptr)
+ { return *this = QWeakPointer(ptr); }
+
inline QWeakPointer(const QWeakPointer<T> &o) : d(o.d), value(o.value)
{ if (d) d->weakref.ref(); }
inline QWeakPointer<T> &operator=(const QWeakPointer<T> &o)
@@ -396,7 +616,7 @@ public:
template <class X>
inline bool operator==(const QSharedPointer<X> &o) const
- { return d == o.d && value == static_cast<const T *>(o.data()); }
+ { return d == o.d; }
template <class X>
inline bool operator!=(const QSharedPointer<X> &o) const
@@ -406,12 +626,16 @@ public:
inline QSharedPointer<T> toStrongRef() const { return QSharedPointer<T>(*this); }
+#if defined(QWEAKPOINTER_ENABLE_ARROW)
+ inline T *operator->() const { return data(); }
+#endif
+
private:
#if defined(Q_NO_TEMPLATE_FRIENDS)
public:
#else
- template <class X, class Y> friend QSharedPointer<X> QtSharedPointer::qStrongRefFromWeakHelper(const QWeakPointer<Y> &src, X *);
+ template <class X> friend class QSharedPointer;
#endif
inline void internalSet(Data *o, T *actual)
@@ -473,60 +697,31 @@ bool operator!=(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2)
return ptr2 != ptr1;
}
+template <class T, class X>
+Q_INLINE_TEMPLATE typename T::difference_type operator-(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
+{
+ return ptr1.data() - ptr2.data();
+}
+
template <class T>
Q_INLINE_TEMPLATE QWeakPointer<T> QSharedPointer<T>::toWeakRef() const
{
return QWeakPointer<T>(*this);
}
+template <class T>
+inline void qSwap(QSharedPointer<T> &p1, QSharedPointer<T> &p2)
+{
+ p1.swap(p2);
+}
+
namespace QtSharedPointer {
// helper functions:
template <class X, class T>
- Q_INLINE_TEMPLATE X *qVerifyStaticCast(T *src, X *)
- {
- return static_cast<X *>(src); // if you get an error in this line, the cast is invalid
- }
- template <class X, class T>
- Q_INLINE_TEMPLATE X *qVerifyDynamicCast(T *src, X *)
- {
- return dynamic_cast<X *>(src); // if you get an error in this line, the cast is invalid
- }
- template <class X, class T>
- Q_INLINE_TEMPLATE X *qVerifyConstCast(T *src, X *)
- {
- return const_cast<X *>(src); // if you get an error in this line, the cast is invalid
- }
-
- template <class X, class T>
- Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerCastHelper(const QSharedPointer<T> &src, X *)
- {
- QSharedPointer<X> result;
- register T *ptr = src.data();
- result.internalSet(src.d, static_cast<X *>(ptr));
- return result;
- }
- template <class X, class T>
- Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCastHelper(const QSharedPointer<T> &src, X *)
- {
- QSharedPointer<X> result;
- register T *ptr = src.data();
- result.internalSet(src.d, dynamic_cast<X *>(ptr));
- return result;
- }
- template <class X, class T>
- Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCastHelper(const QSharedPointer<T> &src, X *)
- {
- QSharedPointer<X> result;
- register T *ptr = src.data();
- result.internalSet(src.d, const_cast<X *>(ptr));
- return result;
- }
- template <class X, class T>
- Q_INLINE_TEMPLATE QSharedPointer<X> qStrongRefFromWeakHelper
- (const QT_PREPEND_NAMESPACE(QWeakPointer<T>) &src, X *)
+ Q_INLINE_TEMPLATE QSharedPointer<X> copyAndSetPointer(X *ptr, const QSharedPointer<T> &src)
{
QSharedPointer<X> result;
- result.internalSet(src.d, src.value);
+ result.internalSet(src.d, ptr);
return result;
}
}
@@ -535,9 +730,8 @@ namespace QtSharedPointer {
template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerCast(const QSharedPointer<T> &src)
{
- X *x = 0;
- QtSharedPointer::qVerifyStaticCast(src.data(), x);
- return QtSharedPointer::qSharedPointerCastHelper(src, x);
+ register X *ptr = static_cast<X *>(src.data()); // if you get an error in this line, the cast is invalid
+ return QtSharedPointer::copyAndSetPointer(ptr, src);
}
template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerCast(const QWeakPointer<T> &src)
@@ -548,8 +742,8 @@ Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerCast(const QWeakPointer<T> &sr
template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCast(const QSharedPointer<T> &src)
{
- X *x = 0;
- return QtSharedPointer::qSharedPointerDynamicCastHelper(src, x);
+ register X *ptr = dynamic_cast<X *>(src.data()); // if you get an error in this line, the cast is invalid
+ return QtSharedPointer::copyAndSetPointer(ptr, src);
}
template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCast(const QWeakPointer<T> &src)
@@ -560,14 +754,13 @@ Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCast(const QWeakPointer
template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &src)
{
- X *x = 0;
- return QtSharedPointer::qSharedPointerConstCastHelper(src, x);
+ register X *ptr = const_cast<X *>(src.data()); // if you get an error in this line, the cast is invalid
+ return QtSharedPointer::copyAndSetPointer(ptr, src);
}
template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCast(const QWeakPointer<T> &src)
{
- X *x = 0;
- return QtSharedPointer::qSharedPointerConstCastHelper(src, x);
+ return qSharedPointerConstCast<X, T>(src.toStrongRef());
}
template <class X, class T>
@@ -577,6 +770,34 @@ QWeakPointer<X> qWeakPointerCast(const QSharedPointer<T> &src)
return qSharedPointerCast<X, T>(src).toWeakRef();
}
+#ifndef QT_NO_QOBJECT
+template <class X, class T>
+Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &src)
+{
+ register X *ptr = qobject_cast<X *>(src.data());
+ return QtSharedPointer::copyAndSetPointer(ptr, src);
+}
+template <class X, class T>
+Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<T> &src)
+{
+ return qSharedPointerObjectCast<X>(src.toStrongRef());
+}
+
+template <class X, class T>
+inline QSharedPointer<typename QtSharedPointer::RemovePointer<X>::Type>
+qobject_cast(const QSharedPointer<T> &src)
+{
+ return qSharedPointerObjectCast<typename QtSharedPointer::RemovePointer<X>::Type, T>(src);
+}
+template <class X, class T>
+inline QSharedPointer<typename QtSharedPointer::RemovePointer<X>::Type>
+qobject_cast(const QWeakPointer<T> &src)
+{
+ return qSharedPointerObjectCast<typename QtSharedPointer::RemovePointer<X>::Type, T>(src);
+}
+
+#endif
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/corelib/tools/qsize.cpp b/src/corelib/tools/qsize.cpp
index 0323fe0..dcbcbfc 100644
--- a/src/corelib/tools/qsize.cpp
+++ b/src/corelib/tools/qsize.cpp
@@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QSize
- \ingroup multimedia
+ \ingroup painting
\brief The QSize class defines the size of a two-dimensional
object using integer point precision.
@@ -432,7 +432,7 @@ QDebug operator<<(QDebug dbg, const QSize &s) {
\brief The QSizeF class defines the size of a two-dimensional object
using floating point precision.
- \ingroup multimedia
+ \ingroup painting
A size is specified by a width() and a height(). It can be set in
the constructor and changed using the setWidth(), setHeight(), or
diff --git a/src/corelib/tools/qsize.h b/src/corelib/tools/qsize.h
index e89f93c..53bdd9a 100644
--- a/src/corelib/tools/qsize.h
+++ b/src/corelib/tools/qsize.h
@@ -98,8 +98,10 @@ Q_DECLARE_TYPEINFO(QSize, Q_MOVABLE_TYPE);
QSize stream functions
*****************************************************************************/
+#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QSize &);
Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QSize &);
+#endif
/*****************************************************************************
@@ -171,14 +173,14 @@ inline const QSize operator*(qreal c, const QSize &s)
inline QSize &QSize::operator/=(qreal c)
{
- Q_ASSERT(!qFuzzyCompare(c + 1, 1));
+ Q_ASSERT(!qFuzzyIsNull(c));
wd = qRound(wd/c); ht = qRound(ht/c);
return *this;
}
inline const QSize operator/(const QSize &s, qreal c)
{
- Q_ASSERT(!qFuzzyCompare(c + 1, 1));
+ Q_ASSERT(!qFuzzyIsNull(c));
return QSize(qRound(s.wd/c), qRound(s.ht/c));
}
@@ -249,8 +251,10 @@ Q_DECLARE_TYPEINFO(QSizeF, Q_MOVABLE_TYPE);
QSizeF stream functions
*****************************************************************************/
+#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QSizeF &);
Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QSizeF &);
+#endif
/*****************************************************************************
@@ -327,14 +331,14 @@ inline const QSizeF operator*(qreal c, const QSizeF &s)
inline QSizeF &QSizeF::operator/=(qreal c)
{
- Q_ASSERT(!qFuzzyCompare(c + 1, 1));
+ Q_ASSERT(!qFuzzyIsNull(c));
wd = wd/c; ht = ht/c;
return *this;
}
inline const QSizeF operator/(const QSizeF &s, qreal c)
{
- Q_ASSERT(!qFuzzyCompare(c + 1, 1));
+ Q_ASSERT(!qFuzzyIsNull(c));
return QSizeF(s.wd/c, s.ht/c);
}
diff --git a/src/corelib/tools/qstack.cpp b/src/corelib/tools/qstack.cpp
index b7609c9..29630db 100644
--- a/src/corelib/tools/qstack.cpp
+++ b/src/corelib/tools/qstack.cpp
@@ -45,7 +45,7 @@
\ingroup tools
\ingroup shared
- \mainclass
+
\reentrant
QStack\<T\> is one of Qt's generic \l{container classes}. It implements
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 2515fc4..56caa72 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -45,6 +45,7 @@
#ifndef QT_NO_TEXTCODEC
#include <qtextcodec.h>
#endif
+#include <private/qutfcodec_p.h>
#include <qdatastream.h>
#include <qlist.h>
#include "qlocale.h"
@@ -195,6 +196,68 @@ static int ucstrnicmp(const ushort *a, const ushort *b, int l)
return ucstricmp(a, a + l, b, b + l);
}
+static bool qMemEquals(const quint16 *a, const quint16 *b, int length)
+{
+ // Benchmarking indicates that doing memcmp is much slower than
+ // executing the comparison ourselves.
+ // To make it even faster, we do a 32-bit comparison, comparing
+ // twice the amount of data as a normal word-by-word comparison.
+ //
+ // Benchmarking results on a 2.33 GHz Core2 Duo, with a 64-QChar
+ // block of data, with 4194304 iterations (per iteration):
+ // operation usec cpu ticks
+ // memcmp 330 710
+ // 16-bit 79 167-171
+ // 32-bit aligned 49 105-109
+ //
+ // Testing also indicates that unaligned 32-bit loads are as
+ // performant as 32-bit aligned.
+ if (a == b || !length)
+ return true;
+
+ register union {
+ const quint16 *w;
+ const quint32 *d;
+ quintptr value;
+ } sa, sb;
+ sa.w = a;
+ sb.w = b;
+
+ // check alignment
+ if ((sa.value & 2) == (sb.value & 2)) {
+ // both addresses have the same alignment
+ if (sa.value & 2) {
+ // both addresses are not aligned to 4-bytes boundaries
+ // compare the first character
+ if (*sa.w != *sb.w)
+ return false;
+ --length;
+ ++sa.w;
+ ++sb.w;
+
+ // now both addresses are 4-bytes aligned
+ }
+
+ // both addresses are 4-bytes aligned
+ // do a fast 32-bit comparison
+ register const quint32 *e = sa.d + (length >> 1);
+ for ( ; sa.d != e; ++sa.d, ++sb.d) {
+ if (*sa.d != *sb.d)
+ return false;
+ }
+
+ // do we have a tail?
+ return (length & 1) ? *sa.w == *sb.w : true;
+ } else {
+ // one of the addresses isn't 4-byte aligned but the other is
+ register const quint16 *e = sa.w + length;
+ for ( ; sa.w != e; ++sa.w, ++sb.w) {
+ if (*sa.w != *sb.w)
+ return false;
+ }
+ }
+ return true;
+}
/*!
\internal
@@ -296,7 +359,7 @@ const QString::Null QString::null = { };
\internal
- \ingroup text
+ \ingroup string-processing
When you get an object of type QCharRef, if you can assign to it,
the assignment will apply to the character in the string from
@@ -318,8 +381,8 @@ const QString::Null QString::null = { };
\ingroup tools
\ingroup shared
- \ingroup text
- \mainclass
+ \ingroup string-processing
+
QString stores a string of 16-bit \l{QChar}s, where each QChar
corresponds one Unicode 4.0 character. (Unicode characters
@@ -601,6 +664,74 @@ const QString::Null QString::null = { };
formats, the \e precision represents the maximum number of
significant digits (trailing zeroes are omitted).
+ \section1 More Efficient String Construction
+
+ Using the QString \c{'+'} operator, it is easy to construct a
+ complex string from multiple substrings. You will often write code
+ like this:
+
+ \snippet doc/src/snippets/qstring/stringbuilder.cpp 0
+
+ There is nothing wrong with either of these string constructions,
+ but there are a few hidden inefficiencies. Beginning with Qt 4.6,
+ you can eliminate them.
+
+ First, multiple uses of the \c{'+'} operator usually means
+ multiple memory allocations. When concatenating \e{n} substrings,
+ where \e{n > 2}, there can be as many as \e{n - 1} calls to the
+ memory allocator.
+
+ Second, QLatin1String does not store its length internally but
+ calls qstrlen() when it needs to know its length.
+
+ In 4.6, an internal template class \c{QStringBuilder} has been
+ added along with a few helper functions. This class is marked
+ internal and does not appear in the documentation, because you
+ aren't meant to instantiate it in your code. Its use will be
+ automatic, as described below. The class is found in
+ \c {src/corelib/tools/qstringbuilder.cpp} if you want to have a
+ look at it.
+
+ \c{QStringBuilder} uses expression templates and reimplements the
+ \c{'%'} operator so that when you use \c{'%'} for string
+ concatenation instead of \c{'+'}, multiple substring
+ concatenations will be postponed until the final result is about
+ to be assigned to a QString. At this point, the amount of memory
+ required for the final result is known. The memory allocator is
+ then called \e{once} to get the required space, and the substrings
+ are copied into it one by one.
+
+ \c{QLatin1Literal} is a second internal class that can replace
+ QLatin1String, which can't be changed for compatibility reasons.
+ \c{QLatin1Literal} stores its length, thereby saving time when
+ \c{QStringBuilder} computes the amount of memory required for the
+ final string.
+
+ Additional efficiency is gained by inlining and reduced reference
+ counting (the QString created from a \c{QStringBuilder} typically
+ has a ref count of 1, whereas QString::append() needs an extra
+ test).
+
+ There are three ways you can access this improved method of string
+ construction. The straightforward way is to include
+ \c{QStringBuilder} wherever you want to use it, and use the
+ \c{'%'} operator instead of \c{'+'} when concatenating strings:
+
+ \snippet doc/src/snippets/qstring/stringbuilder.cpp 5
+
+ A more global approach is to include this define:
+
+ \snippet doc/src/snippets/qstring/stringbuilder.cpp 3
+
+ and use \c{'%'} instead of \c{'+'} for string concatenation
+ everywhere. The third approach, which is the most convenient but
+ not entirely source compatible, is to include two defines:
+
+ \snippet doc/src/snippets/qstring/stringbuilder.cpp 4
+
+ and the \c{'+'} will automatically be performed as the
+ \c{QStringBuilder} \c{'%'} everywhere.
+
\sa fromRawData(), QChar, QLatin1String, QByteArray, QStringRef
*/
@@ -834,7 +965,8 @@ int QString::toWCharArray(wchar_t *array) const
Constructs a string initialized with the first \a size characters
of the QChar array \a unicode.
- QString makes a deep copy of the string data.
+ QString makes a deep copy of the string data. The unicode data is copied as
+ is and the Byte Order Mark is preserved if present.
*/
QString::QString(const QChar *unicode, int size)
{
@@ -846,6 +978,7 @@ QString::QString(const QChar *unicode, int size)
d->ref.ref();
} else {
d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar));
+ Q_CHECK_PTR(d);
d->ref = 1;
d->alloc = d->size = size;
d->clean = d->asciiCache = d->simpletext = d->righttoleft = d->capacity = 0;
@@ -869,6 +1002,7 @@ QString::QString(int size, QChar ch)
d->ref.ref();
} else {
d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar));
+ Q_CHECK_PTR(d);
d->ref = 1;
d->alloc = d->size = size;
d->clean = d->asciiCache = d->simpletext = d->righttoleft = d->capacity = 0;
@@ -882,6 +1016,23 @@ QString::QString(int size, QChar ch)
}
}
+/*! \fn QString::QString(int size, Qt::Initialization)
+ \internal
+
+ Constructs a string of the given \a size without initializing the
+ characters. This is only used in \c QStringBuilder::toString().
+*/
+QString::QString(int size, Qt::Initialization)
+{
+ d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar));
+ Q_CHECK_PTR(d);
+ d->ref = 1;
+ d->alloc = d->size = size;
+ d->clean = d->asciiCache = d->simpletext = d->righttoleft = d->capacity = 0;
+ d->data = d->array;
+ d->array[size] = '\0';
+}
+
/*! \fn QString::QString(const QLatin1String &str)
Constructs a copy of the Latin-1 string \a str.
@@ -894,7 +1045,9 @@ QString::QString(int size, QChar ch)
*/
QString::QString(QChar ch)
{
- d = (Data *)qMalloc(sizeof(Data) + sizeof(QChar));
+ void *buf = qMalloc(sizeof(Data) + sizeof(QChar));
+ Q_CHECK_PTR(buf);
+ d = reinterpret_cast<Data *>(buf);
d->ref = 1;
d->alloc = d->size = 1;
d->clean = d->asciiCache = d->simpletext = d->righttoleft = d->capacity = 0;
@@ -1064,8 +1217,7 @@ void QString::realloc(int alloc)
{
if (d->ref != 1 || d->data != d->array) {
Data *x = static_cast<Data *>(qMalloc(sizeof(Data) + alloc * sizeof(QChar)));
- if (!x)
- return;
+ Q_CHECK_PTR(x);
x->size = qMin(alloc, d->size);
::memcpy(x->array, d->data, x->size * sizeof(QChar));
x->array[x->size] = 0;
@@ -1087,12 +1239,9 @@ void QString::realloc(int alloc)
asciiCache->remove(d);
}
#endif
- Data *x = static_cast<Data *>(qRealloc(d, sizeof(Data) + alloc * sizeof(QChar)));
- if (!x)
- return;
- x->alloc = alloc;
- x->data = x->array;
- d = x;
+ d = static_cast<Data *>(q_check_ptr(qRealloc(d, sizeof(Data) + alloc * sizeof(QChar))));
+ d->alloc = alloc;
+ d->data = d->array;
}
}
@@ -1246,6 +1395,7 @@ QString& QString::insert(int i, const QChar *unicode, int size)
if (s >= d->data && s < d->data + d->alloc) {
// Part of me - take a copy
ushort *tmp = static_cast<ushort *>(qMalloc(size * sizeof(QChar)));
+ Q_CHECK_PTR(tmp);
memcpy(tmp, s, size * sizeof(QChar));
insert(i, reinterpret_cast<const QChar *>(tmp), size);
qFree(tmp);
@@ -1600,51 +1750,69 @@ QString &QString::replace(const QString &before, const QString &after, Qt::CaseS
*/
void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar *after, int alen)
{
- if (blen == alen) {
- detach();
- for (int i = 0; i < nIndices; ++i)
- memcpy(d->data + indices[i], after, alen * sizeof(QChar));
- } else if (alen < blen) {
+ // copy *after in case it lies inside our own d->data area
+ // (which we could possibly invalidate via a realloc or corrupt via memcpy operations.)
+ QChar *afterBuffer = const_cast<QChar *>(after);
+ if (after >= reinterpret_cast<QChar *>(d->data) && after < reinterpret_cast<QChar *>(d->data) + d->size) {
+ afterBuffer = static_cast<QChar *>(qMalloc(alen*sizeof(QChar)));
+ Q_CHECK_PTR(afterBuffer);
+ ::memcpy(afterBuffer, after, alen*sizeof(QChar));
+ }
+
+ QT_TRY {
detach();
- uint to = indices[0];
- if (alen)
- memcpy(d->data+to, after, alen*sizeof(QChar));
- to += alen;
- uint movestart = indices[0] + blen;
- for (int i = 1; i < nIndices; ++i) {
- int msize = indices[i] - movestart;
- if (msize > 0) {
- memmove(d->data + to, d->data + movestart, msize * sizeof(QChar));
- to += msize;
+ if (blen == alen) {
+ // replace in place
+ for (int i = 0; i < nIndices; ++i)
+ memcpy(d->data + indices[i], afterBuffer, alen * sizeof(QChar));
+ } else if (alen < blen) {
+ // replace from front
+ uint to = indices[0];
+ if (alen)
+ memcpy(d->data+to, after, alen*sizeof(QChar));
+ to += alen;
+ uint movestart = indices[0] + blen;
+ for (int i = 1; i < nIndices; ++i) {
+ int msize = indices[i] - movestart;
+ if (msize > 0) {
+ memmove(d->data + to, d->data + movestart, msize * sizeof(QChar));
+ to += msize;
+ }
+ if (alen) {
+ memcpy(d->data + to, afterBuffer, alen*sizeof(QChar));
+ to += alen;
+ }
+ movestart = indices[i] + blen;
}
- if (alen) {
- memcpy(d->data + to, after, alen*sizeof(QChar));
- to += alen;
+ int msize = d->size - movestart;
+ if (msize > 0)
+ memmove(d->data + to, d->data + movestart, msize * sizeof(QChar));
+ resize(d->size - nIndices*(blen-alen));
+ } else {
+ // replace from back
+ int adjust = nIndices*(alen-blen);
+ int newLen = d->size + adjust;
+ int moveend = d->size;
+ resize(newLen);
+
+ while (nIndices) {
+ --nIndices;
+ int movestart = indices[nIndices] + blen;
+ int insertstart = indices[nIndices] + nIndices*(alen-blen);
+ int moveto = insertstart + alen;
+ memmove(d->data + moveto, d->data + movestart,
+ (moveend - movestart)*sizeof(QChar));
+ memcpy(d->data + insertstart, afterBuffer, alen*sizeof(QChar));
+ moveend = movestart-blen;
}
- movestart = indices[i] + blen;
- }
- int msize = d->size - movestart;
- if (msize > 0)
- memmove(d->data + to, d->data + movestart, msize * sizeof(QChar));
- resize(d->size - nIndices*(blen-alen));
- } else {
- // we have a table of replacement positions, use them for fast replacing
- int adjust = nIndices*(alen-blen);
- int newLen = d->size + adjust;
- int moveend = d->size;
- resize(newLen);
-
- while (nIndices) {
- --nIndices;
- int movestart = indices[nIndices] + blen;
- int insertstart = indices[nIndices] + nIndices*(alen-blen);
- int moveto = insertstart + alen;
- memmove(d->data + moveto, d->data + movestart,
- (moveend - movestart)*sizeof(QChar));
- memcpy(d->data + insertstart, after, alen*sizeof(QChar));
- moveend = movestart-blen;
}
+ } QT_CATCH(const std::bad_alloc &) {
+ if (afterBuffer != after)
+ qFree(afterBuffer);
+ QT_RETHROW;
}
+ if (afterBuffer != after)
+ qFree(afterBuffer);
}
/*!
@@ -1672,21 +1840,7 @@ QString &QString::replace(const QChar *before, int blen,
if (alen == 0 && blen == 0)
return *this;
- // protect against before or after being part of this
- const QChar *a = after;
- const QChar *b = before;
- if (after >= (const QChar *)d->data && after < (const QChar *)d->data + d->size) {
- QChar *copy = (QChar *)malloc(alen*sizeof(QChar));
- memcpy(copy, after, alen*sizeof(QChar));
- a = copy;
- }
- if (before >= (const QChar *)d->data && before < (const QChar *)d->data + d->size) {
- QChar *copy = (QChar *)malloc(blen*sizeof(QChar));
- memcpy(copy, before, blen*sizeof(QChar));
- b = copy;
- }
-
- QStringMatcher matcher(b, blen, cs);
+ QStringMatcher matcher(before, blen, cs);
int index = 0;
while (1) {
@@ -1705,7 +1859,7 @@ QString &QString::replace(const QChar *before, int blen,
if (!pos)
break;
- replace_helper(indices, pos, blen, a, alen);
+ replace_helper(indices, pos, blen, after, alen);
if (index == -1)
break;
@@ -1713,11 +1867,6 @@ QString &QString::replace(const QChar *before, int blen,
index += pos*(alen-blen);
}
- if (a != after)
- ::free((QChar *)a);
- if (b != before)
- ::free((QChar *)b);
-
return *this;
}
@@ -1908,8 +2057,10 @@ QString &QString::replace(QChar c, const QLatin1String &after, Qt::CaseSensitivi
*/
bool QString::operator==(const QString &other) const
{
- return (size() == other.size()) &&
- (memcmp((char*)unicode(),(char*)other.unicode(), size()*sizeof(QChar))==0);
+ if (d->size != other.d->size)
+ return false;
+
+ return qMemEquals(d->data, other.d->data, d->size);
}
/*!
@@ -3136,7 +3287,7 @@ bool QString::startsWith(const QString& s, Qt::CaseSensitivity cs) const
if (s.d->size > d->size)
return false;
if (cs == Qt::CaseSensitive) {
- return memcmp((char*)d->data, (char*)s.d->data, s.d->size*sizeof(QChar)) == 0;
+ return qMemEquals(d->data, s.d->data, s.d->size);
} else {
uint last = 0;
uint olast = 0;
@@ -3207,7 +3358,7 @@ bool QString::endsWith(const QString& s, Qt::CaseSensitivity cs) const
if (pos < 0)
return false;
if (cs == Qt::CaseSensitive) {
- return memcmp((char*)&d->data[pos], (char*)s.d->data, s.d->size*sizeof(QChar)) == 0;
+ return qMemEquals(d->data + pos, s.d->data, s.d->size);
} else {
uint last = 0;
uint olast = 0;
@@ -3332,7 +3483,7 @@ QByteArray QString::toAscii() const
return toLatin1();
}
-#ifndef Q_WS_MAC
+#if !defined(Q_WS_MAC) && defined(Q_OS_UNIX)
static QByteArray toLocal8Bit_helper(const QChar *data, int length)
{
#ifndef QT_NO_TEXTCODEC
@@ -3450,6 +3601,7 @@ QString::Data *QString::fromLatin1_helper(const char *str, int size)
if (size < 0)
size = qstrlen(str);
d = static_cast<Data *>(qMalloc(sizeof(Data) + size * sizeof(QChar)));
+ Q_CHECK_PTR(d);
d->ref = 1;
d->alloc = d->size = size;
d->clean = d->asciiCache = d->simpletext = d->righttoleft = d->capacity = 0;
@@ -3457,7 +3609,7 @@ QString::Data *QString::fromLatin1_helper(const char *str, int size)
ushort *i = d->data;
d->array[size] = '\0';
while (size--)
- *i++ = (uchar)*str++;
+ *i++ = (uchar)*str++;
}
return d;
}
@@ -3566,13 +3718,13 @@ QByteArray qt_winQString2MB(const QChar *ch, int uclen)
BOOL used_def;
QByteArray mb(4096, 0);
int len;
- while (!(len=WideCharToMultiByte(CP_ACP, 0, (const WCHAR*)ch, uclen,
+ while (!(len=WideCharToMultiByte(CP_ACP, 0, (const wchar_t*)ch, uclen,
mb.data(), mb.size()-1, 0, &used_def)))
{
int r = GetLastError();
if (r == ERROR_INSUFFICIENT_BUFFER) {
mb.resize(1+WideCharToMultiByte(CP_ACP, 0,
- (const WCHAR*)ch, uclen,
+ (const wchar_t*)ch, uclen,
0, 0, 0, &used_def));
// and try again...
} else {
@@ -3593,9 +3745,9 @@ QString qt_winMB2QString(const char *mb, int mblen)
if (!mb || !mblen)
return QString();
const int wclen_auto = 4096;
- WCHAR wc_auto[wclen_auto];
+ wchar_t wc_auto[wclen_auto];
int wclen = wclen_auto;
- WCHAR *wc = wc_auto;
+ wchar_t *wc = wc_auto;
int len;
while (!(len=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
mb, mblen, wc, wclen)))
@@ -3608,7 +3760,7 @@ QString qt_winMB2QString(const char *mb, int mblen)
} else {
wclen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
mb, mblen, 0, 0);
- wc = new WCHAR[wclen];
+ wc = new wchar_t[wclen];
// and try again...
}
} else {
@@ -3651,11 +3803,6 @@ QString QString::fromLocal8Bit(const char *str, int size)
return QString();
if (size == 0 || (!*str && size < 0))
return QLatin1String("");
-#if defined(Q_OS_WIN32)
- if(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) {
- return qt_winMB2QString(str, size);
- }
-#endif
#if !defined(QT_NO_TEXTCODEC)
if (size < 0)
size = qstrlen(str);
@@ -3700,75 +3847,7 @@ QString QString::fromUtf8(const char *str, int size)
if (size < 0)
size = qstrlen(str);
- QString result;
- result.resize(size); // worst case
- ushort *qch = result.d->data;
- uint uc = 0;
- uint min_uc = 0;
- int need = 0;
- int error = -1;
- uchar ch;
- int i = 0;
-
- // skip utf8-encoded byte order mark
- if (size >= 3
- && (uchar)str[0] == 0xef && (uchar)str[1] == 0xbb && (uchar)str[2] == 0xbf)
- i += 3;
-
- for (; i < size; ++i) {
- ch = str[i];
- if (need) {
- if ((ch&0xc0) == 0x80) {
- uc = (uc << 6) | (ch & 0x3f);
- need--;
- if (!need) {
- if (uc > 0xffffU && uc < 0x110000U) {
- // surrogate pair
- *qch++ = QChar::highSurrogate(uc);
- uc = QChar::lowSurrogate(uc);
- } else if ((uc < min_uc) || (uc >= 0xd800 && uc <= 0xdfff) || (uc >= 0xfffe)) {
- // overlong seqence, UTF16 surrogate or BOM
- uc = QChar::ReplacementCharacter;
- }
- *qch++ = uc;
- }
- } else {
- i = error;
- need = 0;
- *qch++ = QChar::ReplacementCharacter;
- }
- } else {
- if (ch < 128) {
- *qch++ = ch;
- } else if ((ch & 0xe0) == 0xc0) {
- uc = ch & 0x1f;
- need = 1;
- error = i;
- min_uc = 0x80;
- } else if ((ch & 0xf0) == 0xe0) {
- uc = ch & 0x0f;
- need = 2;
- error = i;
- min_uc = 0x800;
- } else if ((ch&0xf8) == 0xf0) {
- uc = ch & 0x07;
- need = 3;
- error = i;
- min_uc = 0x10000;
- } else {
- // Error
- *qch++ = QChar::ReplacementCharacter;
- }
- }
- }
- if (need) {
- // we have some invalid characters remaining we need to add to the string
- for (int i = error; i < size; ++i)
- *qch++ = QChar::ReplacementCharacter;
- }
-
- result.truncate(qch - result.d->data);
- return result;
+ return QUtf8::convertToUnicode(str, size, 0);
}
/*!
@@ -3791,7 +3870,7 @@ QString QString::fromUtf16(const ushort *unicode, int size)
while (unicode[size] != 0)
++size;
}
- return QString((const QChar *)unicode, size);
+ return QUtf16::convertToUnicode((const char *)unicode, size*2, 0);
}
@@ -3815,21 +3894,7 @@ QString QString::fromUcs4(const uint *unicode, int size)
while (unicode[size] != 0)
++size;
}
-
- QString s;
- s.resize(size*2); // worst case
- ushort *uc = s.d->data;
- for (int i = 0; i < size; ++i) {
- uint u = unicode[i];
- if (u > 0xffff) {
- // decompose into a surrogate pair
- *uc++ = QChar::highSurrogate(u);
- u = QChar::lowSurrogate(u);
- }
- *uc++ = u;
- }
- s.resize(uc - s.d->data);
- return s;
+ return QUtf32::convertToUnicode((const char *)unicode, size*4, 0);
}
/*!
@@ -3880,8 +3945,7 @@ QString QString::simplified() const
{
if (d->size == 0)
return *this;
- QString result;
- result.resize(d->size);
+ QString result(d->size, Qt::Uninitialized);
const QChar *from = (const QChar*) d->data;
const QChar *fromend = (const QChar*) from+d->size;
int outc=0;
@@ -4552,16 +4616,7 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
return ucstrcmp(data1, length1, data2, length2);
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
- int res;
- QT_WA({
- const TCHAR* s1 = (TCHAR*)data1;
- const TCHAR* s2 = (TCHAR*)data2;
- res = CompareStringW(GetUserDefaultLCID(), 0, s1, length1, s2, length2);
- } , {
- QByteArray s1 = toLocal8Bit_helper(data1, length1);
- QByteArray s2 = toLocal8Bit_helper(data2, length2);
- res = CompareStringA(GetUserDefaultLCID(), 0, s1.data(), s1.length(), s2.data(), s2.length());
- });
+ int res = CompareString(GetUserDefaultLCID(), 0, (wchar_t*)data1, length1, (wchar_t*)data2, length2);
switch (res) {
case CSTR_LESS_THAN:
@@ -4733,8 +4788,7 @@ QString QString::toLower() const
c = QChar::surrogateToUcs4(*(p - 1), c);
const QUnicodeTables::Properties *prop = qGetProp(c);
if (prop->lowerCaseDiff || prop->lowerCaseSpecial) {
- QString s;
- s.resize(d->size);
+ QString s(d->size, Qt::Uninitialized);
memcpy(s.d->data, d->data, (p - d->data)*sizeof(ushort));
ushort *pp = s.d->data + (p - d->data);
while (p < e) {
@@ -4825,8 +4879,7 @@ QString QString::toUpper() const
c = QChar::surrogateToUcs4(*(p - 1), c);
const QUnicodeTables::Properties *prop = qGetProp(c);
if (prop->upperCaseDiff || prop->upperCaseSpecial) {
- QString s;
- s.resize(d->size);
+ QString s(d->size, Qt::Uninitialized);
memcpy(s.d->data, d->data, (p - d->data)*sizeof(ushort));
ushort *pp = s.d->data + (p - d->data);
while (p < e) {
@@ -5977,6 +6030,7 @@ QString QString::repeated(int times) const
return result;
}
+void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, int from);
/*!
\overload
\fn QString QString::normalized(NormalizationForm mode, QChar::UnicodeVersion version) const
@@ -5986,42 +6040,48 @@ QString QString::repeated(int times) const
*/
QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersion version) const
{
+ QString copy = *this;
+ qt_string_normalize(&copy, mode, version, 0);
+ return copy;
+}
+
+void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, int from)
+{
bool simple = true;
- for (int i = 0; i < d->size; ++i) {
- if (d->data[i] >= 0x80) {
+ const QChar *p = data->constData();
+ int len = data->length();
+ for (int i = from; i < len; ++i) {
+ if (p[i].unicode() >= 0x80) {
simple = false;
break;
}
}
if (simple)
- return *this;
+ return;
- QString s = *this;
+ QString &s = *data;
if (version != CURRENT_VERSION) {
for (int i = 0; i < NumNormalizationCorrections; ++i) {
const NormalizationCorrection &n = uc_normalization_corrections[i];
if (n.version > version) {
+ int pos = from;
if (n.ucs4 > 0xffff) {
ushort ucs4High = QChar::highSurrogate(n.ucs4);
ushort ucs4Low = QChar::lowSurrogate(n.ucs4);
ushort oldHigh = QChar::highSurrogate(n.old_mapping);
ushort oldLow = QChar::lowSurrogate(n.old_mapping);
- int pos = 0;
- while (pos < s.d->size - 1) {
- if (s.d->data[pos] == ucs4High && s.d->data[pos + 1] == ucs4Low) {
- s.detach();
- s.d->data[pos] = oldHigh;
- s.d->data[pos + 1] = oldLow;
+ while (pos < s.length() - 1) {
+ if (s.at(pos).unicode() == ucs4High && s.at(pos + 1).unicode() == ucs4Low) {
+ s[pos] = oldHigh;
+ s[pos + 1] = oldLow;
++pos;
}
++pos;
}
} else {
- int pos = 0;
- while (pos < s.d->size) {
- if (s.d->data[pos] == n.ucs4) {
- s.detach();
- s.d->data[pos] = n.old_mapping;
+ while (pos < s.length()) {
+ if (s.at(pos).unicode() == n.ucs4) {
+ s[pos] = n.old_mapping;
}
++pos;
}
@@ -6029,15 +6089,14 @@ QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersi
}
}
}
- s = decomposeHelper(s, mode < QString::NormalizationForm_KD, version);
+ decomposeHelper(data, mode < QString::NormalizationForm_KD, version, from);
- s = canonicalOrderHelper(s, version);
+ canonicalOrderHelper(data, version, from);
if (mode == QString::NormalizationForm_D || mode == QString::NormalizationForm_KD)
- return s;
-
- return composeHelper(s);
+ return;
+ composeHelper(data, from);
}
@@ -6123,8 +6182,7 @@ static QString replaceArgEscapes(const QString &s, const ArgEscapeData &d, int f
+ d.locale_occurrences
*qMax(abs_field_width, larg.length());
- QString result;
- result.resize(result_len);
+ QString result(result_len, Qt::Uninitialized);
QChar *result_buff = (QChar*) result.unicode();
QChar *rc = result_buff;
@@ -6423,7 +6481,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, const QChar &fillCha
ArgEscapeData d = findArgEscapes(*this);
if (d.occurrences == 0) {
- qWarning("QString::arg: Argument missing: %s, %lld", toLocal8Bit().data(), a);
+ qWarning() << "QString::arg: Argument missing:" << *this << ',' << a;
return *this;
}
@@ -6466,7 +6524,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, const QChar &fillCh
ArgEscapeData d = findArgEscapes(*this);
if (d.occurrences == 0) {
- qWarning("QString::arg: Argument missing: %s, %llu", toLocal8Bit().data(), a);
+ qWarning() << "QString::arg: Argument missing:" << *this << ',' << a;
return *this;
}
@@ -6867,6 +6925,7 @@ void QString::updateProperties() const
QString QString::fromRawData(const QChar *unicode, int size)
{
Data *x = static_cast<Data *>(qMalloc(sizeof(Data)));
+ Q_CHECK_PTR(x);
if (unicode) {
x->data = (ushort *)unicode;
} else {
@@ -6883,7 +6942,7 @@ QString QString::fromRawData(const QChar *unicode, int size)
/*! \class QLatin1String
\brief The QLatin1String class provides a thin wrapper around an ASCII/Latin-1 encoded string literal.
- \ingroup text
+ \ingroup string-processing
\reentrant
Many of QString's member functions are overloaded to accept
@@ -7505,7 +7564,7 @@ QDataStream &operator>>(QDataStream &in, QString &str)
\brief The QStringRef class provides a thin wrapper around QString substrings.
\reentrant
\ingroup tools
- \ingroup text
+ \ingroup string-processing
QStringRef provides a read-only subset of the QString API.
@@ -7692,7 +7751,8 @@ QString QStringRef::toString() const {
*/
bool operator==(const QStringRef &s1,const QStringRef &s2)
{ return (s1.size() == s2.size() &&
- (memcmp((char*)s1.unicode(), (char*)s2.unicode(), s1.size()*sizeof(QChar))==0)); }
+ qMemEquals((const ushort *)s1.unicode(), (const ushort *)s2.unicode(), s1.size()));
+}
/*! \relates QStringRef
@@ -7701,7 +7761,8 @@ bool operator==(const QStringRef &s1,const QStringRef &s2)
*/
bool operator==(const QString &s1,const QStringRef &s2)
{ return (s1.size() == s2.size() &&
- (memcmp((char*)s1.unicode(), (char*)s2.unicode(), s1.size()*sizeof(QChar))==0)); }
+ qMemEquals((const ushort *)s1.unicode(), (const ushort *)s2.unicode(), s1.size()));
+}
/*! \relates QStringRef
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index 303f79b..ce70707 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -579,6 +579,8 @@ public:
bool isSimpleText() const { if (!d->clean) updateProperties(); return d->simpletext; }
bool isRightToLeft() const { if (!d->clean) updateProperties(); return d->righttoleft; }
+ QString(int size, Qt::Initialization);
+
private:
#if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED)
QString &operator+=(const char *s);
@@ -1001,13 +1003,15 @@ inline int QByteArray::findRev(const QString &s, int from) const
# endif // QT3_SUPPORT
#endif // QT_NO_CAST_TO_ASCII
+#ifndef QT_USE_FAST_OPERATOR_PLUS
+# ifndef QT_USE_FAST_CONCATENATION
inline const QString operator+(const QString &s1, const QString &s2)
{ QString t(s1); t += s2; return t; }
inline const QString operator+(const QString &s1, QChar s2)
{ QString t(s1); t += s2; return t; }
inline const QString operator+(QChar s1, const QString &s2)
{ QString t(s1); t += s2; return t; }
-#ifndef QT_NO_CAST_FROM_ASCII
+# ifndef QT_NO_CAST_FROM_ASCII
inline QT_ASCII_CAST_WARN const QString operator+(const QString &s1, const char *s2)
{ QString t(s1); t += QString::fromAscii(s2); return t; }
inline QT_ASCII_CAST_WARN const QString operator+(const char *s1, const QString &s2)
@@ -1020,7 +1024,9 @@ inline QT_ASCII_CAST_WARN const QString operator+(const QByteArray &ba, const QS
{ QString t = QString::fromAscii(ba.constData(), qstrnlen(ba.constData(), ba.size())); t += s; return t; }
inline QT_ASCII_CAST_WARN const QString operator+(const QString &s, const QByteArray &ba)
{ QString t(s); t += QString::fromAscii(ba.constData(), qstrnlen(ba.constData(), ba.size())); return t; }
-#endif
+# endif // QT_NO_CAST_FROM_ASCII
+# endif // QT_USE_FAST_CONCATENATION
+#endif // QT_USE_FAST_OPERATOR_PLUS
#ifndef QT_NO_STL
inline std::string QString::toStdString() const
@@ -1231,4 +1237,8 @@ QT_END_NAMESPACE
QT_END_HEADER
+#ifdef QT_USE_FAST_CONCATENATION
+#include <QtCore/qstringbuilder.h>
+#endif
+
#endif // QSTRING_H
diff --git a/src/corelib/tools/qstringbuilder.cpp b/src/corelib/tools/qstringbuilder.cpp
new file mode 100644
index 0000000..04fbb93
--- /dev/null
+++ b/src/corelib/tools/qstringbuilder.cpp
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstringbuilder.h"
+
+/*!
+ \class QLatin1Literal
+ \internal
+ \reentrant
+ \since 4.6
+
+ \brief The QLatin1Literal class provides a thin wrapper around string
+ literals used in source code.
+
+ \ingroup tools
+ \ingroup shared
+ \ingroup string-processing
+
+
+ Unlike \c QLatin1String, a \c QLatin1Literal can retrieve its size
+ without iterating over the literal.
+
+ The main use of \c QLatin1Literal is in conjunction with \c QStringBuilder
+ to reduce the number of reallocations needed to build up a string from
+ smaller chunks.
+
+ \sa QStringBuilder, QLatin1String, QString, QStringRef
+*/
+
+/*! \fn int QLatin1Literal::size() const
+
+ Returns the number of characters in the literal \e{excluding} the trailing
+ NULL char.
+*/
+
+/*! \fn QLatin1Literal::QLatin1Literal(const char str)
+
+ Constructs a new literal from the string \a str.
+*/
+
+/*! \fn const char *QLatin1Literal::data() const
+
+ Returns a pointer to the first character of the string literal.
+ The string literal is terminated by a NUL character.
+*/
+
+/*!
+ \class QStringBuilder
+ \internal
+ \reentrant
+ \since 4.6
+
+ \brief The QStringBuilder class is a template class that provides a facility to build up QStrings from smaller chunks.
+
+ \ingroup tools
+ \ingroup shared
+ \ingroup string-processing
+
+
+ To build a QString by multiple concatenations, QString::operator+()
+ is typically used. This causes \e{n - 1} reallocations when building
+ a string from \e{n} chunks.
+
+ QStringBuilder uses expression templates to collect the individual
+ chunks, compute the total size, allocate the required amount of
+ memory for the final QString object, and copy the chunks into the
+ allocated memory.
+
+ The QStringBuilder class is not to be used explicitly in user
+ code. Instances of the class are created as return values of the
+ operator%() function, acting on objects of type QString,
+ QLatin1String, QLatin1Literal, QStringRef, QChar, QCharRef,
+ QLatin1Char, and \c char.
+
+ Concatenating strings with operator%() generally yields better
+ performance then using \c QString::operator+() on the same chunks
+ if there are three or more of them, and performs equally well in other
+ cases.
+
+ \sa QLatin1Literal, QString
+*/
+
+/*! \fn QStringBuilder::QStringBuilder(const A &a, const B &b)
+ Constructs a QStringBuilder from \a a and \a b.
+ */
+
+/* \fn QStringBuilder::operator%(const A &a, const B &b)
+
+ Returns a \c QStringBuilder object that is converted to a QString object
+ when assigned to a variable of QString type or passed to a function that
+ takes a QString parameter.
+
+ This function is usable with arguments of type \c QString,
+ \c QLatin1String, \c QLatin1Literal, \c QStringRef,
+ \c QChar, \c QCharRef, \c QLatin1Char, and \c char.
+*/
+
+/*! \fn QByteArray QStringBuilder::toLatin1() const
+ Returns a Latin-1 representation of the string as a QByteArray. The
+ returned byte array is undefined if the string contains non-Latin1
+ characters.
+ */
+
+/*! \fn QStringBuilder::operator QString() const
+
+ Converts the \c QLatin1Literal into a \c QString object.
+*/
diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h
new file mode 100644
index 0000000..9be57c5
--- /dev/null
+++ b/src/corelib/tools/qstringbuilder.h
@@ -0,0 +1,260 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTRINGBUILDER_H
+#define QSTRINGBUILDER_H
+
+#include <QtCore/qstring.h>
+
+#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
+# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0)
+# include <QtCore/qmap.h>
+# endif
+#endif
+
+#include <string.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+// ### Qt 5: merge with QLatin1String
+class QLatin1Literal
+{
+public:
+ int size() const { return m_size; }
+ const char *data() const { return m_data; }
+
+ template <int N>
+ QLatin1Literal(const char (&str)[N])
+ : m_size(N - 1), m_data(str) {}
+
+private:
+ const int m_size;
+ const char *m_data;
+};
+
+
+template <typename T> struct QConcatenable {};
+
+template <typename A, typename B>
+class QStringBuilder
+{
+public:
+ QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {}
+
+ operator QString() const
+ {
+ QString s(QConcatenable< QStringBuilder<A, B> >::size(*this),
+ Qt::Uninitialized);
+
+ QChar *d = s.data();
+ QConcatenable< QStringBuilder<A, B> >::appendTo(*this, d);
+ return s;
+ }
+ QByteArray toLatin1() const { return QString(*this).toLatin1(); }
+
+ const A &a;
+ const B &b;
+};
+
+
+template <> struct QConcatenable<char>
+{
+ typedef char type;
+ static int size(const char) { return 1; }
+ static inline void appendTo(const char c, QChar *&out)
+ {
+ *out++ = QLatin1Char(c);
+ }
+};
+
+template <> struct QConcatenable<QLatin1Char>
+{
+ typedef QLatin1Char type;
+ static int size(const QLatin1Char) { return 1; }
+ static inline void appendTo(const QLatin1Char c, QChar *&out)
+ {
+ *out++ = c;
+ }
+};
+
+template <> struct QConcatenable<QChar>
+{
+ typedef QChar type;
+ static int size(const QChar) { return 1; }
+ static inline void appendTo(const QChar c, QChar *&out)
+ {
+ *out++ = c;
+ }
+};
+
+template <> struct QConcatenable<QCharRef>
+{
+ typedef QCharRef type;
+ static int size(const QCharRef &) { return 1; }
+ static inline void appendTo(const QCharRef &c, QChar *&out)
+ {
+ *out++ = QChar(c);
+ }
+};
+
+template <> struct QConcatenable<QLatin1String>
+{
+ typedef QLatin1String type;
+ static int size(const QLatin1String &a) { return qstrlen(a.latin1()); }
+ static inline void appendTo(const QLatin1String &a, QChar *&out)
+ {
+ for (const char *s = a.latin1(); *s; )
+ *out++ = QLatin1Char(*s++);
+ }
+
+};
+
+template <> struct QConcatenable<QLatin1Literal>
+{
+ typedef QLatin1Literal type;
+ static int size(const QLatin1Literal &a) { return a.size(); }
+ static inline void appendTo(const QLatin1Literal &a, QChar *&out)
+ {
+ for (const char *s = a.data(); *s; )
+ *out++ = QLatin1Char(*s++);
+ }
+};
+
+template <> struct QConcatenable<QString>
+{
+ typedef QString type;
+ static int size(const QString &a) { return a.size(); }
+ static inline void appendTo(const QString &a, QChar *&out)
+ {
+ const int n = a.size();
+ memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
+ out += n;
+ }
+};
+
+template <> struct QConcatenable<QStringRef>
+{
+ typedef QStringRef type;
+ static int size(const QStringRef &a) { return a.size(); }
+ static inline void appendTo(QStringRef a, QChar *&out)
+ {
+ const int n = a.size();
+ memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
+ out += n;
+ }
+};
+
+#ifndef QT_NO_CAST_FROM_ASCII
+template <int N> struct QConcatenable<char[N]>
+{
+ typedef char type[N];
+ static int size(const char[N]) { return N - 1; }
+ static inline void appendTo(const char a[N], QChar *&out)
+ {
+ for (int i = 0; i < N - 1; ++i)
+ *out++ = QLatin1Char(a[i]);
+ }
+};
+
+template <> struct QConcatenable<const char *>
+{
+ typedef char const *type;
+ static int size(const char *a) { return qstrlen(a); }
+ static inline void appendTo(const char *a, QChar *&out)
+ {
+ while (*a)
+ *out++ = QLatin1Char(*a++);
+ }
+};
+
+template <> struct QConcatenable<QByteArray>
+{
+ typedef QByteArray type;
+ static int size(const QByteArray &ba) { return qstrnlen(ba.constData(), ba.size()); }
+ static inline void appendTo(const QByteArray &ba, QChar *&out)
+ {
+ const char *data = ba.constData();
+ while (*data)
+ *out++ = QLatin1Char(*data++);
+ }
+};
+#endif
+
+template <typename A, typename B>
+struct QConcatenable< QStringBuilder<A, B> >
+{
+ typedef QStringBuilder<A, B> type;
+ static int size(const type &p)
+ {
+ return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b);
+ }
+ static inline void appendTo(const QStringBuilder<A, B> &p, QChar *&out)
+ {
+ QConcatenable<A>::appendTo(p.a, out);
+ QConcatenable<B>::appendTo(p.b, out);
+ }
+};
+
+template <typename A, typename B>
+QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
+operator%(const A &a, const B &b)
+{
+ return QStringBuilder<A, B>(a, b);
+}
+
+#ifdef QT_USE_FAST_OPERATOR_PLUS
+template <typename A, typename B>
+QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
+operator+(const A &a, const B &b)
+{
+ return QStringBuilder<A, B>(a, b);
+}
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSTRINGBUILDER_H
diff --git a/src/corelib/tools/qstringlist.cpp b/src/corelib/tools/qstringlist.cpp
index 1430235..20c9bce 100644
--- a/src/corelib/tools/qstringlist.cpp
+++ b/src/corelib/tools/qstringlist.cpp
@@ -41,6 +41,7 @@
#include <qstringlist.h>
#include <qset.h>
+#include <qstringmatcher.h>
QT_BEGIN_NAMESPACE
@@ -76,8 +77,8 @@ QT_BEGIN_NAMESPACE
\ingroup tools
\ingroup shared
- \ingroup text
- \mainclass
+ \ingroup string-processing
+
\reentrant
QStringList inherits from QList<QString>. Like QList, QStringList is
diff --git a/src/corelib/tools/qstringlist.h b/src/corelib/tools/qstringlist.h
index 49da145..a0033fd 100644
--- a/src/corelib/tools/qstringlist.h
+++ b/src/corelib/tools/qstringlist.h
@@ -47,7 +47,6 @@
#include <QtCore/qlist.h>
#include <QtCore/qregexp.h>
#include <QtCore/qstring.h>
-#include <QtCore/qstringmatcher.h>
#ifdef QT_INCLUDE_COMPAT
#include <Qt3Support/q3valuelist.h>
#endif
diff --git a/src/corelib/tools/qstringmatcher.cpp b/src/corelib/tools/qstringmatcher.cpp
index 38bcc67..3e0edd0 100644
--- a/src/corelib/tools/qstringmatcher.cpp
+++ b/src/corelib/tools/qstringmatcher.cpp
@@ -129,7 +129,7 @@ static inline int bm_find(const ushort *uc, uint l, int index, const ushort *puc
can be quickly matched in a Unicode string.
\ingroup tools
- \ingroup text
+ \ingroup string-processing
This class is useful when you have a sequence of \l{QChar}s that
you want to repeatedly match against some strings (perhaps in a
diff --git a/src/corelib/tools/qstringmatcher.h b/src/corelib/tools/qstringmatcher.h
index 7927996..cf01d07 100644
--- a/src/corelib/tools/qstringmatcher.h
+++ b/src/corelib/tools/qstringmatcher.h
@@ -81,13 +81,14 @@ private:
// explicitely allow anonymous unions for RVCT to prevent compiler warnings
#pragma anon_unions
#endif
+ struct Data {
+ uchar q_skiptable[256];
+ const QChar *uc;
+ int len;
+ };
union {
uint q_data[256];
- struct {
- uchar q_skiptable[256];
- const QChar *uc;
- int len;
- } p;
+ Data p;
};
};
diff --git a/src/corelib/tools/qtextboundaryfinder.cpp b/src/corelib/tools/qtextboundaryfinder.cpp
index 3e156a6..1b6b860 100644
--- a/src/corelib/tools/qtextboundaryfinder.cpp
+++ b/src/corelib/tools/qtextboundaryfinder.cpp
@@ -38,11 +38,11 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include "private/qharfbuzz_p.h"
#include <QtCore/qtextboundaryfinder.h>
#include <QtCore/qvarlengtharray.h>
#include <private/qunicodetables_p.h>
#include <qdebug.h>
+#include "private/qharfbuzz_p.h"
QT_BEGIN_NAMESPACE
@@ -107,7 +107,7 @@ static void init(QTextBoundaryFinder::BoundaryType type, const QChar *chars, int
\since 4.4
\ingroup tools
\ingroup shared
- \ingroup text
+ \ingroup string-processing
\reentrant
QTextBoundaryFinder allows to find Unicode text boundaries in a
@@ -176,6 +176,7 @@ QTextBoundaryFinder::QTextBoundaryFinder(const QTextBoundaryFinder &other)
, freePrivate(true)
{
d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(HB_CharAttributes));
+ Q_CHECK_PTR(d);
memcpy(d, other.d, length*sizeof(HB_CharAttributes));
}
@@ -193,8 +194,11 @@ QTextBoundaryFinder &QTextBoundaryFinder::operator=(const QTextBoundaryFinder &o
length = other.length;
pos = other.pos;
freePrivate = true;
-
- d = (QTextBoundaryFinderPrivate *) realloc(d, length*sizeof(HB_CharAttributes));
+
+ QTextBoundaryFinderPrivate *newD = (QTextBoundaryFinderPrivate *)
+ realloc(d, length*sizeof(HB_CharAttributes));
+ Q_CHECK_PTR(newD);
+ d = newD;
memcpy(d, other.d, length*sizeof(HB_CharAttributes));
return *this;
@@ -221,6 +225,7 @@ QTextBoundaryFinder::QTextBoundaryFinder(BoundaryType type, const QString &strin
, freePrivate(true)
{
d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(HB_CharAttributes));
+ Q_CHECK_PTR(d);
init(t, chars, length, d->attributes);
}
@@ -248,6 +253,7 @@ QTextBoundaryFinder::QTextBoundaryFinder(BoundaryType type, const QChar *chars,
freePrivate = false;
} else {
d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(HB_CharAttributes));
+ Q_CHECK_PTR(d);
freePrivate = true;
}
init(t, chars, length, d->attributes);
diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp
index 7b0d102..052c456 100644
--- a/src/corelib/tools/qtimeline.cpp
+++ b/src/corelib/tools/qtimeline.cpp
@@ -48,20 +48,6 @@
QT_BEGIN_NAMESPACE
-static const qreal pi = qreal(3.14159265359);
-static const qreal halfPi = pi / qreal(2.0);
-
-
-static inline qreal qt_sinProgress(qreal value)
-{
- return qSin((value * pi) - halfPi) / 2 + qreal(0.5);
-}
-
-static inline qreal qt_smoothBeginEndMixFactor(qreal value)
-{
- return qMin(qMax(1 - value * 2 + qreal(0.3), qreal(0.0)), qreal(1.0));
-}
-
class QTimeLinePrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QTimeLine)
@@ -70,7 +56,7 @@ public:
: startTime(0), duration(1000), startFrame(0), endFrame(0),
updateInterval(1000 / 25),
totalLoopCount(1), currentLoopCount(0), currentTime(0), timerId(0),
- direction(QTimeLine::Forward), curveShape(QTimeLine::EaseInOutCurve),
+ direction(QTimeLine::Forward), easingCurve(QEasingCurve::InOutSine),
state(QTimeLine::NotRunning)
{ }
@@ -83,12 +69,11 @@ public:
int currentLoopCount;
int currentTime;
- int elapsedTime;
int timerId;
QTime timer;
QTimeLine::Direction direction;
- QTimeLine::CurveShape curveShape;
+ QEasingCurve easingCurve;
QTimeLine::State state;
inline void setState(QTimeLine::State newState)
{
@@ -180,7 +165,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
\class QTimeLine
\brief The QTimeLine class provides a timeline for controlling animations.
\since 4.2
- \ingroup multimedia
+ \ingroup animation
It's most commonly used to animate a GUI control by calling a slot
periodically. You can construct a timeline by passing its duration in
@@ -226,7 +211,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
applies an interpolation algorithm to generate these value. You can choose
from a set of predefined timeline algorithms by calling
setCurveShape().
-
+
Note that by default, QTimeLine uses the EaseInOut curve shape,
which provides a value that grows slowly, then grows steadily, and
finally grows slowly. For a custom timeline, you can reimplement
@@ -523,12 +508,70 @@ void QTimeLine::setUpdateInterval(int interval)
QTimeLine::CurveShape QTimeLine::curveShape() const
{
Q_D(const QTimeLine);
- return d->curveShape;
+ switch (d->easingCurve.type()) {
+ default:
+ case QEasingCurve::InOutSine:
+ return EaseInOutCurve;
+ case QEasingCurve::InCurve:
+ return EaseInCurve;
+ case QEasingCurve::OutCurve:
+ return EaseOutCurve;
+ case QEasingCurve::Linear:
+ return LinearCurve;
+ case QEasingCurve::SineCurve:
+ return SineCurve;
+ case QEasingCurve::CosineCurve:
+ return CosineCurve;
+ }
+ return EaseInOutCurve;
}
+
void QTimeLine::setCurveShape(CurveShape shape)
{
+ switch (shape) {
+ default:
+ case EaseInOutCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::InOutSine));
+ break;
+ case EaseInCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::InCurve));
+ break;
+ case EaseOutCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::OutCurve));
+ break;
+ case LinearCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::Linear));
+ break;
+ case SineCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::SineCurve));
+ break;
+ case CosineCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::CosineCurve));
+ break;
+ }
+}
+
+/*!
+ \property QTimeLine::easingCurve
+
+ \since 4.6
+
+ Specifies the easing curve that the timeline will use.
+ If both easing curve and curveShape are set, the last set property will
+ override the previous one. (If valueForTime() is reimplemented it will
+ override both)
+*/
+
+QEasingCurve QTimeLine::easingCurve() const
+{
+ Q_D(const QTimeLine);
+ return d->easingCurve;
+}
+
+void QTimeLine::setEasingCurve(const QEasingCurve& curve)
+{
Q_D(QTimeLine);
- d->curveShape = shape;
+ d->easingCurve = curve;
}
/*!
@@ -608,42 +651,8 @@ qreal QTimeLine::valueForTime(int msec) const
Q_D(const QTimeLine);
msec = qMin(qMax(msec, 0), d->duration);
- // Simple linear interpolation
qreal value = msec / qreal(d->duration);
-
- switch (d->curveShape) {
- case EaseInOutCurve:
- value = qt_sinProgress(value);
- break;
- // SmoothBegin blends Smooth and Linear Interpolation.
- // Progress 0 - 0.3 : Smooth only
- // Progress 0.3 - ~ 0.5 : Mix of Smooth and Linear
- // Progress ~ 0.5 - 1 : Linear only
- case EaseInCurve: {
- const qreal sinProgress = qt_sinProgress(value);
- const qreal linearProgress = value;
- const qreal mix = qt_smoothBeginEndMixFactor(value);
- value = sinProgress * mix + linearProgress * (1 - mix);
- break;
- }
- case EaseOutCurve: {
- const qreal sinProgress = qt_sinProgress(value);
- const qreal linearProgress = value;
- const qreal mix = qt_smoothBeginEndMixFactor(1 - value);
- value = sinProgress * mix + linearProgress * (1 - mix);
- break;
- }
- case SineCurve:
- value = (qSin(((msec * pi * 2) / d->duration) - pi/2) + 1) / 2;
- break;
- case CosineCurve:
- value = (qCos(((msec * pi * 2) / d->duration) - pi/2) + 1) / 2;
- break;
- default:
- break;
- }
-
- return value;
+ return d->easingCurve.valueForProgress(value);
}
/*!
@@ -653,6 +662,7 @@ qreal QTimeLine::valueForTime(int msec) const
second). You can change the update interval by calling
setUpdateInterval().
+ The timeline will start from position 0, or the end if going backward.
If you want to resume a stopped timeline without restarting, you can call
resume() instead.
@@ -665,10 +675,8 @@ void QTimeLine::start()
qWarning("QTimeLine::start: already running");
return;
}
- int curTime = d->currentTime;
- if (curTime == d->duration && d->direction == Forward)
- curTime = 0;
- else if (curTime == 0 && d->direction == Backward)
+ int curTime = 0;
+ if (d->direction == Backward)
curTime = d->duration;
d->timerId = startTimer(d->updateInterval);
d->startTime = curTime;
@@ -684,7 +692,7 @@ void QTimeLine::start()
frame and value at regular intervals.
In contrast to start(), this function does not restart the timeline before
- is resumes.
+ it resumes.
\sa start(), updateInterval(), frameChanged(), valueChanged()
*/
diff --git a/src/corelib/tools/qtimeline.h b/src/corelib/tools/qtimeline.h
index 37e072d..d89b09a 100644
--- a/src/corelib/tools/qtimeline.h
+++ b/src/corelib/tools/qtimeline.h
@@ -42,6 +42,7 @@
#ifndef QTIMELINE_H
#define QTIMELINE_H
+#include <QtCore/qeasingcurve.h>
#include <QtCore/qobject.h>
QT_BEGIN_HEADER
@@ -60,6 +61,7 @@ class Q_CORE_EXPORT QTimeLine : public QObject
Q_PROPERTY(Direction direction READ direction WRITE setDirection)
Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount)
Q_PROPERTY(CurveShape curveShape READ curveShape WRITE setCurveShape)
+ Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve)
public:
enum State {
NotRunning,
@@ -105,6 +107,9 @@ public:
CurveShape curveShape() const;
void setCurveShape(CurveShape shape);
+ QEasingCurve easingCurve() const;
+ void setEasingCurve(const QEasingCurve &curve);
+
int currentTime() const;
int currentFrame() const;
qreal currentValue() const;
diff --git a/src/corelib/tools/qunicodetables_p.h b/src/corelib/tools/qunicodetables_p.h
index ed28afb..e08e541 100644
--- a/src/corelib/tools/qunicodetables_p.h
+++ b/src/corelib/tools/qunicodetables_p.h
@@ -178,7 +178,7 @@ namespace QUnicodeTables {
}
Q_CORE_EXPORT int QT_FASTCALL script(uint ucs4);
- Q_CORE_EXPORT_INLINE int QT_FASTCALL script(const QChar &ch) {
+ inline int script(const QChar &ch) {
return script(ch.unicode());
}
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index f270913..f7284a8 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -52,6 +52,9 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Core)
+template<class T, int Prealloc>
+class QPodList;
+
// Prealloc = 256 by default, specified in qcontainerfwd.h
template<class T, int Prealloc>
class QVarLengthArray
@@ -122,6 +125,7 @@ public:
inline const T * constData() const { return ptr; }
private:
+ friend class QPodList<T, Prealloc>;
void realloc(int size, int alloc);
int a;
@@ -140,6 +144,7 @@ Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(int asize)
: s(asize) {
if (s > Prealloc) {
ptr = reinterpret_cast<T *>(qMalloc(s * sizeof(T)));
+ Q_CHECK_PTR(ptr);
a = s;
} else {
ptr = reinterpret_cast<T *>(array);
@@ -161,25 +166,24 @@ Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reserve(int asize)
{ if (asize > a) realloc(s, asize); }
template <class T, int Prealloc>
-Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, int asize)
+Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, int increment)
{
Q_ASSERT(abuf);
- if (asize <= 0)
+ if (increment <= 0)
return;
- const int idx = s;
- const int news = s + asize;
- if (news >= a)
- realloc(s, qMax(s<<1, news));
- s = news;
+ const int asize = s + increment;
+
+ if (asize >= a)
+ realloc(s, qMax(s*2, asize));
if (QTypeInfo<T>::isComplex) {
- T *i = ptr + idx;
- T *j = i + asize;
- while (i < j)
- new (i++) T(*abuf++);
+ // call constructor for new objects (which can throw)
+ while (s < asize)
+ new (ptr+(s++)) T(*abuf++);
} else {
- qMemCopy(&ptr[idx], abuf, asize * sizeof(T));
+ qMemCopy(&ptr[s], abuf, increment * sizeof(T));
+ s = asize;
}
}
@@ -189,46 +193,60 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int a
Q_ASSERT(aalloc >= asize);
T *oldPtr = ptr;
int osize = s;
- s = asize;
+ // s = asize;
if (aalloc != a) {
ptr = reinterpret_cast<T *>(qMalloc(aalloc * sizeof(T)));
+ Q_CHECK_PTR(ptr);
if (ptr) {
+ s = 0;
a = aalloc;
if (QTypeInfo<T>::isStatic) {
- T *i = ptr + osize;
- T *j = oldPtr + osize;
- while (i != ptr) {
- new (--i) T(*--j);
- j->~T();
+ QT_TRY {
+ // copy all the old elements
+ const int copySize = qMin(asize, osize);
+ while (s < copySize) {
+ new (ptr+s) T(*(oldPtr+s));
+ (oldPtr+s)->~T();
+ s++;
+ }
+ } QT_CATCH(...) {
+ // clean up all the old objects and then free the old ptr
+ int sClean = s;
+ while (sClean < osize)
+ (oldPtr+(sClean++))->~T();
+ if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
+ qFree(oldPtr);
+ QT_RETHROW;
}
} else {
- qMemCopy(ptr, oldPtr, osize * sizeof(T));
+ qMemCopy(ptr, oldPtr, qMin(asize, osize) * sizeof(T));
+ s = asize;
}
} else {
ptr = oldPtr;
- s = 0;
- asize = 0;
+ return;
}
}
if (QTypeInfo<T>::isComplex) {
- if (asize < osize) {
- T *i = oldPtr + osize;
- T *j = oldPtr + asize;
- while (i-- != j)
- i->~T();
- } else {
- T *i = ptr + asize;
- T *j = ptr + osize;
- while (i != j)
- new (--i) T;
- }
+ while (osize > asize)
+ (oldPtr+(--osize))->~T();
+ if( oldPtr == ptr )
+ s = osize;
}
if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
qFree(oldPtr);
+
+ if (QTypeInfo<T>::isComplex) {
+ // call default constructor for new objects (which can throw)
+ while (s < asize)
+ new (ptr+(s++)) T;
+ } else {
+ s = asize;
+ }
}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
new file mode 100644
index 0000000..e56e6f5
--- /dev/null
+++ b/src/corelib/tools/qvarlengtharray.qdoc
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QVarLengthArray
+ \brief The QVarLengthArray class provides a low-level variable-length array.
+
+ \ingroup tools
+ \reentrant
+
+ The C++ language doesn't support variable-length arrays on the stack.
+ For example, the following code won't compile:
+
+ \snippet doc/src/snippets/code/doc_src_qvarlengtharray.qdoc 0
+
+ The alternative is to allocate the array on the heap (with
+ \c{new}):
+
+ \snippet doc/src/snippets/code/doc_src_qvarlengtharray.qdoc 1
+
+ However, if myfunc() is called very frequently from the
+ application's inner loop, heap allocation can be a major source
+ of slowdown.
+
+ QVarLengthArray is an attempt to work around this gap in the C++
+ language. It allocates a certain number of elements on the stack,
+ and if you resize the array to a larger size, it automatically
+ uses the heap instead. Stack allocation has the advantage that
+ it is much faster than heap allocation.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qvarlengtharray.qdoc 2
+
+ In the example above, QVarLengthArray will preallocate 1024
+ elements on the stack and use them unless \c{n + 1} is greater
+ than 1024. If you omit the second template argument,
+ QVarLengthArray's default of 256 is used.
+
+ QVarLengthArray's value type must be an \l{assignable data type}.
+ This covers most data types that are commonly used, but the
+ compiler won't let you, for example, store a QWidget as a value;
+ instead, store a QWidget *.
+
+ QVarLengthArray, like QVector, provides a resizable array data
+ structure. The main differences between the two classes are:
+
+ \list
+ \o QVarLengthArray's API is much more low-level. It provides no
+ iterators and lacks much of QVector's functionality.
+
+ \o QVarLengthArray doesn't initialize the memory if the value is
+ a basic type. (QVector always does.)
+
+ \o QVector uses \l{implicit sharing} as a memory optimization.
+ QVarLengthArray doesn't provide that feature; however, it
+ usually produces slightly better performance due to reduced
+ overhead, especially in tight loops.
+ \endlist
+
+ In summary, QVarLengthArray is a low-level optimization class
+ that only makes sense in very specific cases. It is used a few
+ places inside Qt and was added to Qt's public API for the
+ convenience of advanced users.
+
+ \sa QVector, QList, QLinkedList
+*/
+
+/*! \fn QVarLengthArray::QVarLengthArray(int size)
+
+ Constructs an array with an initial size of \a size elements.
+
+ If the value type is a primitive type (e.g., char, int, float) or
+ a pointer type (e.g., QWidget *), the elements are not
+ initialized. For other types, the elements are initialized with a
+ \l{default-constructed value}.
+*/
+
+/*! \fn QVarLengthArray::~QVarLengthArray()
+
+ Destroys the array.
+*/
+
+/*! \fn int QVarLengthArray::size() const
+
+ Returns the number of elements in the array.
+
+ \sa isEmpty(), resize()
+*/
+
+/*! \fn int QVarLengthArray::count() const
+
+ Same as size().
+
+ \sa isEmpty(), resize()
+*/
+
+/*! \fn bool QVarLengthArray::isEmpty() const
+
+ Returns true if the array has size 0; otherwise returns false.
+
+ \sa size(), resize()
+*/
+
+/*! \fn void QVarLengthArray::clear()
+
+ Removes all the elements from the array.
+
+ Same as resize(0).
+*/
+
+/*! \fn void QVarLengthArray::resize(int size)
+
+ Sets the size of the array to \a size. If \a size is greater than
+ the current size, elements are added to the end. If \a size is
+ less than the current size, elements are removed from the end.
+
+ If the value type is a primitive type (e.g., char, int, float) or
+ a pointer type (e.g., QWidget *), new elements are not
+ initialized. For other types, the elements are initialized with a
+ \l{default-constructed value}.
+
+ \sa size()
+*/
+
+/*! \fn int QVarLengthArray::capacity() const
+
+ Returns the maximum number of elements that can be stored in the
+ array without forcing a reallocation.
+
+ The sole purpose of this function is to provide a means of fine
+ tuning QVarLengthArray's memory usage. In general, you will rarely ever
+ need to call this function. If you want to know how many items are
+ in the array, call size().
+
+ \sa reserve()
+*/
+
+/*! \fn void QVarLengthArray::reserve(int size)
+
+ Attempts to allocate memory for at least \a size elements. If you
+ know in advance how large the array can get, you can call this
+ function and if you call resize() often, you are likely to get
+ better performance. If \a size is an underestimate, the worst
+ that will happen is that the QVarLengthArray will be a bit
+ slower.
+
+ The sole purpose of this function is to provide a means of fine
+ tuning QVarLengthArray's memory usage. In general, you will
+ rarely ever need to call this function. If you want to change the
+ size of the array, call resize().
+
+ \sa capacity()
+*/
+
+/*! \fn T &QVarLengthArray::operator[](int i)
+
+ Returns a reference to the item at index position \a i.
+
+ \a i must be a valid index position in the array (i.e., 0 <= \a i
+ < size()).
+
+ \sa data()
+*/
+
+/*! \fn const T &QVarLengthArray::operator[](int i) const
+
+ \overload
+*/
+
+
+/*!
+ \fn void QVarLengthArray::append(const T &t)
+
+ Appends item \a t to the array, extending the array if necessary.
+
+ \sa removeLast()
+*/
+
+
+/*!
+ \fn inline void QVarLengthArray::removeLast()
+ \since 4.5
+
+ Decreases the size of the array by one. The allocated size is not changed.
+
+ \sa append()
+*/
+
+/*!
+ \fn void QVarLengthArray::append(const T *buf, int size)
+
+ Appends \a size amount of items referenced by \a buf to this array.
+*/
+
+
+/*! \fn T *QVarLengthArray::data()
+
+ Returns a pointer to the data stored in the array. The pointer can
+ be used to access and modify the items in the array.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qvarlengtharray.qdoc 3
+
+ The pointer remains valid as long as the array isn't reallocated.
+
+ This function is mostly useful to pass an array to a function
+ that accepts a plain C++ array.
+
+ \sa constData(), operator[]()
+*/
+
+/*! \fn const T *QVarLengthArray::data() const
+
+ \overload
+*/
+
+/*! \fn const T *QVarLengthArray::constData() const
+
+ Returns a const pointer to the data stored in the array. The
+ pointer can be used to access the items in the array. The
+ pointer remains valid as long as the array isn't reallocated.
+
+ This function is mostly useful to pass an array to a function
+ that accepts a plain C++ array.
+
+ \sa data(), operator[]()
+*/
+
+/*! \fn QVarLengthArray<T, Prealloc> &QVarLengthArray::operator=(const QVarLengthArray<T, Prealloc> &other)
+ Assigns \a other to this array and returns a reference to this array.
+ */
+
+/*! \fn QVarLengthArray::QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
+ Constructs a copy of \a other.
+ */
+
diff --git a/src/corelib/tools/qvector.cpp b/src/corelib/tools/qvector.cpp
index 6ca5526..b365fd0 100644
--- a/src/corelib/tools/qvector.cpp
+++ b/src/corelib/tools/qvector.cpp
@@ -50,6 +50,7 @@ QVectorData QVectorData::shared_null = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, tr
QVectorData *QVectorData::malloc(int sizeofTypedData, int size, int sizeofT, QVectorData *init)
{
QVectorData* p = (QVectorData *)qMalloc(sizeofTypedData + (size - 1) * sizeofT);
+ Q_CHECK_PTR(p);
::memcpy(p, init, sizeofTypedData + (qMin(size, init->alloc) - 1) * sizeofT);
return p;
}
@@ -67,7 +68,7 @@ int QVectorData::grow(int sizeofTypedData, int size, int sizeofT, bool excessive
\ingroup tools
\ingroup shared
- \mainclass
+
\reentrant
QVector\<T\> is one of Qt's generic \l{container classes}. It
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index a3beff8..56707c74 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -77,24 +77,15 @@ struct Q_CORE_EXPORT QVectorData
static QVectorData shared_null;
// ### Qt 5: rename to 'allocate()'. The current name causes problems for
// some debugges when the QVector is member of a class within an unnamed namespace.
+ // ### Qt 5: can be removed completely. (Ralf)
static QVectorData *malloc(int sizeofTypedData, int size, int sizeofT, QVectorData *init);
static int grow(int sizeofTypedData, int size, int sizeofT, bool excessive);
};
template <typename T>
-struct QVectorTypedData
-{
- QBasicAtomicInt ref;
- int alloc;
- int size;
-#if defined(QT_ARCH_SPARC) && defined(Q_CC_GNU) && defined(__LP64__) && defined(QT_BOOTSTRAPPED)
- // workaround for bug in gcc 3.4.2
- uint sharable;
- uint capacity;
-#else
- uint sharable : 1;
- uint capacity : 1;
-#endif
+struct QVectorTypedData : private QVectorData
+{ // private inheritance as we must not access QVectorData member thought QVectorTypedData
+ // as this would break strict aliasing rules. (in the case of shared_null)
T array[1];
};
@@ -104,14 +95,21 @@ template <typename T>
class QVector
{
typedef QVectorTypedData<T> Data;
- union { QVectorData *p; QVectorTypedData<T> *d; };
+ union {
+ QVectorData *d;
+#if defined(Q_CC_SUN) && (__SUNPRO_CC <= 0x550)
+ QVectorTypedData<T> *p;
+#else
+ Data *p;
+#endif
+ };
public:
- inline QVector() : p(&QVectorData::shared_null) { d->ref.ref(); }
+ inline QVector() : d(&QVectorData::shared_null) { d->ref.ref(); }
explicit QVector(int size);
QVector(int size, const T &t);
inline QVector(const QVector<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); }
- inline ~QVector() { if (!d) return; if (!d->ref.deref()) free(d); }
+ inline ~QVector() { if (!d) return; if (!d->ref.deref()) free(p); }
QVector<T> &operator=(const QVector<T> &v);
bool operator==(const QVector<T> &v) const;
inline bool operator!=(const QVector<T> &v) const { return !(*this == v); }
@@ -130,9 +128,9 @@ public:
inline bool isDetached() const { return d->ref == 1; }
inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; }
- inline T *data() { detach(); return d->array; }
- inline const T *data() const { return d->array; }
- inline const T *constData() const { return d->array; }
+ inline T *data() { detach(); return p->array; }
+ inline const T *data() const { return p->array; }
+ inline const T *constData() const { return p->array; }
void clear();
const T &at(int i) const;
@@ -225,12 +223,12 @@ public:
typedef T* iterator;
typedef const T* const_iterator;
#endif
- inline iterator begin() { detach(); return d->array; }
- inline const_iterator begin() const { return d->array; }
- inline const_iterator constBegin() const { return d->array; }
- inline iterator end() { detach(); return d->array + d->size; }
- inline const_iterator end() const { return d->array + d->size; }
- inline const_iterator constEnd() const { return d->array + d->size; }
+ inline iterator begin() { detach(); return p->array; }
+ inline const_iterator begin() const { return p->array; }
+ inline const_iterator constBegin() const { return p->array; }
+ inline iterator end() { detach(); return p->array + d->size; }
+ inline const_iterator end() const { return p->array + d->size; }
+ inline const_iterator constEnd() const { return p->array + d->size; }
iterator insert(iterator before, int n, const T &x);
inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); }
iterator erase(iterator begin, iterator end);
@@ -255,11 +253,7 @@ public:
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
-#ifndef QT_NO_STL
typedef ptrdiff_t difference_type;
-#else
- typedef int difference_type;
-#endif
typedef iterator Iterator;
typedef const_iterator ConstIterator;
typedef int size_type;
@@ -327,11 +321,11 @@ inline void QVector<T>::clear()
template <typename T>
inline const T &QVector<T>::at(int i) const
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range");
- return d->array[i]; }
+ return p->array[i]; }
template <typename T>
inline const T &QVector<T>::operator[](int i) const
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
- return d->array[i]; }
+ return p->array[i]; }
template <typename T>
inline T &QVector<T>::operator[](int i)
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
@@ -369,7 +363,7 @@ QVector<T> &QVector<T>::operator=(const QVector<T> &v)
{
v.d->ref.ref();
if (!d->ref.deref())
- free(d);
+ free(p);
d = v.d;
if (!d->sharable)
detach_helper();
@@ -379,37 +373,39 @@ QVector<T> &QVector<T>::operator=(const QVector<T> &v)
template <typename T>
inline QVectorData *QVector<T>::malloc(int aalloc)
{
- return static_cast<QVectorData *>(qMalloc(sizeOfTypedData() + (aalloc - 1) * sizeof(T)));
+ QVectorData *data = static_cast<QVectorData *>(qMalloc(sizeOfTypedData() + (aalloc - 1) * sizeof(T)));
+ Q_CHECK_PTR(data);
+ return data;
}
template <typename T>
QVector<T>::QVector(int asize)
{
- p = malloc(asize);
+ d = malloc(asize);
d->ref = 1;
d->alloc = d->size = asize;
d->sharable = true;
d->capacity = false;
if (QTypeInfo<T>::isComplex) {
- T* b = d->array;
- T* i = d->array + d->size;
+ T* b = p->array;
+ T* i = p->array + d->size;
while (i != b)
new (--i) T;
} else {
- qMemSet(d->array, 0, asize * sizeof(T));
+ qMemSet(p->array, 0, asize * sizeof(T));
}
}
template <typename T>
QVector<T>::QVector(int asize, const T &t)
{
- p = malloc(asize);
+ d = malloc(asize);
d->ref = 1;
d->alloc = d->size = asize;
d->sharable = true;
d->capacity = false;
- T* i = d->array + d->size;
- while (i != d->array)
+ T* i = p->array + d->size;
+ while (i != p->array)
new (--i) T(t);
}
@@ -418,7 +414,9 @@ void QVector<T>::free(Data *x)
{
if (QTypeInfo<T>::isComplex) {
T* b = x->array;
- T* i = b + x->size;
+ union { QVectorData *d; Data *p; } u;
+ u.p = x;
+ T* i = b + u.d->size;
while (i-- != b)
i->~T();
}
@@ -428,77 +426,82 @@ void QVector<T>::free(Data *x)
template <typename T>
void QVector<T>::realloc(int asize, int aalloc)
{
- T *j, *i, *b;
- union { QVectorData *p; Data *d; } x;
+ T *pOld;
+ T *pNew;
+ union { QVectorData *d; Data *p; } x;
x.d = d;
- if (QTypeInfo<T>::isComplex && aalloc == d->alloc && d->ref == 1) {
- // pure resize
- i = d->array + d->size;
- j = d->array + asize;
- if (i > j) {
- while (i-- != j)
- i->~T();
- } else {
- while (j-- != i)
- new (j) T;
+ if (QTypeInfo<T>::isComplex && asize < d->size && d->ref == 1 ) {
+ // call the destructor on all objects that need to be
+ // destroyed when shrinking
+ pOld = p->array + d->size;
+ pNew = p->array + asize;
+ while (asize < d->size) {
+ (--pOld)->~T();
+ d->size--;
}
- d->size = asize;
- return;
}
if (aalloc != d->alloc || d->ref != 1) {
// (re)allocate memory
if (QTypeInfo<T>::isStatic) {
- x.p = malloc(aalloc);
+ x.d = malloc(aalloc);
+ Q_CHECK_PTR(x.p);
+ x.d->size = 0;
} else if (d->ref != 1) {
- x.p = QVectorData::malloc(sizeOfTypedData(), aalloc, sizeof(T), p);
- } else {
+ x.d = malloc(aalloc);
+ Q_CHECK_PTR(x.p);
if (QTypeInfo<T>::isComplex) {
- // call the destructor on all objects that need to be
- // destroyed when shrinking
- if (asize < d->size) {
- j = d->array + asize;
- i = d->array + d->size;
- while (i-- != j)
- i->~T();
- i = d->array + asize;
- }
+ x.d->size = 0;
+ } else {
+ ::memcpy(x.p, p, sizeOfTypedData() + (qMin(aalloc, d->alloc) - 1) * sizeof(T));
+ x.d->size = d->size;
+ }
+ } else {
+ QT_TRY {
+ QVectorData *mem = static_cast<QVectorData *>(qRealloc(p, sizeOfTypedData() + (aalloc - 1) * sizeof(T)));
+ Q_CHECK_PTR(mem);
+ x.d = d = mem;
+ x.d->size = d->size;
+ } QT_CATCH (const std::bad_alloc &) {
+ if (aalloc > d->alloc) // ignore the error in case we are just shrinking.
+ QT_RETHROW;
}
- x.p = p = static_cast<QVectorData *>(qRealloc(p, sizeOfTypedData() + (aalloc - 1) * sizeof(T)));
}
x.d->ref = 1;
+ x.d->alloc = aalloc;
x.d->sharable = true;
x.d->capacity = d->capacity;
-
}
+
if (QTypeInfo<T>::isComplex) {
- if (asize < d->size) {
- j = d->array + asize;
- i = x.d->array + asize;
- } else {
- // construct all new objects when growing
- i = x.d->array + asize;
- j = x.d->array + d->size;
- while (i != j)
- new (--i) T;
- j = d->array + d->size;
- }
- if (i != j) {
+ QT_TRY {
+ pOld = p->array + x.d->size;
+ pNew = x.p->array + x.d->size;
// copy objects from the old array into the new array
- b = x.d->array;
- while (i != b)
- new (--i) T(*--j);
+ while (x.d->size < qMin(asize, d->size)) {
+ new (pNew++) T(*pOld++);
+ x.d->size++;
+ }
+ // construct all new objects when growing
+ while (x.d->size < asize) {
+ new (pNew++) T;
+ x.d->size++;
+ }
+ } QT_CATCH (...) {
+ free(x.p);
+ QT_RETHROW;
}
- } else if (asize > d->size) {
+
+ } else if (asize > x.d->size) {
// initialize newly allocated memory to 0
- qMemSet(x.d->array + d->size, 0, (asize - d->size) * sizeof(T));
+ qMemSet(x.p->array + x.d->size, 0, (asize - x.d->size) * sizeof(T));
}
x.d->size = asize;
- x.d->alloc = aalloc;
+
if (d != x.d) {
if (!d->ref.deref())
- free(d);
+ free(p);
d = x.d;
}
}
@@ -506,15 +509,15 @@ void QVector<T>::realloc(int asize, int aalloc)
template<typename T>
Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const
{
- if (i < 0 || i >= p->size) {
+ if (i < 0 || i >= d->size) {
return T();
}
- return d->array[i];
+ return p->array[i];
}
template<typename T>
Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const
{
- return ((i < 0 || i >= p->size) ? defaultValue : d->array[i]);
+ return ((i < 0 || i >= d->size) ? defaultValue : p->array[i]);
}
template <typename T>
@@ -525,14 +528,14 @@ void QVector<T>::append(const T &t)
realloc(d->size, QVectorData::grow(sizeOfTypedData(), d->size + 1, sizeof(T),
QTypeInfo<T>::isStatic));
if (QTypeInfo<T>::isComplex)
- new (d->array + d->size) T(copy);
+ new (p->array + d->size) T(copy);
else
- d->array[d->size] = copy;
+ p->array[d->size] = copy;
} else {
if (QTypeInfo<T>::isComplex)
- new (d->array + d->size) T(t);
+ new (p->array + d->size) T(t);
else
- d->array[d->size] = t;
+ p->array[d->size] = t;
}
++d->size;
}
@@ -540,27 +543,27 @@ void QVector<T>::append(const T &t)
template <typename T>
Q_TYPENAME QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t)
{
- int offset = before - d->array;
+ int offset = before - p->array;
if (n != 0) {
const T copy(t);
if (d->ref != 1 || d->size + n > d->alloc)
realloc(d->size, QVectorData::grow(sizeOfTypedData(), d->size + n, sizeof(T),
QTypeInfo<T>::isStatic));
if (QTypeInfo<T>::isStatic) {
- T *b = d->array + d->size;
- T *i = d->array + d->size + n;
+ T *b = p->array + d->size;
+ T *i = p->array + d->size + n;
while (i != b)
new (--i) T;
- i = d->array + d->size;
+ i = p->array + d->size;
T *j = i + n;
- b = d->array + offset;
+ b = p->array + offset;
while (i != b)
*--j = *--i;
i = b+n;
while (i != b)
*--i = copy;
} else {
- T *b = d->array + offset;
+ T *b = p->array + offset;
T *i = b + n;
memmove(i, b, (d->size - offset) * sizeof(T));
while (i != b)
@@ -568,29 +571,29 @@ Q_TYPENAME QVector<T>::iterator QVector<T>::insert(iterator before, size_type n,
}
d->size += n;
}
- return d->array + offset;
+ return p->array + offset;
}
template <typename T>
Q_TYPENAME QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
{
- int f = abegin - d->array;
- int l = aend - d->array;
+ int f = abegin - p->array;
+ int l = aend - p->array;
int n = l - f;
detach();
if (QTypeInfo<T>::isComplex) {
- qCopy(d->array+l, d->array+d->size, d->array+f);
- T *i = d->array+d->size;
- T* b = d->array+d->size-n;
+ qCopy(p->array+l, p->array+d->size, p->array+f);
+ T *i = p->array+d->size;
+ T* b = p->array+d->size-n;
while (i != b) {
--i;
i->~T();
}
} else {
- memmove(d->array + f, d->array + l, (d->size-l)*sizeof(T));
+ memmove(p->array + f, p->array + l, (d->size-l)*sizeof(T));
}
d->size -= n;
- return d->array + f;
+ return p->array + f;
}
template <typename T>
@@ -600,9 +603,9 @@ bool QVector<T>::operator==(const QVector<T> &v) const
return false;
if (d == v.d)
return true;
- T* b = d->array;
+ T* b = p->array;
T* i = b + d->size;
- T* j = v.d->array + d->size;
+ T* j = v.p->array + d->size;
while (i != b)
if (!(*--i == *--j))
return false;
@@ -615,8 +618,8 @@ QVector<T> &QVector<T>::fill(const T &from, int asize)
const T copy(from);
resize(asize < 0 ? d->size : asize);
if (d->size) {
- T *i = d->array + d->size;
- T *b = d->array;
+ T *i = p->array + d->size;
+ T *b = p->array;
while (i != b)
*--i = copy;
}
@@ -629,9 +632,9 @@ QVector<T> &QVector<T>::operator+=(const QVector &l)
int newSize = d->size + l.d->size;
realloc(d->size, newSize);
- T *w = d->array + newSize;
- T *i = l.d->array + l.d->size;
- T *b = l.d->array;
+ T *w = p->array + newSize;
+ T *i = l.p->array + l.d->size;
+ T *b = l.p->array;
while (i != b) {
if (QTypeInfo<T>::isComplex)
new (--w) T(*--i);
@@ -648,11 +651,11 @@ int QVector<T>::indexOf(const T &t, int from) const
if (from < 0)
from = qMax(from + d->size, 0);
if (from < d->size) {
- T* n = d->array + from - 1;
- T* e = d->array + d->size;
+ T* n = p->array + from - 1;
+ T* e = p->array + d->size;
while (++n != e)
if (*n == t)
- return n - d->array;
+ return n - p->array;
}
return -1;
}
@@ -665,8 +668,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const
else if (from >= d->size)
from = d->size-1;
if (from >= 0) {
- T* b = d->array;
- T* n = d->array + from + 1;
+ T* b = p->array;
+ T* n = p->array + from + 1;
while (n != b) {
if (*--n == t)
return n - b;
@@ -678,8 +681,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const
template <typename T>
bool QVector<T>::contains(const T &t) const
{
- T* b = d->array;
- T* i = d->array + d->size;
+ T* b = p->array;
+ T* i = p->array + d->size;
while (i != b)
if (*--i == t)
return true;
@@ -690,8 +693,8 @@ template <typename T>
int QVector<T>::count(const T &t) const
{
int c = 0;
- T* b = d->array;
- T* i = d->array + d->size;
+ T* b = p->array;
+ T* i = p->array + d->size;
while (i != b)
if (*--i == t)
++c;
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index b70c7df..464c60f 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -5,12 +5,14 @@ HEADERS += \
tools/qbitarray.h \
tools/qbytearray.h \
tools/qbytearraymatcher.h \
+ tools/qbytedata_p.h \
tools/qcache.h \
tools/qchar.h \
tools/qcontainerfwd.h \
tools/qcryptographichash.h \
tools/qdatetime.h \
tools/qdatetime_p.h \
+ tools/qeasingcurve.h \
tools/qhash.h \
tools/qline.h \
tools/qlinkedlist.h \
@@ -19,6 +21,7 @@ HEADERS += \
tools/qlocale_p.h \
tools/qlocale_data_p.h \
tools/qmap.h \
+ tools/qcontiguouscache.h \
tools/qpodlist_p.h \
tools/qpoint.h \
tools/qqueue.h \
@@ -32,13 +35,15 @@ HEADERS += \
tools/qsize.h \
tools/qstack.h \
tools/qstring.h \
+ tools/qstringbuilder.h \
tools/qstringlist.h \
tools/qstringmatcher.h \
tools/qtextboundaryfinder.h \
tools/qtimeline.h \
tools/qunicodetables_p.h \
tools/qvarlengtharray.h \
- tools/qvector.h
+ tools/qvector.h \
+ tools/qscopedpointer.h
SOURCES += \
@@ -47,26 +52,29 @@ SOURCES += \
tools/qbytearraymatcher.cpp \
tools/qcryptographichash.cpp \
tools/qdatetime.cpp \
- tools/qdumper.cpp \
+ tools/qeasingcurve.cpp \
tools/qhash.cpp \
tools/qline.cpp \
tools/qlinkedlist.cpp \
- tools/qlistdata.cpp \
+ tools/qlist.cpp \
tools/qlocale.cpp \
tools/qpoint.cpp \
tools/qmap.cpp \
+ tools/qcontiguouscache.cpp \
tools/qrect.cpp \
tools/qregexp.cpp \
tools/qshareddata.cpp \
tools/qsharedpointer.cpp \
tools/qsize.cpp \
tools/qstring.cpp \
+ tools/qstringbuilder.cpp \
tools/qstringlist.cpp \
tools/qtextboundaryfinder.cpp \
tools/qtimeline.cpp \
tools/qvector.cpp \
tools/qvsnprintf.cpp
+symbian:SOURCES+=tools/qlocale_symbian.cpp
#zlib support
contains(QT_CONFIG, zlib) {
@@ -85,7 +93,7 @@ contains(QT_CONFIG, zlib) {
../3rdparty/zlib/uncompr.c \
../3rdparty/zlib/zutil.c
} else:!contains(QT_CONFIG, no-zlib) {
- unix:LIBS += -lz
+ unix:LIBS_PRIVATE += -lz
# win32:LIBS += libz.lib
}
@@ -103,4 +111,9 @@ SOURCES += ../3rdparty/harfbuzz/src/harfbuzz-buffer.c \
tools/qharfbuzz.cpp
HEADERS += tools/qharfbuzz_p.h
-!macx-icc:unix:LIBS += -lm
+INCLUDEPATH += ../3rdparty/md5 \
+ ../3rdparty/md4
+
+# Note: libm should be present by default becaue this is C++
+!macx-icc:!vxworks:!symbian:unix:LIBS_PRIVATE += -lm
+
diff --git a/src/corelib/xml/make-parser.sh b/src/corelib/xml/make-parser.sh
index 0c2ba12..0e2cbe1 100755
--- a/src/corelib/xml/make-parser.sh
+++ b/src/corelib/xml/make-parser.sh
@@ -6,10 +6,8 @@ mkdir -p $me/out
for f in $me/out/*.h; do
n=$(basename $f)
- p4 open $n
cp $f $n
done
-p4 revert -a ...
-p4 diff -dub ...
+git diff .
diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp
index b7003d3..e379eea 100644
--- a/src/corelib/xml/qxmlstream.cpp
+++ b/src/corelib/xml/qxmlstream.cpp
@@ -52,13 +52,13 @@
#include "qxmlutils_p.h"
#include <qdebug.h>
-#include <QFile>
+#include <qfile.h>
#include <stdio.h>
#include <qtextcodec.h>
#include <qstack.h>
#include <qbuffer.h>
#ifndef QT_BOOTSTRAPPED
-#include <QCoreApplication>
+#include <qcoreapplication.h>
#else
// This specialization of Q_DECLARE_TR_FUNCTIONS is not in qcoreapplication.h,
// because that header depends on QObject being available, which is not the
@@ -129,6 +129,21 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \enum QXmlStreamReader::ReadElementTextBehaviour
+
+ This enum specifies the different behaviours of readElementText().
+
+ \value ErrorOnUnexpectedElement Raise an UnexpectedElementError and return
+ what was read so far when a child element is encountered.
+
+ \value IncludeChildElements Recursively include the text from child elements.
+
+ \value SkipChildElements Skip child elements.
+
+ \since 4.6
+*/
+
+/*!
\enum QXmlStreamReader::Error
This enum specifies different error cases
@@ -244,7 +259,7 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const
\brief The QXmlStreamReader class provides a fast parser for reading
well-formed XML via a simple streaming API.
- \mainclass
+
\ingroup xml-tools
QXmlStreamReader is a faster and more convenient replacement for
@@ -298,8 +313,8 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const
error handling described.
The \l{QXmlStream Bookmarks Example} illustrates how to use the
- recursive descent technique with a subclassed stream reader to read
- an XML bookmark file (XBEL).
+ recursive descent technique to read an XML bookmark file (XBEL) with
+ a stream reader.
\section1 Namespaces
@@ -334,12 +349,17 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const
from the PrematureEndOfDocumentError error and continues parsing the
new data with the next call to readNext().
- For example, if you read data from the network using QHttp, you
- would connect its \l{QHttp::readyRead()}{readyRead()} signal to a
- custom slot. In this slot, you read all available data with
- \l{QHttp::readAll()}{readAll()} and pass it to the XML stream reader
- using addData(). Then you call your custom parsing function that
- reads the XML events from the reader.
+ For example, if your application reads data from the network using a
+ \l{QNetworkAccessManager} {network access manager}, you would issue
+ a \l{QNetworkRequest} {network request} to the manager and receive a
+ \l{QNetworkReply} {network reply} in return. Since a QNetworkReply
+ is a QIODevice, you connect its \l{QNetworkReply::readyRead()}
+ {readyRead()} signal to a custom slot, e.g. \c{slotReadyRead()} in
+ the code snippet shown in the discussion for QNetworkAccessManager.
+ In this slot, you read all available data with
+ \l{QNetworkReply::readAll()} {readAll()} and pass it to the XML
+ stream reader using addData(). Then you call your custom parsing
+ function that reads the XML events from the reader.
\section1 Performance and memory consumption
@@ -429,7 +449,6 @@ QXmlStreamReader::~QXmlStreamReader()
Q_D(QXmlStreamReader);
if (d->deleteDevice)
delete d->device;
- delete d;
}
/*! \fn bool QXmlStreamReader::hasError() const
@@ -568,7 +587,7 @@ bool QXmlStreamReader::atEnd() const
returns true, hasError() returns true, and this function returns
QXmlStreamReader::Invalid.
- The exception is when error() return PrematureEndOfDocumentError.
+ The exception is when error() returns PrematureEndOfDocumentError.
This error is reported when the end of an otherwise well-formed
chunk of XML is reached, but the chunk doesn't represent a complete
XML document. In that case, parsing \e can be resumed by calling
@@ -617,6 +636,56 @@ QXmlStreamReader::TokenType QXmlStreamReader::tokenType() const
return d->type;
}
+/*!
+ Reads until the next start element within the current element. Returns true
+ when a start element was reached. When the end element was reached, or when
+ an error occurred, false is returned.
+
+ The current element is the element matching the most recently parsed start
+ element of which a matching end element has not yet been reached. When the
+ parser has reached the end element, the current element becomes the parent
+ element.
+
+ This is a convenience function for when you're only concerned with parsing
+ XML elements. The \l{QXmlStream Bookmarks Example} makes extensive use of
+ this function.
+
+ \since 4.6
+ \sa readNext()
+ */
+bool QXmlStreamReader::readNextStartElement()
+{
+ while (readNext() != Invalid) {
+ if (isEndElement())
+ return false;
+ else if (isStartElement())
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Reads until the end of the current element, skipping any child nodes.
+ This function is useful for skipping unknown elements.
+
+ The current element is the element matching the most recently parsed start
+ element of which a matching end element has not yet been reached. When the
+ parser has reached the end element, the current element becomes the parent
+ element.
+
+ \since 4.6
+ */
+void QXmlStreamReader::skipCurrentElement()
+{
+ int depth = 1;
+ while (depth && readNext() != Invalid) {
+ if (isEndElement())
+ --depth;
+ else if (isStartElement())
+ ++depth;
+ }
+}
+
/*
* Use the following Perl script to generate the error string index list:
===== PERL SCRIPT ====
@@ -629,7 +698,7 @@ while (<STDIN>) {
$sizes[$i++] = $counter;
$counter += length 1 + $_;
}
-print " \"\\0\";\n\nstatic const int QXmlStreamReader_tokenTypeString_indices[] = {\n ";
+print " \"\\0\";\n\nstatic const short QXmlStreamReader_tokenTypeString_indices[] = {\n ";
for ($j = 0; $j < $i; ++$j) {
printf "$sizes[$j], ";
}
@@ -660,10 +729,9 @@ static const char QXmlStreamReader_tokenTypeString_string[] =
"Comment\0"
"DTD\0"
"EntityReference\0"
- "ProcessingInstruction\0"
- "\0";
+ "ProcessingInstruction\0";
-static const int QXmlStreamReader_tokenTypeString_indices[] = {
+static const short QXmlStreamReader_tokenTypeString_indices[] = {
0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0
};
@@ -819,7 +887,9 @@ inline void QXmlStreamReaderPrivate::reallocateStack()
{
stack_size <<= 1;
sym_stack = reinterpret_cast<Value*> (qRealloc(sym_stack, stack_size * sizeof(Value)));
+ Q_CHECK_PTR(sym_stack);
state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int)));
+ Q_CHECK_PTR(sym_stack);
}
@@ -2017,12 +2087,17 @@ void QXmlStreamReader::addExtraNamespaceDeclarations(const QXmlStreamNamespaceDe
The function concatenates text() when it reads either \l Characters
or EntityReference tokens, but skips ProcessingInstruction and \l
- Comment. In case anything else is read before reaching EndElement,
- the function returns what it read so far and raises an
- UnexpectedElementError. If the current token is not StartElement, an
- empty string is returned.
+ Comment. If the current token is not StartElement, an empty string is
+ returned.
+
+ The \a behaviour defines what happens in case anything else is
+ read before reaching EndElement. The function can include the text from
+ child elements (useful for example for HTML), ignore child elements, or
+ raise an UnexpectedElementError and return what was read so far.
+
+ \since 4.6
*/
-QString QXmlStreamReader::readElementText()
+QString QXmlStreamReader::readElementText(ReadElementTextBehaviour behaviour)
{
Q_D(QXmlStreamReader);
if (isStartElement()) {
@@ -2038,16 +2113,37 @@ QString QXmlStreamReader::readElementText()
case ProcessingInstruction:
case Comment:
break;
+ case StartElement:
+ if (behaviour == SkipChildElements) {
+ skipCurrentElement();
+ break;
+ } else if (behaviour == IncludeChildElements) {
+ result += readElementText(behaviour);
+ break;
+ }
+ // Fall through (for ErrorOnUnexpectedElement)
default:
- if (!d->error)
- d->raiseError(UnexpectedElementError, QXmlStream::tr("Expected character data."));
- return result;
+ if (d->error || behaviour == ErrorOnUnexpectedElement) {
+ if (!d->error)
+ d->raiseError(UnexpectedElementError, QXmlStream::tr("Expected character data."));
+ return result;
+ }
}
}
}
return QString();
}
+/*!
+ \overload readElementText()
+
+ Calling this function is equivalent to calling readElementText(ErrorOnUnexpectedElement).
+ */
+QString QXmlStreamReader::readElementText()
+{
+ return readElementText(ErrorOnUnexpectedElement);
+}
+
/*! Raises a custom error with an optional error \a message.
\sa error(), errorString()
@@ -2788,7 +2884,7 @@ QStringRef QXmlStreamReader::documentEncoding() const
\brief The QXmlStreamWriter class provides an XML writer with a
simple streaming API.
- \mainclass
+
\inmodule QtXml
\ingroup xml-tools
@@ -2848,7 +2944,7 @@ QStringRef QXmlStreamReader::documentEncoding() const
encodings can be enforced using setCodec().
The \l{QXmlStream Bookmarks Example} illustrates how to use a
- subclassed stream writer to write an XML bookmark file (XBEL) that
+ stream writer to write an XML bookmark file (XBEL) that
was previously read in by a QXmlStreamReader.
*/
@@ -3058,7 +3154,7 @@ QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNa
QString s;
int n = ++namespacePrefixCount;
forever {
- s = QLatin1String("n") + QString::number(n++);
+ s = QLatin1Char('n') + QString::number(n++);
int j = namespaceDeclarations.size() - 2;
while (j >= 0 && namespaceDeclarations.at(j).prefix != s)
--j;
@@ -3131,8 +3227,6 @@ QXmlStreamWriter::QXmlStreamWriter(QString *string)
*/
QXmlStreamWriter::~QXmlStreamWriter()
{
- Q_D(QXmlStreamWriter);
- delete d;
}
@@ -3411,11 +3505,12 @@ void QXmlStreamWriter::writeComment(const QString &text)
{
Q_D(QXmlStreamWriter);
Q_ASSERT(!text.contains(QLatin1String("--")) && !text.endsWith(QLatin1Char('-')));
- if (!d->finishStartElement() && d->autoFormatting)
+ if (!d->finishStartElement(false) && d->autoFormatting)
d->indent(d->tagStack.size());
d->write("<!--");
d->write(text);
d->write("-->");
+ d->inStartElement = d->lastWasStartElement = false;
}
diff --git a/src/corelib/xml/qxmlstream.g b/src/corelib/xml/qxmlstream.g
index d957a1c..b9659ba 100644
--- a/src/corelib/xml/qxmlstream.g
+++ b/src/corelib/xml/qxmlstream.g
@@ -1533,8 +1533,8 @@ attribute ::= qname space_opt EQ space_opt attribute_value;
QStringRef namespacePrefix = symString(attribute.key);
QStringRef namespaceUri = symString(attribute.value);
attributeStack.pop();
- if ((namespacePrefix == QLatin1String("xml")
- ^ namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace"))
+ if (((namespacePrefix == QLatin1String("xml"))
+ ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace")))
|| namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/")
|| namespaceUri.isEmpty()
|| namespacePrefix == QLatin1String("xmlns"))
diff --git a/src/corelib/xml/qxmlstream.h b/src/corelib/xml/qxmlstream.h
index 6884104..de93c0e 100644
--- a/src/corelib/xml/qxmlstream.h
+++ b/src/corelib/xml/qxmlstream.h
@@ -42,12 +42,13 @@
#ifndef QXMLSTREAM_H
#define QXMLSTREAM_H
-#include <QtCore/QIODevice>
+#include <QtCore/qiodevice.h>
#ifndef QT_NO_XMLSTREAM
-#include <QtCore/QString>
-#include <QtCore/QVector>
+#include <QtCore/qstring.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_HEADER
@@ -60,7 +61,7 @@ QT_MODULE(Core)
// keep binary compatibility
//
// The list of supported platforms is in:
-// http://qt.nokia.com/developer/notes/supported_platforms
+// http://qt.nokia.com/doc/supported_platforms.html
//
// These platforms do not support symbol moving nor duplication
// (because duplicate symbols cause warnings when linking):
@@ -321,6 +322,9 @@ public:
bool atEnd() const;
TokenType readNext();
+ bool readNextStartElement();
+ void skipCurrentElement();
+
TokenType tokenType() const;
QString tokenString() const;
@@ -348,6 +352,13 @@ public:
qint64 characterOffset() const;
QXmlStreamAttributes attributes() const;
+
+ enum ReadElementTextBehaviour {
+ ErrorOnUnexpectedElement,
+ IncludeChildElements,
+ SkipChildElements
+ };
+ QString readElementText(ReadElementTextBehaviour behaviour);
QString readElementText();
QStringRef name() const;
@@ -392,7 +403,7 @@ public:
private:
Q_DISABLE_COPY(QXmlStreamReader)
Q_DECLARE_PRIVATE(QXmlStreamReader)
- QXmlStreamReaderPrivate *d_ptr;
+ QScopedPointer<QXmlStreamReaderPrivate> d_ptr;
};
#endif // QT_NO_XMLSTREAMREADER
@@ -465,7 +476,7 @@ public:
private:
Q_DISABLE_COPY(QXmlStreamWriter)
Q_DECLARE_PRIVATE(QXmlStreamWriter)
- QXmlStreamWriterPrivate *d_ptr;
+ QScopedPointer<QXmlStreamWriterPrivate> d_ptr;
};
#endif // QT_NO_XMLSTREAMWRITER
diff --git a/src/corelib/xml/qxmlstream_p.h b/src/corelib/xml/qxmlstream_p.h
index de60bd8..b11988e 100644
--- a/src/corelib/xml/qxmlstream_p.h
+++ b/src/corelib/xml/qxmlstream_p.h
@@ -1,3 +1,4 @@
+// This file was generated by qlalr - DO NOT EDIT!
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
@@ -53,6 +54,10 @@
#ifndef QXMLSTREAM_P_H
#define QXMLSTREAM_P_H
+#if defined(Q_OS_VXWORKS) && defined(ERROR)
+# undef ERROR
+#endif
+
class QXmlStreamReader_Table
{
public:
@@ -126,27 +131,22 @@ public:
GOTO_CHECK_OFFSET = 1017
};
- static const char *const spell [];
- static const int lhs [];
- static const int rhs [];
- static const int goto_default [];
- static const int action_default [];
- static const int action_index [];
- static const int action_info [];
- static const int action_check [];
+ static const char *const spell [];
+ static const qint16 lhs [];
+ static const qint16 rhs [];
+ static const qint16 goto_default [];
+ static const qint16 action_default [];
+ static const qint16 action_index [];
+ static const qint16 action_info [];
+ static const qint16 action_check [];
static inline int nt_action (int state, int nt)
{
- const int *const goto_index = &action_index [GOTO_INDEX_OFFSET];
- const int *const goto_check = &action_check [GOTO_CHECK_OFFSET];
-
- const int yyn = goto_index [state] + nt;
-
- if (yyn < 0 || goto_check [yyn] != nt)
+ const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
+ if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
return goto_default [nt];
- const int *const goto_info = &action_info [GOTO_INFO_OFFSET];
- return goto_info [yyn];
+ return action_info [GOTO_INFO_OFFSET + yyn];
}
static inline int t_action (int state, int token)
@@ -169,7 +169,7 @@ const char *const QXmlStreamReader_Table::spell [] = {
"EMPTY", "ANY", "PCDATA", 0, 0, 0, 0, "CDATA", "ID", "IDREF",
"IDREFS", "ENTITIES", "NMTOKEN", "NMTOKENS", "<?xml", "version", 0};
-const int QXmlStreamReader_Table::lhs [] = {
+const qint16 QXmlStreamReader_Table::lhs [] = {
57, 57, 59, 59, 59, 59, 59, 59, 59, 59,
67, 68, 64, 72, 72, 72, 75, 66, 66, 66,
66, 79, 78, 80, 80, 80, 80, 80, 80, 81,
@@ -198,7 +198,7 @@ const int QXmlStreamReader_Table::lhs [] = {
58, 58, 58, 58, 58, 58, 58, 58, 74, 69,
69, 77, 111, 102, 102, 102, 102, 102, 140};
-const int QXmlStreamReader_Table:: rhs[] = {
+const qint16 QXmlStreamReader_Table:: rhs[] = {
2, 1, 4, 2, 2, 2, 2, 2, 2, 0,
1, 1, 9, 2, 4, 0, 4, 4, 6, 6,
4, 1, 3, 1, 1, 1, 2, 2, 2, 1,
@@ -227,7 +227,7 @@ const int QXmlStreamReader_Table:: rhs[] = {
2, 2, 2, 2, 2, 2, 2, 0, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 2};
-const int QXmlStreamReader_Table::action_default [] = {
+const qint16 QXmlStreamReader_Table::action_default [] = {
10, 258, 0, 2, 1, 0, 124, 116, 118, 119,
126, 128, 122, 11, 113, 107, 0, 108, 127, 110,
114, 112, 120, 123, 125, 106, 109, 111, 117, 115,
@@ -272,7 +272,7 @@ const int QXmlStreamReader_Table::action_default [] = {
260, 0, 230, 0, 0, 13, 269, 9, 5, 8,
4, 0, 7, 258, 6, 0, 3};
-const int QXmlStreamReader_Table::goto_default [] = {
+const qint16 QXmlStreamReader_Table::goto_default [] = {
2, 4, 3, 49, 388, 43, 37, 52, 47, 41,
249, 53, 127, 84, 393, 81, 85, 126, 42, 46,
169, 130, 131, 146, 145, 149, 138, 136, 140, 147,
@@ -283,7 +283,7 @@ const int QXmlStreamReader_Table::goto_default [] = {
264, 252, 251, 250, 339, 326, 325, 329, 398, 399,
50, 51, 59, 0};
-const int QXmlStreamReader_Table::action_index [] = {
+const qint16 QXmlStreamReader_Table::action_index [] = {
-21, -57, 33, 119, 960, 70, -57, -57, -57, -57,
-57, -57, -57, -57, -57, -57, 105, -57, -57, -57,
-57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
@@ -372,7 +372,7 @@ const int QXmlStreamReader_Table::action_index [] = {
28, 15, 82, -84, -84, -84, -84, -84, -84, -84,
-84, -84, -84, 3, -84, 98, -84};
-const int QXmlStreamReader_Table::action_info [] = {
+const qint16 QXmlStreamReader_Table::action_info [] = {
65, 332, 65, 405, 392, 385, 377, 65, 414, 410,
415, 55, 397, 374, 373, 217, 206, 408, 65, 65,
207, 211, 216, 1, 55, 199, 182, 192, 70, 70,
@@ -506,7 +506,7 @@ const int QXmlStreamReader_Table::action_info [] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0};
-const int QXmlStreamReader_Table::action_check [] = {
+const qint16 QXmlStreamReader_Table::action_check [] = {
26, 18, 26, 14, 4, 4, 4, 26, 24, 14,
4, 26, 4, 4, 4, 4, 22, 55, 26, 26,
42, 4, 4, 44, 26, 22, 19, 12, 2, 2,
@@ -652,6 +652,7 @@ public:
if (tos + extraCapacity + 1 > cap) {
cap = qMax(tos + extraCapacity + 1, cap << 1 );
data = reinterpret_cast<T *>(qRealloc(data, cap * sizeof(T)));
+ Q_CHECK_PTR(data);
}
}
diff --git a/src/corelib/xml/qxmlutils.cpp b/src/corelib/xml/qxmlutils.cpp
index a13601b..f719a96 100644
--- a/src/corelib/xml/qxmlutils.cpp
+++ b/src/corelib/xml/qxmlutils.cpp
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#include <QRegExp>
-#include <QString>
+#include <qregexp.h>
+#include <qstring.h>
#include "qxmlutils_p.h"
diff --git a/src/corelib/xml/qxmlutils_p.h b/src/corelib/xml/qxmlutils_p.h
index 4d968dc..1902b4e 100644
--- a/src/corelib/xml/qxmlutils_p.h
+++ b/src/corelib/xml/qxmlutils_p.h
@@ -53,7 +53,7 @@
// We mean it.
//
-#include <QtCore/QString>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE