summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/bearer/bearer.pro2
-rw-r--r--src/plugins/bearer/generic/qgenericengine.cpp38
-rw-r--r--src/plugins/bearer/nla/nla.pro6
-rw-r--r--src/plugins/generic/tuiotouch/qtuiohandler.cpp256
-rw-r--r--src/plugins/generic/tuiotouch/qtuiohandler_p.h8
-rw-r--r--src/plugins/generic/tuiotouch/qtuiotoken_p.h144
-rw-r--r--src/plugins/generic/tuiotouch/tuiotouch.pro3
-rw-r--r--src/plugins/imageformats/gif/gif.pro7
-rw-r--r--src/plugins/imageformats/gif/qgifhandler.cpp1218
-rw-r--r--src/plugins/imageformats/gif/qgifhandler_p.h105
-rw-r--r--src/plugins/imageformats/ico/ico.pro7
-rw-r--r--src/plugins/imageformats/imageformats.pro4
-rw-r--r--src/plugins/imageformats/jpeg/jpeg.pro16
-rw-r--r--src/plugins/imageformats/jpeg/qjpeghandler.cpp1144
-rw-r--r--src/plugins/imageformats/jpeg/qjpeghandler_p.h85
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp2
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp14
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp18
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.h2
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.cpp3
-rw-r--r--src/plugins/platforms/bsdfb/bsdfb.json3
-rw-r--r--src/plugins/platforms/bsdfb/bsdfb.pro15
-rw-r--r--src/plugins/platforms/bsdfb/main.cpp60
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbintegration.cpp142
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbintegration.h81
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbscreen.cpp276
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbscreen.h74
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm10
-rw-r--r--src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm10
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm7
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm59
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm90
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm24
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h1
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm65
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac.mm5
-rw-r--r--src/plugins/platforms/direct2d/direct2d.pro2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp10
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp2
-rw-r--r--src/plugins/platforms/directfb/qdirectfbbackingstore.cpp16
-rw-r--r--src/plugins/platforms/directfb/qdirectfbbackingstore.h2
-rw-r--r--src/plugins/platforms/eglfs/api/api.pri15
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor.cpp (renamed from src/plugins/platforms/eglfs/qeglfscursor.cpp)4
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor_p.h (renamed from src/plugins/platforms/eglfs/qeglfscursor.h)0
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp (renamed from src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp)105
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h (renamed from src/plugins/platforms/eglfs/qeglfsdeviceintegration.h)18
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsglobal.h (renamed from src/plugins/platforms/eglfs/qeglfsglobal.h)9
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfshooks.cpp (renamed from src/plugins/platforms/eglfs/qeglfshooks.cpp)16
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfshooks_p.h (renamed from src/plugins/platforms/eglfs/qeglfshooks.h)17
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsscreen.cpp (renamed from src/plugins/platforms/eglfs/qeglfsscreen.cpp)6
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsscreen_p.h (renamed from src/plugins/platforms/eglfs/qeglfsscreen.h)13
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow.cpp (renamed from src/plugins/platforms/eglfs/qeglfswindow.cpp)9
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow_p.h (renamed from src/plugins/platforms/eglfs/qeglfswindow.h)13
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/eglfs_viv_wl.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp8
-rw-r--r--src/plugins/platforms/eglfs/eglfs-plugin.pro2
-rw-r--r--src/plugins/platforms/eglfs/eglfs.pro2
-rw-r--r--src/plugins/platforms/eglfs/eglfsdeviceintegration.pro (renamed from src/plugins/platforms/eglfs/eglfs_device_lib.pro)17
-rw-r--r--src/plugins/platforms/eglfs/qeglfscontext.cpp6
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.cpp26
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.h2
-rw-r--r--src/plugins/platforms/eglfs/qeglfsoffscreenwindow.cpp2
-rw-r--r--src/plugins/platforms/ios/ios.pro36
-rw-r--r--src/plugins/platforms/ios/plugin.mm4
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm2
-rw-r--r--src/plugins/platforms/ios/qiosfileenginefactory.h4
-rw-r--r--src/plugins/platforms/ios/qiosglobal.h7
-rw-r--r--src/plugins/platforms/ios/qiosglobal.mm22
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm14
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h7
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm10
-rw-r--r--src/plugins/platforms/ios/qiosmenu.mm2
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm22
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.mm22
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm12
-rw-r--r--src/plugins/platforms/ios/qiostheme.mm12
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.h4
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm66
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm2
-rw-r--r--src/plugins/platforms/ios/quiview.mm23
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp6
-rw-r--r--src/plugins/platforms/mirclient/qmirclientbackingstore.cpp4
-rw-r--r--src/plugins/platforms/offscreen/qoffscreencommon.cpp5
-rw-r--r--src/plugins/platforms/platforms.pro12
-rw-r--r--src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp4
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp12
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp4
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp4
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp3
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatorpps.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterwindow.cpp5
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.cpp13
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp4
-rw-r--r--src/plugins/platforms/vnc/main.cpp65
-rw-r--r--src/plugins/platforms/vnc/qvnc.cpp680
-rw-r--r--src/plugins/platforms/vnc/qvnc_p.h417
-rw-r--r--src/plugins/platforms/vnc/qvncclient.cpp662
-rw-r--r--src/plugins/platforms/vnc/qvncclient.h149
-rw-r--r--src/plugins/platforms/vnc/qvncintegration.cpp148
-rw-r--r--src/plugins/platforms/vnc/qvncintegration.h85
-rw-r--r--src/plugins/platforms/vnc/qvncscreen.cpp187
-rw-r--r--src/plugins/platforms/vnc/qvncscreen.h93
-rw-r--r--src/plugins/platforms/vnc/vnc.json3
-rw-r--r--src/plugins/platforms/vnc/vnc.pro25
-rw-r--r--src/plugins/platforms/windows/accessible/accessible.pri14
-rw-r--r--src/plugins/platforms/windows/accessible/comutils.cpp24
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp36
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp2
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h2
-rw-r--r--src/plugins/platforms/windows/qplatformfunctions_wince.h371
-rw-r--r--src/plugins/platforms/windows/qtwindows_additional.h179
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h23
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.cpp39
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsclipboard.cpp3
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp208
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h46
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp70
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp340
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.cpp12
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.cpp26
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp333
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase_ft.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp124
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp10
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp49
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsinternalmimedata.cpp1
-rw-r--r--src/plugins/platforms/windows/qwindowsinternalmimedata.h2
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp34
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp128
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.h6
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeimage.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeimage.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsole.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.cpp36
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp25
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h3
-rw-r--r--src/plugins/platforms/windows/qwindowsservices.cpp15
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.h4
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp82
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp185
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h22
-rw-r--r--src/plugins/platforms/windows/windows.pri40
-rw-r--r--src/plugins/platforms/windows/windows.pro2
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp19
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp18
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h1
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp5
-rw-r--r--src/plugins/platforms/xcb/xcb_qpa_lib.pro10
-rw-r--r--src/plugins/platformthemes/gtk3/gtk3.pro6
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp12
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3menu.cpp489
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3menu.h162
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3theme.cpp11
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3theme.h3
-rw-r--r--src/plugins/sqldrivers/db2/db2.pro11
-rw-r--r--src/plugins/sqldrivers/db2/main.cpp2
-rw-r--r--src/plugins/sqldrivers/db2/qsql_db2.cpp1700
-rw-r--r--src/plugins/sqldrivers/db2/qsql_db2_p.h103
-rw-r--r--src/plugins/sqldrivers/ibase/ibase.pro13
-rw-r--r--src/plugins/sqldrivers/ibase/main.cpp2
-rw-r--r--src/plugins/sqldrivers/ibase/qsql_ibase.cpp1948
-rw-r--r--src/plugins/sqldrivers/ibase/qsql_ibase_p.h114
-rw-r--r--src/plugins/sqldrivers/mysql/main.cpp2
-rw-r--r--src/plugins/sqldrivers/mysql/mysql.pro19
-rw-r--r--src/plugins/sqldrivers/mysql/qsql_mysql.cpp1666
-rw-r--r--src/plugins/sqldrivers/mysql/qsql_mysql_p.h110
-rw-r--r--src/plugins/sqldrivers/oci/main.cpp2
-rw-r--r--src/plugins/sqldrivers/oci/oci.pro12
-rw-r--r--src/plugins/sqldrivers/oci/qsql_oci.cpp2725
-rw-r--r--src/plugins/sqldrivers/oci/qsql_oci_p.h106
-rw-r--r--src/plugins/sqldrivers/odbc/main.cpp2
-rw-r--r--src/plugins/sqldrivers/odbc/odbc.pro15
-rw-r--r--src/plugins/sqldrivers/odbc/qsql_odbc.cpp2639
-rw-r--r--src/plugins/sqldrivers/odbc/qsql_odbc_p.h127
-rw-r--r--src/plugins/sqldrivers/psql/main.cpp2
-rw-r--r--src/plugins/sqldrivers/psql/psql.pro13
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql.cpp1508
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql_p.h128
-rw-r--r--src/plugins/sqldrivers/sqldrivers.pro18
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp903
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h106
-rw-r--r--src/plugins/sqldrivers/sqlite/smain.cpp2
-rw-r--r--src/plugins/sqldrivers/sqlite/sqlite.pro12
-rw-r--r--src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp615
-rw-r--r--src/plugins/sqldrivers/sqlite2/qsql_sqlite2_p.h109
-rw-r--r--src/plugins/sqldrivers/sqlite2/smain.cpp2
-rw-r--r--src/plugins/sqldrivers/sqlite2/sqlite2.pro7
-rw-r--r--src/plugins/sqldrivers/tds/main.cpp2
-rw-r--r--src/plugins/sqldrivers/tds/qsql_tds.cpp881
-rw-r--r--src/plugins/sqldrivers/tds/qsql_tds_p.h120
-rw-r--r--src/plugins/sqldrivers/tds/tds.pro13
240 files changed, 23315 insertions, 3039 deletions
diff --git a/src/plugins/bearer/bearer.pro b/src/plugins/bearer/bearer.pro
index cc590cc545..8028e65147 100644
--- a/src/plugins/bearer/bearer.pro
+++ b/src/plugins/bearer/bearer.pro
@@ -7,7 +7,7 @@ TEMPLATE = subdirs
#win32:SUBDIRS += nla
win32:SUBDIRS += generic
-win32:!wince:!winrt: SUBDIRS += nativewifi
+win32:!winrt: SUBDIRS += nativewifi
mac:contains(QT_CONFIG, corewlan):SUBDIRS += corewlan
mac:SUBDIRS += generic
android:SUBDIRS += android
diff --git a/src/plugins/bearer/generic/qgenericengine.cpp b/src/plugins/bearer/generic/qgenericengine.cpp
index aa0fc6b945..02ea7abf88 100644
--- a/src/plugins/bearer/generic/qgenericengine.cpp
+++ b/src/plugins/bearer/generic/qgenericengine.cpp
@@ -50,17 +50,10 @@
#include <QtCore/qdebug.h>
#include <QtCore/private/qcoreapplication_p.h>
-#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+#if defined(Q_OS_WIN32)
#include "../platformdefs_win.h"
#endif
-#ifdef Q_OS_WINCE
-typedef ULONG NDIS_OID, *PNDIS_OID;
-# ifndef QT_NO_WINCE_NUIOUSER
-# include <nuiouser.h>
-# endif
-#endif // Q_OS_WINCE
-
#ifdef Q_OS_WINRT
#include <qfunctions_winrt.h>
@@ -92,36 +85,22 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_NETWORKINTERFACE
static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interface)
{
-#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+#if defined(Q_OS_WIN32)
DWORD bytesWritten;
NDIS_MEDIUM medium;
NDIS_PHYSICAL_MEDIUM physicalMedium;
-#if defined(Q_OS_WINCE) && !defined(QT_NO_WINCE_NUIOUSER)
- NDISUIO_QUERY_OID nicGetOid;
- HANDLE handle = CreateFile((PTCHAR)NDISUIO_DEVICE_NAME, 0,
- FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
-#else
unsigned long oid;
HANDLE handle = CreateFile((TCHAR *)QString::fromLatin1("\\\\.\\%1").arg(interface).utf16(), 0,
FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
-#endif
if (handle == INVALID_HANDLE_VALUE)
return QNetworkConfiguration::BearerUnknown;
bytesWritten = 0;
-#if defined(Q_OS_WINCE) && !defined(QT_NO_WINCE_NUIOUSER)
- ZeroMemory(&nicGetOid, sizeof(NDISUIO_QUERY_OID));
- nicGetOid.Oid = OID_GEN_MEDIA_SUPPORTED;
- nicGetOid.ptcDeviceName = (PTCHAR)interface.utf16();
- bool result = DeviceIoControl(handle, IOCTL_NDISUIO_QUERY_OID_VALUE, &nicGetOid, sizeof(nicGetOid),
- &nicGetOid, sizeof(nicGetOid), &bytesWritten, 0);
-#else
oid = OID_GEN_MEDIA_SUPPORTED;
bool result = DeviceIoControl(handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof(oid),
&medium, sizeof(medium), &bytesWritten, 0);
-#endif
if (!result) {
CloseHandle(handle);
return QNetworkConfiguration::BearerUnknown;
@@ -129,22 +108,9 @@ static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interf
bytesWritten = 0;
-#if defined(Q_OS_WINCE) && !defined(QT_NO_WINCE_NUIOUSER)
- medium = NDIS_MEDIUM( *(LPDWORD)nicGetOid.Data );
-
- ZeroMemory(&nicGetOid, sizeof(NDISUIO_QUERY_OID));
- nicGetOid.Oid = OID_GEN_PHYSICAL_MEDIUM;
- nicGetOid.ptcDeviceName = (PTCHAR)interface.utf16();
-
- result = DeviceIoControl(handle, IOCTL_NDISUIO_QUERY_OID_VALUE, &nicGetOid, sizeof(nicGetOid),
- &nicGetOid, sizeof(nicGetOid), &bytesWritten, 0);
-
- physicalMedium = NDIS_PHYSICAL_MEDIUM( *(LPDWORD)nicGetOid.Data );
-#else
oid = OID_GEN_PHYSICAL_MEDIUM;
result = DeviceIoControl(handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof(oid),
&physicalMedium, sizeof(physicalMedium), &bytesWritten, 0);
-#endif
if (!result) {
CloseHandle(handle);
diff --git a/src/plugins/bearer/nla/nla.pro b/src/plugins/bearer/nla/nla.pro
index 32ff5446e5..113d0667d2 100644
--- a/src/plugins/bearer/nla/nla.pro
+++ b/src/plugins/bearer/nla/nla.pro
@@ -2,11 +2,7 @@ TARGET = qnlabearer
QT = core core-private network network-private
-!wince* {
- LIBS += -lws2_32
-} else {
- LIBS += -lws2
-}
+LIBS += -lws2_32
HEADERS += qnlaengine.h \
../platformdefs_win.h \
diff --git a/src/plugins/generic/tuiotouch/qtuiohandler.cpp b/src/plugins/generic/tuiotouch/qtuiohandler.cpp
index 5d34e0ea38..38105fe656 100644
--- a/src/plugins/generic/tuiotouch/qtuiohandler.cpp
+++ b/src/plugins/generic/tuiotouch/qtuiohandler.cpp
@@ -43,10 +43,12 @@
#include <QWindow>
#include <QGuiApplication>
#include <QTouchDevice>
+#include <qmath.h>
#include <qpa/qwindowsysteminterface.h>
#include "qtuiocursor_p.h"
+#include "qtuiotoken_p.h"
#include "qtuiohandler_p.h"
#include "qoscbundle_p.h"
@@ -55,6 +57,12 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcTuioSource, "qt.qpa.tuio.source")
Q_LOGGING_CATEGORY(lcTuioSet, "qt.qpa.tuio.set")
+// With TUIO the first application takes exclusive ownership of the "device"
+// we cannot attach more than one application to the same port anyway.
+// Forcing delivery makes it easy to use simulators in the same machine
+// and forget about headaches about unfocused TUIO windows.
+static bool forceDelivery = qEnvironmentVariableIsSet("QT_TUIOTOUCH_DELIVER_WITHOUT_FOCUS");
+
QTuioHandler::QTuioHandler(const QString &specification)
: m_device(new QTouchDevice) // not leaked, QTouchDevice cleans up registered devices itself
{
@@ -157,29 +165,49 @@ void QTuioHandler::processPackets()
messages.push_back(msg);
}
- foreach (const QOscMessage &message, messages) {
- if (message.addressPattern() != "/tuio/2Dcur") {
- qWarning() << "Ignoring unknown address pattern " << message.addressPattern();
- continue;
- }
-
- QList<QVariant> arguments = message.arguments();
- if (arguments.count() == 0) {
- qWarning("Ignoring TUIO message with no arguments");
- continue;
- }
-
- QByteArray messageType = arguments.at(0).toByteArray();
- if (messageType == "source") {
- process2DCurSource(message);
- } else if (messageType == "alive") {
- process2DCurAlive(message);
- } else if (messageType == "set") {
- process2DCurSet(message);
- } else if (messageType == "fseq") {
- process2DCurFseq(message);
+ for (const QOscMessage &message : messages) {
+ if (message.addressPattern() == "/tuio/2Dcur") {
+ QList<QVariant> arguments = message.arguments();
+ if (arguments.count() == 0) {
+ qWarning("Ignoring TUIO message with no arguments");
+ continue;
+ }
+
+ QByteArray messageType = arguments.at(0).toByteArray();
+ if (messageType == "source") {
+ process2DCurSource(message);
+ } else if (messageType == "alive") {
+ process2DCurAlive(message);
+ } else if (messageType == "set") {
+ process2DCurSet(message);
+ } else if (messageType == "fseq") {
+ process2DCurFseq(message);
+ } else {
+ qWarning() << "Ignoring unknown TUIO message type: " << messageType;
+ continue;
+ }
+ } else if (message.addressPattern() == "/tuio/2Dobj") {
+ QList<QVariant> arguments = message.arguments();
+ if (arguments.count() == 0) {
+ qWarning("Ignoring TUIO message with no arguments");
+ continue;
+ }
+
+ QByteArray messageType = arguments.at(0).toByteArray();
+ if (messageType == "source") {
+ process2DObjSource(message);
+ } else if (messageType == "alive") {
+ process2DObjAlive(message);
+ } else if (messageType == "set") {
+ process2DObjSet(message);
+ } else if (messageType == "fseq") {
+ process2DObjFseq(message);
+ } else {
+ qWarning() << "Ignoring unknown TUIO message type: " << messageType;
+ continue;
+ }
} else {
- qWarning() << "Ignoring unknown TUIO message type: " << messageType;
+ qWarning() << "Ignoring unknown address pattern " << message.addressPattern();
continue;
}
}
@@ -327,11 +355,6 @@ void QTuioHandler::process2DCurFseq(const QOscMessage &message)
Q_UNUSED(message); // TODO: do we need to do anything with the frame id?
QWindow *win = QGuiApplication::focusWindow();
- // With TUIO the first application takes exclusive ownership of the "device"
- // we cannot attach more than one application to the same port anyway.
- // Forcing delivery makes it easy to use simulators in the same machine
- // and forget about headaches about unfocused TUIO windows.
- static bool forceDelivery = qEnvironmentVariableIsSet("QT_TUIOTOUCH_DELIVER_WITHOUT_FOCUS");
if (!win && QGuiApplication::topLevelWindows().length() > 0 && forceDelivery)
win = QGuiApplication::topLevelWindows().at(0);
@@ -341,12 +364,12 @@ void QTuioHandler::process2DCurFseq(const QOscMessage &message)
QList<QWindowSystemInterface::TouchPoint> tpl;
tpl.reserve(m_activeCursors.size() + m_deadCursors.size());
- foreach (const QTuioCursor &tc, m_activeCursors) {
+ for (const QTuioCursor &tc : m_activeCursors) {
QWindowSystemInterface::TouchPoint tp = cursorToTouchPoint(tc, win);
tpl.append(tp);
}
- foreach (const QTuioCursor &tc, m_deadCursors) {
+ for (const QTuioCursor &tc : m_deadCursors) {
QWindowSystemInterface::TouchPoint tp = cursorToTouchPoint(tc, win);
tp.state = Qt::TouchPointReleased;
tpl.append(tp);
@@ -356,5 +379,180 @@ void QTuioHandler::process2DCurFseq(const QOscMessage &message)
m_deadCursors.clear();
}
+void QTuioHandler::process2DObjSource(const QOscMessage &message)
+{
+ QList<QVariant> arguments = message.arguments();
+ if (arguments.count() != 2) {
+ qWarning() << "Ignoring malformed TUIO source message: " << arguments.count();
+ return;
+ }
+
+ if (QMetaType::Type(arguments.at(1).type()) != QMetaType::QByteArray) {
+ qWarning("Ignoring malformed TUIO source message (bad argument type)");
+ return;
+ }
+
+ qCDebug(lcTuioSource) << "Got TUIO source message from: " << arguments.at(1).toByteArray();
+}
+
+void QTuioHandler::process2DObjAlive(const QOscMessage &message)
+{
+ QList<QVariant> arguments = message.arguments();
+
+ // delta the notified tokens that are active, against the ones we already
+ // know of.
+ //
+ // TBD: right now we're assuming one 2DObj alive message corresponds to a
+ // new data source from the input. is this correct, or do we need to store
+ // changes and only process the deltas on fseq?
+ QMap<int, QTuioToken> oldActiveTokens = m_activeTokens;
+ QMap<int, QTuioToken> newActiveTokens;
+
+ for (int i = 1; i < arguments.count(); ++i) {
+ if (QMetaType::Type(arguments.at(i).type()) != QMetaType::Int) {
+ qWarning() << "Ignoring malformed TUIO alive message (bad argument on position" << i << arguments << ')';
+ return;
+ }
+
+ int sessionId = arguments.at(i).toInt();
+ if (!oldActiveTokens.contains(sessionId)) {
+ // newly active
+ QTuioToken token(sessionId);
+ token.setState(Qt::TouchPointPressed);
+ newActiveTokens.insert(sessionId, token);
+ } else {
+ // we already know about it, remove it so it isn't marked as released
+ QTuioToken token = oldActiveTokens.value(sessionId);
+ token.setState(Qt::TouchPointStationary); // position change in SET will update if needed
+ newActiveTokens.insert(sessionId, token);
+ oldActiveTokens.remove(sessionId);
+ }
+ }
+
+ // anything left is dead now
+ QMap<int, QTuioToken>::ConstIterator it = oldActiveTokens.constBegin();
+
+ // deadTokens should be cleared from the last FSEQ now
+ m_deadTokens.reserve(oldActiveTokens.size());
+
+ // TODO: there could be an issue of resource exhaustion here if FSEQ isn't
+ // sent in a timely fashion. we should probably track message counts and
+ // force-flush if we get too many built up.
+ while (it != oldActiveTokens.constEnd()) {
+ m_deadTokens.append(it.value());
+ ++it;
+ }
+
+ m_activeTokens = newActiveTokens;
+}
+
+void QTuioHandler::process2DObjSet(const QOscMessage &message)
+{
+ QList<QVariant> arguments = message.arguments();
+ if (arguments.count() < 7) {
+ qWarning() << "Ignoring malformed TUIO set message with too few arguments: " << arguments.count();
+ return;
+ }
+
+ if (QMetaType::Type(arguments.at(1).type()) != QMetaType::Int ||
+ QMetaType::Type(arguments.at(2).type()) != QMetaType::Int ||
+ QMetaType::Type(arguments.at(3).type()) != QMetaType::Float ||
+ QMetaType::Type(arguments.at(4).type()) != QMetaType::Float ||
+ QMetaType::Type(arguments.at(5).type()) != QMetaType::Float ||
+ QMetaType::Type(arguments.at(6).type()) != QMetaType::Float ||
+ QMetaType::Type(arguments.at(7).type()) != QMetaType::Float ||
+ QMetaType::Type(arguments.at(8).type()) != QMetaType::Float ||
+ QMetaType::Type(arguments.at(9).type()) != QMetaType::Float ||
+ QMetaType::Type(arguments.at(10).type()) != QMetaType::Float) {
+ qWarning() << "Ignoring malformed TUIO set message with bad types: " << arguments;
+ return;
+ }
+
+ int id = arguments.at(1).toInt();
+ int classId = arguments.at(2).toInt();
+ float x = arguments.at(3).toFloat();
+ float y = arguments.at(4).toFloat();
+ float angle = arguments.at(5).toFloat();
+ float vx = arguments.at(6).toFloat();
+ float vy = arguments.at(7).toFloat();
+ float angularVelocity = arguments.at(8).toFloat();
+ float acceleration = arguments.at(9).toFloat();
+ float angularAcceleration = arguments.at(10).toFloat();
+
+ QMap<int, QTuioToken>::Iterator it = m_activeTokens.find(id);
+ if (it == m_activeTokens.end()) {
+ qWarning() << "Ignoring malformed TUIO set for nonexistent token " << classId;
+ return;
+ }
+
+ qCDebug(lcTuioSet) << "Processing SET for token " << classId << id << " @ " << x << y << "∡" << angle <<
+ "vel" << vx << vy << angularVelocity << "acc" << acceleration << angularAcceleration;
+ QTuioToken &tok = *it;
+ tok.setClassId(classId);
+ tok.setX(x);
+ tok.setY(y);
+ tok.setVX(vx);
+ tok.setVY(vy);
+ tok.setAcceleration(acceleration);
+ tok.setAngle(angle);
+ tok.setAngularVelocity(angularAcceleration);
+ tok.setAngularAcceleration(angularAcceleration);
+}
+
+QWindowSystemInterface::TouchPoint QTuioHandler::tokenToTouchPoint(const QTuioToken &tc, QWindow *win)
+{
+ QWindowSystemInterface::TouchPoint tp;
+ tp.id = tc.id();
+ tp.uniqueId = tc.classId(); // TODO TUIO 2.0: populate a QVariant, and register the mapping from int to arbitrary UID data
+ tp.flags = QTouchEvent::TouchPoint::Token;
+ tp.pressure = 1.0f;
+
+ tp.normalPosition = QPointF(tc.x(), tc.y());
+
+ if (!m_transform.isIdentity())
+ tp.normalPosition = m_transform.map(tp.normalPosition);
+
+ tp.state = tc.state();
+
+ // We map the token position to the size of the window.
+ QPointF relPos = QPointF(win->size().width() * tp.normalPosition.x(), win->size().height() * tp.normalPosition.y());
+ QPointF delta = relPos - relPos.toPoint();
+ tp.area.moveCenter(win->mapToGlobal(relPos.toPoint()) + delta);
+ tp.velocity = QVector2D(win->size().width() * tc.vx(), win->size().height() * tc.vy());
+ tp.rotation = tc.angle() * 180.0 / M_PI; // convert radians to degrees
+ return tp;
+}
+
+
+void QTuioHandler::process2DObjFseq(const QOscMessage &message)
+{
+ Q_UNUSED(message); // TODO: do we need to do anything with the frame id?
+
+ QWindow *win = QGuiApplication::focusWindow();
+ if (!win && QGuiApplication::topLevelWindows().length() > 0 && forceDelivery)
+ win = QGuiApplication::topLevelWindows().at(0);
+
+ if (!win)
+ return;
+
+ QList<QWindowSystemInterface::TouchPoint> tpl;
+ tpl.reserve(m_activeTokens.size() + m_deadTokens.size());
+
+ for (const QTuioToken & t : m_activeTokens) {
+ QWindowSystemInterface::TouchPoint tp = tokenToTouchPoint(t, win);
+ tpl.append(tp);
+ }
+
+ for (const QTuioToken & t : m_deadTokens) {
+ QWindowSystemInterface::TouchPoint tp = tokenToTouchPoint(t, win);
+ tp.state = Qt::TouchPointReleased;
+ tp.velocity = QVector2D();
+ tpl.append(tp);
+ }
+ QWindowSystemInterface::handleTouchEvent(win, m_device, tpl);
+
+ m_deadTokens.clear();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/generic/tuiotouch/qtuiohandler_p.h b/src/plugins/generic/tuiotouch/qtuiohandler_p.h
index 3034872aae..2e444f2a0d 100644
--- a/src/plugins/generic/tuiotouch/qtuiohandler_p.h
+++ b/src/plugins/generic/tuiotouch/qtuiohandler_p.h
@@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE
class QTouchDevice;
class QOscMessage;
class QTuioCursor;
+class QTuioToken;
class QTuioHandler : public QObject
{
@@ -69,14 +70,21 @@ private slots:
void process2DCurAlive(const QOscMessage &message);
void process2DCurSet(const QOscMessage &message);
void process2DCurFseq(const QOscMessage &message);
+ void process2DObjSource(const QOscMessage &message);
+ void process2DObjAlive(const QOscMessage &message);
+ void process2DObjSet(const QOscMessage &message);
+ void process2DObjFseq(const QOscMessage &message);
private:
QWindowSystemInterface::TouchPoint cursorToTouchPoint(const QTuioCursor &tc, QWindow *win);
+ QWindowSystemInterface::TouchPoint tokenToTouchPoint(const QTuioToken &tc, QWindow *win);
QTouchDevice *m_device;
QUdpSocket m_socket;
QMap<int, QTuioCursor> m_activeCursors;
QVector<QTuioCursor> m_deadCursors;
+ QMap<int, QTuioToken> m_activeTokens;
+ QVector<QTuioToken> m_deadTokens;
QTransform m_transform;
};
diff --git a/src/plugins/generic/tuiotouch/qtuiotoken_p.h b/src/plugins/generic/tuiotouch/qtuiotoken_p.h
new file mode 100644
index 0000000000..5084aeed11
--- /dev/null
+++ b/src/plugins/generic/tuiotouch/qtuiotoken_p.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTUIOOBJECT_P_H
+#define QTUIOOBJECT_P_H
+
+#include <Qt>
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+
+ A fiducial object, or token, represented by 2Dobj in TUIO 1.x and tok in TUIO 2:
+ a physical object whose position and rotation can be uniquely tracked
+ on the touchscreen surface.
+*/
+class QTuioToken
+{
+public:
+ QTuioToken(int id = -1)
+ : m_id(id)
+ , m_classId(-1)
+ , m_x(0)
+ , m_y(0)
+ , m_vx(0)
+ , m_vy(0)
+ , m_acceleration(0)
+ , m_angle(0)
+ , m_angularVelocity(0)
+ , m_angularAcceleration(0)
+ , m_state(Qt::TouchPointPressed)
+ {
+ }
+
+ int id() const { return m_id; }
+
+ int classId() const { return m_classId; }
+ void setClassId(int classId) { m_classId = classId; }
+
+ void setX(float x)
+ {
+ if (state() == Qt::TouchPointStationary &&
+ !qFuzzyCompare(m_x + 2.0, x + 2.0)) { // +2 because 1 is a valid value, and qFuzzyCompare can't cope with 0.0
+ setState(Qt::TouchPointMoved);
+ }
+ m_x = x;
+ }
+ float x() const { return m_x; }
+
+ void setY(float y)
+ {
+ if (state() == Qt::TouchPointStationary &&
+ !qFuzzyCompare(m_y + 2.0, y + 2.0)) { // +2 because 1 is a valid value, and qFuzzyCompare can't cope with 0.0
+ setState(Qt::TouchPointMoved);
+ }
+ m_y = y;
+ }
+ float y() const { return m_y; }
+
+ void setVX(float vx) { m_vx = vx; }
+ float vx() const { return m_vx; }
+
+ void setVY(float vy) { m_vy = vy; }
+ float vy() const { return m_vy; }
+
+ void setAcceleration(float acceleration) { m_acceleration = acceleration; }
+ float acceleration() const { return m_acceleration; }
+
+ float angle() const { return m_angle; }
+ void setAngle(float angle)
+ {
+ if (angle > M_PI)
+ angle = angle - M_PI * 2.0; // zero is pointing upwards, and is the default; but we want to have negative angles when rotating left
+ if (state() == Qt::TouchPointStationary &&
+ !qFuzzyCompare(m_angle + 2.0, angle + 2.0)) { // +2 because 1 is a valid value, and qFuzzyCompare can't cope with 0.0
+ setState(Qt::TouchPointMoved);
+ }
+ m_angle = angle;
+ }
+
+ float angularVelocity() const { return m_angularVelocity; }
+ void setAngularVelocity(float angularVelocity) { m_angularVelocity = angularVelocity; }
+
+ float angularAcceleration() const { return m_angularAcceleration; }
+ void setAngularAcceleration(float angularAcceleration) { m_angularAcceleration = angularAcceleration; }
+
+ void setState(const Qt::TouchPointState &state) { m_state = state; }
+ Qt::TouchPointState state() const { return m_state; }
+
+private:
+ int m_id; // sessionID, temporary object ID
+ int m_classId; // classID (e.g. marker ID)
+ float m_x;
+ float m_y;
+ float m_vx;
+ float m_vy;
+ float m_acceleration;
+ float m_angle;
+ float m_angularVelocity;
+ float m_angularAcceleration;
+ Qt::TouchPointState m_state;
+};
+
+QT_END_NAMESPACE
+
+#endif // QTUIOOBJECT_P_H
diff --git a/src/plugins/generic/tuiotouch/tuiotouch.pro b/src/plugins/generic/tuiotouch/tuiotouch.pro
index ae2ccde058..ad6a1c6876 100644
--- a/src/plugins/generic/tuiotouch/tuiotouch.pro
+++ b/src/plugins/generic/tuiotouch/tuiotouch.pro
@@ -15,7 +15,8 @@ HEADERS += \
qoscbundle_p.h \
qoscmessage_p.h \
qtuiohandler_p.h \
- qtuiocursor_p.h
+ qtuiocursor_p.h \
+ qtuiotoken_p.h
OTHER_FILES += \
tuiotouch.json
diff --git a/src/plugins/imageformats/gif/gif.pro b/src/plugins/imageformats/gif/gif.pro
index a361bc2532..c2625be85a 100644
--- a/src/plugins/imageformats/gif/gif.pro
+++ b/src/plugins/imageformats/gif/gif.pro
@@ -1,9 +1,8 @@
TARGET = qgif
-include(../../../gui/image/qgifhandler.pri)
-INCLUDEPATH += ../../../gui/image
-SOURCES += $$PWD/main.cpp
-HEADERS += $$PWD/main.h
+SOURCES += main.cpp qgifhandler.cpp
+HEADERS += main.h qgifhandler_p.h
+
OTHER_FILES += gif.json
PLUGIN_TYPE = imageformats
diff --git a/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp
new file mode 100644
index 0000000000..476b456563
--- /dev/null
+++ b/src/plugins/imageformats/gif/qgifhandler.cpp
@@ -0,0 +1,1218 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** WARNING:
+** A separate license from Unisys may be required to use the gif
+** reader. See http://www.unisys.com/about__unisys/lzw/
+** for information from Unisys
+**
+****************************************************************************/
+
+#include "qgifhandler_p.h"
+
+#include <qimage.h>
+#include <qiodevice.h>
+#include <qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+#define Q_TRANSPARENT 0x00ffffff
+
+// avoid going through QImage::scanLine() which calls detach
+#define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl)
+
+
+/*
+ Incremental image decoder for GIF image format.
+
+ This subclass of QImageFormat decodes GIF format images,
+ including animated GIFs. Internally in
+*/
+
+class QGIFFormat {
+public:
+ QGIFFormat();
+ ~QGIFFormat();
+
+ int decode(QImage *image, const uchar* buffer, int length,
+ int *nextFrameDelay, int *loopCount);
+ static void scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount);
+
+ bool newFrame;
+ bool partialNewFrame;
+
+private:
+ void fillRect(QImage *image, int x, int y, int w, int h, QRgb col);
+ inline QRgb color(uchar index) const;
+
+ // GIF specific stuff
+ QRgb* globalcmap;
+ QRgb* localcmap;
+ QImage backingstore;
+ unsigned char hold[16];
+ bool gif89;
+ int count;
+ int ccount;
+ int expectcount;
+ enum State {
+ Header,
+ LogicalScreenDescriptor,
+ GlobalColorMap,
+ LocalColorMap,
+ Introducer,
+ ImageDescriptor,
+ TableImageLZWSize,
+ ImageDataBlockSize,
+ ImageDataBlock,
+ ExtensionLabel,
+ GraphicControlExtension,
+ ApplicationExtension,
+ NetscapeExtensionBlockSize,
+ NetscapeExtensionBlock,
+ SkipBlockSize,
+ SkipBlock,
+ Done,
+ Error
+ } state;
+ int gncols;
+ int lncols;
+ int ncols;
+ int lzwsize;
+ bool lcmap;
+ int swidth, sheight;
+ int width, height;
+ int left, top, right, bottom;
+ enum Disposal { NoDisposal, DoNotChange, RestoreBackground, RestoreImage };
+ Disposal disposal;
+ bool disposed;
+ int trans_index;
+ bool gcmap;
+ int bgcol;
+ int interlace;
+ int accum;
+ int bitcount;
+
+ enum { max_lzw_bits=12 }; // (poor-compiler's static const int)
+
+ int code_size, clear_code, end_code, max_code_size, max_code;
+ int firstcode, oldcode, incode;
+ short* table[2];
+ short* stack;
+ short *sp;
+ bool needfirst;
+ int x, y;
+ int frame;
+ bool out_of_bounds;
+ bool digress;
+ void nextY(unsigned char *bits, int bpl);
+ void disposePrevious(QImage *image);
+};
+
+/*!
+ Constructs a QGIFFormat.
+*/
+QGIFFormat::QGIFFormat()
+{
+ globalcmap = 0;
+ localcmap = 0;
+ lncols = 0;
+ gncols = 0;
+ disposal = NoDisposal;
+ out_of_bounds = false;
+ disposed = true;
+ frame = -1;
+ state = Header;
+ count = 0;
+ lcmap = false;
+ newFrame = false;
+ partialNewFrame = false;
+ table[0] = 0;
+ table[1] = 0;
+ stack = 0;
+}
+
+/*!
+ Destroys a QGIFFormat.
+*/
+QGIFFormat::~QGIFFormat()
+{
+ if (globalcmap) delete[] globalcmap;
+ if (localcmap) delete[] localcmap;
+ delete [] stack;
+}
+
+void QGIFFormat::disposePrevious(QImage *image)
+{
+ if (out_of_bounds) {
+ // flush anything that survived
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ }
+
+ // Handle disposal of previous image before processing next one
+
+ if (disposed) return;
+
+ int l = qMin(swidth-1,left);
+ int r = qMin(swidth-1,right);
+ int t = qMin(sheight-1,top);
+ int b = qMin(sheight-1,bottom);
+
+ switch (disposal) {
+ case NoDisposal:
+ break;
+ case DoNotChange:
+ break;
+ case RestoreBackground:
+ if (trans_index>=0) {
+ // Easy: we use the transparent color
+ fillRect(image, l, t, r-l+1, b-t+1, Q_TRANSPARENT);
+ } else if (bgcol>=0) {
+ // Easy: we use the bgcol given
+ fillRect(image, l, t, r-l+1, b-t+1, color(bgcol));
+ } else {
+ // Impossible: We don't know of a bgcol - use pixel 0
+ const QRgb *bits = reinterpret_cast<const QRgb *>(image->constBits());
+ fillRect(image, l, t, r-l+1, b-t+1, bits[0]);
+ }
+ // ### Changed: QRect(l, t, r-l+1, b-t+1)
+ break;
+ case RestoreImage: {
+ if (frame >= 0) {
+ for (int ln=t; ln<=b; ln++) {
+ memcpy(image->scanLine(ln)+l,
+ backingstore.constScanLine(ln-t),
+ (r-l+1)*sizeof(QRgb));
+ }
+ // ### Changed: QRect(l, t, r-l+1, b-t+1)
+ }
+ }
+ }
+ disposal = NoDisposal; // Until an extension says otherwise.
+
+ disposed = true;
+}
+
+/*!
+ This function decodes some data into image changes.
+
+ Returns the number of bytes consumed.
+*/
+int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
+ int *nextFrameDelay, int *loopCount)
+{
+ // We are required to state that
+ // "The Graphics Interchange Format(c) is the Copyright property of
+ // CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ // CompuServe Incorporated."
+
+ if (!stack) {
+ stack = new short[(1 << max_lzw_bits) * 4];
+ table[0] = &stack[(1 << max_lzw_bits) * 2];
+ table[1] = &stack[(1 << max_lzw_bits) * 3];
+ }
+
+ image->detach();
+ int bpl = image->bytesPerLine();
+ unsigned char *bits = image->bits();
+
+#define LM(l, m) (((m)<<8)|l)
+ digress = false;
+ const int initial = length;
+ while (!digress && length) {
+ length--;
+ unsigned char ch=*buffer++;
+ switch (state) {
+ case Header:
+ hold[count++]=ch;
+ if (count==6) {
+ // Header
+ gif89=(hold[3]!='8' || hold[4]!='7');
+ state=LogicalScreenDescriptor;
+ count=0;
+ }
+ break;
+ case LogicalScreenDescriptor:
+ hold[count++]=ch;
+ if (count==7) {
+ // Logical Screen Descriptor
+ swidth=LM(hold[0], hold[1]);
+ sheight=LM(hold[2], hold[3]);
+ gcmap=!!(hold[4]&0x80);
+ //UNUSED: bpchan=(((hold[4]&0x70)>>3)+1);
+ //UNUSED: gcmsortflag=!!(hold[4]&0x08);
+ gncols=2<<(hold[4]&0x7);
+ bgcol=(gcmap) ? hold[5] : -1;
+ //aspect=hold[6] ? double(hold[6]+15)/64.0 : 1.0;
+
+ trans_index = -1;
+ count=0;
+ ncols=gncols;
+ if (gcmap) {
+ ccount=0;
+ state=GlobalColorMap;
+ globalcmap = new QRgb[gncols+1]; // +1 for trans_index
+ globalcmap[gncols] = Q_TRANSPARENT;
+ } else {
+ state=Introducer;
+ }
+ }
+ break;
+ case GlobalColorMap: case LocalColorMap:
+ hold[count++]=ch;
+ if (count==3) {
+ QRgb rgb = qRgb(hold[0], hold[1], hold[2]);
+ if (state == LocalColorMap) {
+ if (ccount < lncols)
+ localcmap[ccount] = rgb;
+ } else {
+ globalcmap[ccount] = rgb;
+ }
+ if (++ccount >= ncols) {
+ if (state == LocalColorMap)
+ state=TableImageLZWSize;
+ else
+ state=Introducer;
+ }
+ count=0;
+ }
+ break;
+ case Introducer:
+ hold[count++]=ch;
+ switch (ch) {
+ case ',':
+ state=ImageDescriptor;
+ break;
+ case '!':
+ state=ExtensionLabel;
+ break;
+ case ';':
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ state=Done;
+ break;
+ default:
+ digress=true;
+ // Unexpected Introducer - ignore block
+ state=Error;
+ }
+ break;
+ case ImageDescriptor:
+ hold[count++]=ch;
+ if (count==10) {
+ int newleft=LM(hold[1], hold[2]);
+ int newtop=LM(hold[3], hold[4]);
+ int newwidth=LM(hold[5], hold[6]);
+ int newheight=LM(hold[7], hold[8]);
+
+ // disbelieve ridiculous logical screen sizes,
+ // unless the image frames are also large.
+ if (swidth/10 > qMax(newwidth,200))
+ swidth = -1;
+ if (sheight/10 > qMax(newheight,200))
+ sheight = -1;
+
+ if (swidth <= 0)
+ swidth = newleft + newwidth;
+ if (sheight <= 0)
+ sheight = newtop + newheight;
+
+ QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32;
+ if (image->isNull()) {
+ (*image) = QImage(swidth, sheight, format);
+ bpl = image->bytesPerLine();
+ bits = image->bits();
+ memset(bits, 0, image->byteCount());
+ }
+
+ // Check if the previous attempt to create the image failed. If it
+ // did then the image is broken and we should give up.
+ if (image->isNull()) {
+ state = Error;
+ return -1;
+ }
+
+ disposePrevious(image);
+ disposed = false;
+
+ left = newleft;
+ top = newtop;
+ width = newwidth;
+ height = newheight;
+
+ right=qMax(0, qMin(left+width, swidth)-1);
+ bottom=qMax(0, qMin(top+height, sheight)-1);
+ lcmap=!!(hold[9]&0x80);
+ interlace=!!(hold[9]&0x40);
+ //bool lcmsortflag=!!(hold[9]&0x20);
+ lncols=lcmap ? (2<<(hold[9]&0x7)) : 0;
+ if (lncols) {
+ if (localcmap)
+ delete [] localcmap;
+ localcmap = new QRgb[lncols+1];
+ localcmap[lncols] = Q_TRANSPARENT;
+ ncols = lncols;
+ } else {
+ ncols = gncols;
+ }
+ frame++;
+ if (frame == 0) {
+ if (left || top || width<swidth || height<sheight) {
+ // Not full-size image - erase with bg or transparent
+ if (trans_index >= 0) {
+ fillRect(image, 0, 0, swidth, sheight, color(trans_index));
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ } else if (bgcol>=0) {
+ fillRect(image, 0, 0, swidth, sheight, color(bgcol));
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ }
+ }
+ }
+
+ if (disposal == RestoreImage) {
+ int l = qMin(swidth-1,left);
+ int r = qMin(swidth-1,right);
+ int t = qMin(sheight-1,top);
+ int b = qMin(sheight-1,bottom);
+ int w = r-l+1;
+ int h = b-t+1;
+
+ if (backingstore.width() < w
+ || backingstore.height() < h) {
+ // We just use the backing store as a byte array
+ backingstore = QImage(qMax(backingstore.width(), w),
+ qMax(backingstore.height(), h),
+ QImage::Format_RGB32);
+ memset(bits, 0, image->byteCount());
+ }
+ const int dest_bpl = backingstore.bytesPerLine();
+ unsigned char *dest_data = backingstore.bits();
+ for (int ln=0; ln<h; ln++) {
+ memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln),
+ FAST_SCAN_LINE(bits, bpl, t+ln) + l, w*sizeof(QRgb));
+ }
+ }
+
+ count=0;
+ if (lcmap) {
+ ccount=0;
+ state=LocalColorMap;
+ } else {
+ state=TableImageLZWSize;
+ }
+ x = left;
+ y = top;
+ accum = 0;
+ bitcount = 0;
+ sp = stack;
+ firstcode = oldcode = 0;
+ needfirst = true;
+ out_of_bounds = left>=swidth || y>=sheight;
+ }
+ break;
+ case TableImageLZWSize: {
+ lzwsize=ch;
+ if (lzwsize > max_lzw_bits) {
+ state=Error;
+ } else {
+ code_size=lzwsize+1;
+ clear_code=1<<lzwsize;
+ end_code=clear_code+1;
+ max_code_size=2*clear_code;
+ max_code=clear_code+2;
+ int i;
+ for (i=0; i<clear_code; i++) {
+ table[0][i]=0;
+ table[1][i]=i;
+ }
+ state=ImageDataBlockSize;
+ }
+ count=0;
+ break;
+ } case ImageDataBlockSize:
+ expectcount=ch;
+ if (expectcount) {
+ state=ImageDataBlock;
+ } else {
+ state=Introducer;
+ digress = true;
+ newFrame = true;
+ }
+ break;
+ case ImageDataBlock:
+ count++;
+ accum|=(ch<<bitcount);
+ bitcount+=8;
+ while (bitcount>=code_size && state==ImageDataBlock) {
+ int code=accum&((1<<code_size)-1);
+ bitcount-=code_size;
+ accum>>=code_size;
+
+ if (code==clear_code) {
+ if (!needfirst) {
+ code_size=lzwsize+1;
+ max_code_size=2*clear_code;
+ max_code=clear_code+2;
+ }
+ needfirst=true;
+ } else if (code==end_code) {
+ bitcount = -32768;
+ // Left the block end arrive
+ } else {
+ if (needfirst) {
+ firstcode=oldcode=code;
+ if (!out_of_bounds && image->height() > y && ((frame == 0) || (firstcode != trans_index)))
+ ((QRgb*)FAST_SCAN_LINE(bits, bpl, y))[x] = color(firstcode);
+ x++;
+ if (x>=swidth) out_of_bounds = true;
+ needfirst=false;
+ if (x>=left+width) {
+ x=left;
+ out_of_bounds = left>=swidth || y>=sheight;
+ nextY(bits, bpl);
+ }
+ } else {
+ incode=code;
+ if (code>=max_code) {
+ *sp++=firstcode;
+ code=oldcode;
+ }
+ while (code>=clear_code+2) {
+ if (code >= max_code) {
+ state = Error;
+ return -1;
+ }
+ *sp++=table[1][code];
+ if (code==table[0][code]) {
+ state=Error;
+ return -1;
+ }
+ if (sp-stack>=(1<<(max_lzw_bits))*2) {
+ state=Error;
+ return -1;
+ }
+ code=table[0][code];
+ }
+ if (code < 0) {
+ state = Error;
+ return -1;
+ }
+
+ *sp++=firstcode=table[1][code];
+ code=max_code;
+ if (code<(1<<max_lzw_bits)) {
+ table[0][code]=oldcode;
+ table[1][code]=firstcode;
+ max_code++;
+ if ((max_code>=max_code_size)
+ && (max_code_size<(1<<max_lzw_bits)))
+ {
+ max_code_size*=2;
+ code_size++;
+ }
+ }
+ oldcode=incode;
+ const int h = image->height();
+ QRgb *line = 0;
+ if (!out_of_bounds && h > y)
+ line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
+ while (sp>stack) {
+ const uchar index = *(--sp);
+ if (!out_of_bounds && h > y && ((frame == 0) || (index != trans_index))) {
+ line[x] = color(index);
+ }
+ x++;
+ if (x>=swidth) out_of_bounds = true;
+ if (x>=left+width) {
+ x=left;
+ out_of_bounds = left>=swidth || y>=sheight;
+ nextY(bits, bpl);
+ if (!out_of_bounds && h > y)
+ line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
+ }
+ }
+ }
+ }
+ }
+ partialNewFrame = true;
+ if (count==expectcount) {
+ count=0;
+ state=ImageDataBlockSize;
+ }
+ break;
+ case ExtensionLabel:
+ switch (ch) {
+ case 0xf9:
+ state=GraphicControlExtension;
+ break;
+ case 0xff:
+ state=ApplicationExtension;
+ break;
+#if 0
+ case 0xfe:
+ state=CommentExtension;
+ break;
+ case 0x01:
+ break;
+#endif
+ default:
+ state=SkipBlockSize;
+ }
+ count=0;
+ break;
+ case ApplicationExtension:
+ if (count<11) hold[count]=ch;
+ count++;
+ if (count==hold[0]+1) {
+ if (qstrncmp((char*)(hold+1), "NETSCAPE", 8)==0) {
+ // Looping extension
+ state=NetscapeExtensionBlockSize;
+ } else {
+ state=SkipBlockSize;
+ }
+ count=0;
+ }
+ break;
+ case NetscapeExtensionBlockSize:
+ expectcount=ch;
+ count=0;
+ if (expectcount) state=NetscapeExtensionBlock;
+ else state=Introducer;
+ break;
+ case NetscapeExtensionBlock:
+ if (count<3) hold[count]=ch;
+ count++;
+ if (count==expectcount) {
+ *loopCount = hold[1]+hold[2]*256;
+ state=SkipBlockSize; // Ignore further blocks
+ }
+ break;
+ case GraphicControlExtension:
+ if (count<5) hold[count]=ch;
+ count++;
+ if (count==hold[0]+1) {
+ disposePrevious(image);
+ disposal=Disposal((hold[1]>>2)&0x7);
+ //UNUSED: waitforuser=!!((hold[1]>>1)&0x1);
+ int delay=count>3 ? LM(hold[2], hold[3]) : 1;
+ // IE and mozilla use a minimum delay of 10. With the minimum delay of 10
+ // we are compatible to them and avoid huge loads on the app and xserver.
+ *nextFrameDelay = (delay < 2 ? 10 : delay) * 10;
+
+ bool havetrans=hold[1]&0x1;
+ trans_index = havetrans ? hold[4] : -1;
+
+ count=0;
+ state=SkipBlockSize;
+ }
+ break;
+ case SkipBlockSize:
+ expectcount=ch;
+ count=0;
+ if (expectcount) state=SkipBlock;
+ else state=Introducer;
+ break;
+ case SkipBlock:
+ count++;
+ if (count==expectcount) state=SkipBlockSize;
+ break;
+ case Done:
+ digress=true;
+ /* Netscape ignores the junk, so we do too.
+ length++; // Unget
+ state=Error; // More calls to this is an error
+ */
+ break;
+ case Error:
+ return -1; // Called again after done.
+ }
+ }
+ return initial-length;
+}
+
+/*!
+ Scans through the data stream defined by \a device and returns the image
+ sizes found in the stream in the \a imageSizes vector.
+*/
+void QGIFFormat::scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount)
+{
+ if (!device)
+ return;
+
+ qint64 oldPos = device->pos();
+ if (device->isSequential() || !device->seek(0))
+ return;
+
+ int colorCount = 0;
+ int localColorCount = 0;
+ int globalColorCount = 0;
+ int colorReadCount = 0;
+ bool localColormap = false;
+ bool globalColormap = false;
+ int count = 0;
+ int blockSize = 0;
+ int imageWidth = 0;
+ int imageHeight = 0;
+ bool done = false;
+ uchar hold[16];
+ State state = Header;
+
+ const int readBufferSize = 40960; // 40k read buffer
+ QByteArray readBuffer(device->read(readBufferSize));
+
+ if (readBuffer.isEmpty()) {
+ device->seek(oldPos);
+ return;
+ }
+
+ // This is a specialized version of the state machine from decode(),
+ // which doesn't do any image decoding or mallocing, and has an
+ // optimized way of skipping SkipBlocks, ImageDataBlocks and
+ // Global/LocalColorMaps.
+
+ while (!readBuffer.isEmpty()) {
+ int length = readBuffer.size();
+ const uchar *buffer = (const uchar *) readBuffer.constData();
+ while (!done && length) {
+ length--;
+ uchar ch = *buffer++;
+ switch (state) {
+ case Header:
+ hold[count++] = ch;
+ if (count == 6) {
+ state = LogicalScreenDescriptor;
+ count = 0;
+ }
+ break;
+ case LogicalScreenDescriptor:
+ hold[count++] = ch;
+ if (count == 7) {
+ imageWidth = LM(hold[0], hold[1]);
+ imageHeight = LM(hold[2], hold[3]);
+ globalColormap = !!(hold[4] & 0x80);
+ globalColorCount = 2 << (hold[4] & 0x7);
+ count = 0;
+ colorCount = globalColorCount;
+ if (globalColormap) {
+ int colorTableSize = 3 * globalColorCount;
+ if (length >= colorTableSize) {
+ // skip the global color table in one go
+ length -= colorTableSize;
+ buffer += colorTableSize;
+ state = Introducer;
+ } else {
+ colorReadCount = 0;
+ state = GlobalColorMap;
+ }
+ } else {
+ state=Introducer;
+ }
+ }
+ break;
+ case GlobalColorMap:
+ case LocalColorMap:
+ hold[count++] = ch;
+ if (count == 3) {
+ if (++colorReadCount >= colorCount) {
+ if (state == LocalColorMap)
+ state = TableImageLZWSize;
+ else
+ state = Introducer;
+ }
+ count = 0;
+ }
+ break;
+ case Introducer:
+ hold[count++] = ch;
+ switch (ch) {
+ case 0x2c:
+ state = ImageDescriptor;
+ break;
+ case 0x21:
+ state = ExtensionLabel;
+ break;
+ case 0x3b:
+ state = Done;
+ break;
+ default:
+ done = true;
+ state = Error;
+ }
+ break;
+ case ImageDescriptor:
+ hold[count++] = ch;
+ if (count == 10) {
+ int newLeft = LM(hold[1], hold[2]);
+ int newTop = LM(hold[3], hold[4]);
+ int newWidth = LM(hold[5], hold[6]);
+ int newHeight = LM(hold[7], hold[8]);
+
+ if (imageWidth/10 > qMax(newWidth,200))
+ imageWidth = -1;
+ if (imageHeight/10 > qMax(newHeight,200))
+ imageHeight = -1;
+
+ if (imageWidth <= 0)
+ imageWidth = newLeft + newWidth;
+ if (imageHeight <= 0)
+ imageHeight = newTop + newHeight;
+
+ *imageSizes << QSize(imageWidth, imageHeight);
+
+ localColormap = !!(hold[9] & 0x80);
+ localColorCount = localColormap ? (2 << (hold[9] & 0x7)) : 0;
+ if (localColorCount)
+ colorCount = localColorCount;
+ else
+ colorCount = globalColorCount;
+
+ count = 0;
+ if (localColormap) {
+ int colorTableSize = 3 * localColorCount;
+ if (length >= colorTableSize) {
+ // skip the local color table in one go
+ length -= colorTableSize;
+ buffer += colorTableSize;
+ state = TableImageLZWSize;
+ } else {
+ colorReadCount = 0;
+ state = LocalColorMap;
+ }
+ } else {
+ state = TableImageLZWSize;
+ }
+ }
+ break;
+ case TableImageLZWSize:
+ if (ch > max_lzw_bits)
+ state = Error;
+ else
+ state = ImageDataBlockSize;
+ count = 0;
+ break;
+ case ImageDataBlockSize:
+ blockSize = ch;
+ if (blockSize) {
+ if (length >= blockSize) {
+ // we can skip the block in one go
+ length -= blockSize;
+ buffer += blockSize;
+ count = 0;
+ } else {
+ state = ImageDataBlock;
+ }
+ } else {
+ state = Introducer;
+ }
+ break;
+ case ImageDataBlock:
+ ++count;
+ if (count == blockSize) {
+ count = 0;
+ state = ImageDataBlockSize;
+ }
+ break;
+ case ExtensionLabel:
+ switch (ch) {
+ case 0xf9:
+ state = GraphicControlExtension;
+ break;
+ case 0xff:
+ state = ApplicationExtension;
+ break;
+ default:
+ state = SkipBlockSize;
+ }
+ count = 0;
+ break;
+ case ApplicationExtension:
+ if (count < 11)
+ hold[count] = ch;
+ ++count;
+ if (count == hold[0] + 1) {
+ if (qstrncmp((char*)(hold+1), "NETSCAPE", 8) == 0)
+ state=NetscapeExtensionBlockSize;
+ else
+ state=SkipBlockSize;
+ count = 0;
+ }
+ break;
+ case GraphicControlExtension:
+ if (count < 5)
+ hold[count] = ch;
+ ++count;
+ if (count == hold[0] + 1) {
+ count = 0;
+ state = SkipBlockSize;
+ }
+ break;
+ case NetscapeExtensionBlockSize:
+ blockSize = ch;
+ count = 0;
+ if (blockSize)
+ state = NetscapeExtensionBlock;
+ else
+ state = Introducer;
+ break;
+ case NetscapeExtensionBlock:
+ if (count < 3)
+ hold[count] = ch;
+ count++;
+ if (count == blockSize) {
+ *loopCount = LM(hold[1], hold[2]);
+ state = SkipBlockSize;
+ }
+ break;
+ case SkipBlockSize:
+ blockSize = ch;
+ count = 0;
+ if (blockSize) {
+ if (length >= blockSize) {
+ // we can skip the block in one go
+ length -= blockSize;
+ buffer += blockSize;
+ } else {
+ state = SkipBlock;
+ }
+ } else {
+ state = Introducer;
+ }
+ break;
+ case SkipBlock:
+ ++count;
+ if (count == blockSize)
+ state = SkipBlockSize;
+ break;
+ case Done:
+ done = true;
+ break;
+ case Error:
+ device->seek(oldPos);
+ return;
+ }
+ }
+ readBuffer = device->read(readBufferSize);
+ }
+ device->seek(oldPos);
+ return;
+}
+
+void QGIFFormat::fillRect(QImage *image, int col, int row, int w, int h, QRgb color)
+{
+ if (w>0) {
+ for (int j=0; j<h; j++) {
+ QRgb *line = (QRgb*)image->scanLine(j+row);
+ for (int i=0; i<w; i++)
+ *(line+col+i) = color;
+ }
+ }
+}
+
+void QGIFFormat::nextY(unsigned char *bits, int bpl)
+{
+ if (out_of_bounds)
+ return;
+ int my;
+ switch (interlace) {
+ case 0: // Non-interlaced
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, 1);
+ // }
+ y++;
+ break;
+ case 1: {
+ int i;
+ my = qMin(7, bottom-y);
+ // Don't dup with transparency
+ if (trans_index < 0) {
+ for (i=1; i<=my; i++) {
+ memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
+ (right-left+1)*sizeof(QRgb));
+ }
+ }
+
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, my + 1);
+ // }
+// if (!out_of_bounds)
+// qDebug("consumer->changed(QRect(%d, %d, %d, %d))", left, y, right-left+1, my+1);
+ y+=8;
+ if (y>bottom) {
+ interlace++; y=top+4;
+ if (y > bottom) { // for really broken GIFs with bottom < 5
+ interlace=2;
+ y = top + 2;
+ if (y > bottom) { // for really broken GIF with bottom < 3
+ interlace = 0;
+ y = top + 1;
+ }
+ }
+ }
+ } break;
+ case 2: {
+ int i;
+ my = qMin(3, bottom-y);
+ // Don't dup with transparency
+ if (trans_index < 0) {
+ for (i=1; i<=my; i++) {
+ memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
+ (right-left+1)*sizeof(QRgb));
+ }
+ }
+
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, my + 1);
+ // }
+ y+=8;
+ if (y>bottom) {
+ interlace++; y=top+2;
+ // handle broken GIF with bottom < 3
+ if (y > bottom) {
+ interlace = 3;
+ y = top + 1;
+ }
+ }
+ } break;
+ case 3: {
+ int i;
+ my = qMin(1, bottom-y);
+ // Don't dup with transparency
+ if (trans_index < 0) {
+ for (i=1; i<=my; i++) {
+ memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
+ (right-left+1)*sizeof(QRgb));
+ }
+ }
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, my + 1);
+ // }
+ y+=4;
+ if (y>bottom) { interlace++; y=top+1; }
+ } break;
+ case 4:
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, 1);
+ // }
+ y+=2;
+ }
+
+ // Consume bogus extra lines
+ if (y >= sheight) out_of_bounds=true; //y=bottom;
+}
+
+inline QRgb QGIFFormat::color(uchar index) const
+{
+ if (index > ncols)
+ return Q_TRANSPARENT;
+
+ QRgb *map = lcmap ? localcmap : globalcmap;
+ QRgb col = map ? map[index] : 0;
+ return index == trans_index ? col & Q_TRANSPARENT : col;
+}
+
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+
+QGifHandler::QGifHandler()
+{
+ gifFormat = new QGIFFormat;
+ nextDelay = 100;
+ loopCnt = -1;
+ frameNumber = -1;
+ scanIsCached = false;
+}
+
+QGifHandler::~QGifHandler()
+{
+ delete gifFormat;
+}
+
+// Does partial decode if necessary, just to see if an image is coming
+
+bool QGifHandler::imageIsComing() const
+{
+ const int GifChunkSize = 4096;
+
+ while (!gifFormat->partialNewFrame) {
+ if (buffer.isEmpty()) {
+ buffer += device()->read(GifChunkSize);
+ if (buffer.isEmpty())
+ break;
+ }
+
+ int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
+ &nextDelay, &loopCnt);
+ if (decoded == -1)
+ break;
+ buffer.remove(0, decoded);
+ }
+ return gifFormat->partialNewFrame;
+}
+
+bool QGifHandler::canRead() const
+{
+ if (canRead(device()) || imageIsComing()) {
+ setFormat("gif");
+ return true;
+ }
+
+ return false;
+}
+
+bool QGifHandler::canRead(QIODevice *device)
+{
+ if (!device) {
+ qWarning("QGifHandler::canRead() called with no device");
+ return false;
+ }
+
+ char head[6];
+ if (device->peek(head, sizeof(head)) == sizeof(head))
+ return qstrncmp(head, "GIF87a", 6) == 0
+ || qstrncmp(head, "GIF89a", 6) == 0;
+ return false;
+}
+
+bool QGifHandler::read(QImage *image)
+{
+ const int GifChunkSize = 4096;
+
+ while (!gifFormat->newFrame) {
+ if (buffer.isEmpty()) {
+ buffer += device()->read(GifChunkSize);
+ if (buffer.isEmpty())
+ break;
+ }
+
+ int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
+ &nextDelay, &loopCnt);
+ if (decoded == -1)
+ break;
+ buffer.remove(0, decoded);
+ }
+ if (gifFormat->newFrame || (gifFormat->partialNewFrame && device()->atEnd())) {
+ *image = lastImage;
+ ++frameNumber;
+ gifFormat->newFrame = false;
+ gifFormat->partialNewFrame = false;
+ return true;
+ }
+
+ return false;
+}
+
+bool QGifHandler::write(const QImage &image)
+{
+ Q_UNUSED(image);
+ return false;
+}
+
+bool QGifHandler::supportsOption(ImageOption option) const
+{
+ if (!device() || device()->isSequential())
+ return option == Animation;
+ else
+ return option == Size
+ || option == Animation;
+}
+
+QVariant QGifHandler::option(ImageOption option) const
+{
+ if (option == Size) {
+ if (!scanIsCached) {
+ QGIFFormat::scan(device(), &imageSizes, &loopCnt);
+ scanIsCached = true;
+ }
+ // before the first frame is read, or we have an empty data stream
+ if (frameNumber == -1)
+ return (imageSizes.count() > 0) ? QVariant(imageSizes.at(0)) : QVariant();
+ // after the last frame has been read, the next size is undefined
+ if (frameNumber >= imageSizes.count() - 1)
+ return QVariant();
+ // and the last case: the size of the next frame
+ return imageSizes.at(frameNumber + 1);
+ } else if (option == Animation) {
+ return true;
+ }
+ return QVariant();
+}
+
+void QGifHandler::setOption(ImageOption option, const QVariant &value)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(value);
+}
+
+int QGifHandler::nextImageDelay() const
+{
+ return nextDelay;
+}
+
+int QGifHandler::imageCount() const
+{
+ if (!scanIsCached) {
+ QGIFFormat::scan(device(), &imageSizes, &loopCnt);
+ scanIsCached = true;
+ }
+ return imageSizes.count();
+}
+
+int QGifHandler::loopCount() const
+{
+ if (!scanIsCached) {
+ QGIFFormat::scan(device(), &imageSizes, &loopCnt);
+ scanIsCached = true;
+ }
+
+ if (loopCnt == 0)
+ return -1;
+ else if (loopCnt == -1)
+ return 0;
+ else
+ return loopCnt;
+}
+
+int QGifHandler::currentImageNumber() const
+{
+ return frameNumber;
+}
+
+QByteArray QGifHandler::name() const
+{
+ return "gif";
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/gif/qgifhandler_p.h b/src/plugins/imageformats/gif/qgifhandler_p.h
new file mode 100644
index 0000000000..bc3debe83c
--- /dev/null
+++ b/src/plugins/imageformats/gif/qgifhandler_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** WARNING:
+** A separate license from Unisys may be required to use the gif
+** reader. See http://www.unisys.com/about__unisys/lzw/
+** for information from Unisys
+**
+****************************************************************************/
+
+#ifndef QGIFHANDLER_P_H
+#define QGIFHANDLER_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 <QtGui/qimageiohandler.h>
+#include <QtGui/qimage.h>
+#include <QtCore/qbytearray.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGIFFormat;
+class QGifHandler : public QImageIOHandler
+{
+public:
+ QGifHandler();
+ ~QGifHandler();
+
+ bool canRead() const Q_DECL_OVERRIDE;
+ bool read(QImage *image) Q_DECL_OVERRIDE;
+ bool write(const QImage &image) Q_DECL_OVERRIDE;
+
+ QByteArray name() const Q_DECL_OVERRIDE;
+
+ static bool canRead(QIODevice *device);
+
+ QVariant option(ImageOption option) const Q_DECL_OVERRIDE;
+ void setOption(ImageOption option, const QVariant &value) Q_DECL_OVERRIDE;
+ bool supportsOption(ImageOption option) const Q_DECL_OVERRIDE;
+
+ int imageCount() const Q_DECL_OVERRIDE;
+ int loopCount() const Q_DECL_OVERRIDE;
+ int nextImageDelay() const Q_DECL_OVERRIDE;
+ int currentImageNumber() const Q_DECL_OVERRIDE;
+
+private:
+ bool imageIsComing() const;
+ QGIFFormat *gifFormat;
+ QString fileName;
+ mutable QByteArray buffer;
+ mutable QImage lastImage;
+
+ mutable int nextDelay;
+ mutable int loopCnt;
+ int frameNumber;
+ mutable QVector<QSize> imageSizes;
+ mutable bool scanIsCached;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGIFHANDLER_P_H
diff --git a/src/plugins/imageformats/ico/ico.pro b/src/plugins/imageformats/ico/ico.pro
index 60afdaed70..7ca1f18cb1 100644
--- a/src/plugins/imageformats/ico/ico.pro
+++ b/src/plugins/imageformats/ico/ico.pro
@@ -1,10 +1,7 @@
TARGET = qico
-QTDIR_build:REQUIRES = "!contains(QT_CONFIG, no-ico)"
-
-HEADERS += qicohandler.h main.h
-SOURCES += main.cpp \
- qicohandler.cpp
+HEADERS += main.h qicohandler.h
+SOURCES += main.cpp qicohandler.cpp
OTHER_FILES += ico.json
PLUGIN_TYPE = imageformats
diff --git a/src/plugins/imageformats/imageformats.pro b/src/plugins/imageformats/imageformats.pro
index 2b05f2feec..3de77c056d 100644
--- a/src/plugins/imageformats/imageformats.pro
+++ b/src/plugins/imageformats/imageformats.pro
@@ -1,5 +1,5 @@
TEMPLATE = subdirs
-!contains(QT_CONFIG, no-jpeg):!contains(QT_CONFIG, jpeg):SUBDIRS += jpeg
-!contains(QT_CONFIG, no-gif):!contains(QT_CONFIG, gif):SUBDIRS += gif
!contains(QT_CONFIG, no-ico):SUBDIRS += ico
+contains(QT_CONFIG, jpeg): SUBDIRS += jpeg
+contains(QT_CONFIG, gif): SUBDIRS += gif
diff --git a/src/plugins/imageformats/jpeg/jpeg.pro b/src/plugins/imageformats/jpeg/jpeg.pro
index 526556179c..9181abb465 100644
--- a/src/plugins/imageformats/jpeg/jpeg.pro
+++ b/src/plugins/imageformats/jpeg/jpeg.pro
@@ -2,12 +2,18 @@ TARGET = qjpeg
QT += core-private
-QTDIR_build:REQUIRES = "!contains(QT_CONFIG, no-jpeg)"
+SOURCES += main.cpp qjpeghandler.cpp
+HEADERS += main.h qjpeghandler_p.h
+
+contains(QT_CONFIG, system-jpeg) {
+ msvc: \
+ LIBS += libjpeg.lib
+ else: \
+ LIBS += -ljpeg
+} else {
+ include($$PWD/../../../3rdparty/libjpeg.pri)
+}
-include(../../../gui/image/qjpeghandler.pri)
-INCLUDEPATH += ../../../gui/image
-SOURCES += main.cpp
-HEADERS += main.h
OTHER_FILES += jpeg.json
PLUGIN_TYPE = imageformats
diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
new file mode 100644
index 0000000000..52e8b39f11
--- /dev/null
+++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
@@ -0,0 +1,1144 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qjpeghandler_p.h"
+
+#include <qimage.h>
+#include <qvariant.h>
+#include <qvector.h>
+#include <qbuffer.h>
+#include <qmath.h>
+#include <private/qsimd_p.h>
+
+#include <stdio.h> // jpeglib needs this to be pre-included
+#include <setjmp.h>
+
+#ifdef FAR
+#undef FAR
+#endif
+
+// including jpeglib.h seems to be a little messy
+extern "C" {
+// mingw includes rpcndr.h but does not define boolean
+#if defined(Q_OS_WIN) && defined(Q_CC_GNU)
+# if defined(__RPCNDR_H__) && !defined(boolean)
+ typedef unsigned char boolean;
+# define HAVE_BOOLEAN
+# endif
+#endif
+
+#define XMD_H // shut JPEGlib up
+#if defined(Q_OS_UNIXWARE)
+# define HAVE_BOOLEAN // libjpeg under Unixware seems to need this
+#endif
+#include <jpeglib.h>
+#ifdef const
+# undef const // remove crazy C hackery in jconfig.h
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+QT_WARNING_DISABLE_GCC("-Wclobbered")
+
+Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32(quint32 *dst, const uchar *src, int len);
+typedef void (QT_FASTCALL *Rgb888ToRgb32Converter)(quint32 *dst, const uchar *src, int len);
+
+struct my_error_mgr : public jpeg_error_mgr {
+ jmp_buf setjmp_buffer;
+};
+
+extern "C" {
+
+static void my_error_exit (j_common_ptr cinfo)
+{
+ my_error_mgr* myerr = (my_error_mgr*) cinfo->err;
+ char buffer[JMSG_LENGTH_MAX];
+ (*cinfo->err->format_message)(cinfo, buffer);
+ qWarning("%s", buffer);
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+static void my_output_message(j_common_ptr cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+ (*cinfo->err->format_message)(cinfo, buffer);
+ qWarning("%s", buffer);
+}
+
+}
+
+
+static const int max_buf = 4096;
+
+struct my_jpeg_source_mgr : public jpeg_source_mgr {
+ // Nothing dynamic - cannot rely on destruction over longjump
+ QIODevice *device;
+ JOCTET buffer[max_buf];
+ const QBuffer *memDevice;
+
+public:
+ my_jpeg_source_mgr(QIODevice *device);
+};
+
+extern "C" {
+
+static void qt_init_source(j_decompress_ptr)
+{
+}
+
+static boolean qt_fill_input_buffer(j_decompress_ptr cinfo)
+{
+ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
+ qint64 num_read = 0;
+ if (src->memDevice) {
+ src->next_input_byte = (const JOCTET *)(src->memDevice->data().constData() + src->memDevice->pos());
+ num_read = src->memDevice->data().size() - src->memDevice->pos();
+ src->device->seek(src->memDevice->data().size());
+ } else {
+ src->next_input_byte = src->buffer;
+ num_read = src->device->read((char*)src->buffer, max_buf);
+ }
+ if (num_read <= 0) {
+ // Insert a fake EOI marker - as per jpeglib recommendation
+ src->next_input_byte = src->buffer;
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ src->bytes_in_buffer = 2;
+ } else {
+ src->bytes_in_buffer = num_read;
+ }
+ return TRUE;
+}
+
+static void qt_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
+
+ // `dumb' implementation from jpeglib
+
+ /* Just a dumb implementation for now. Could use fseek() except
+ * it doesn't work on pipes. Not clear that being smart is worth
+ * any trouble anyway --- large skips are infrequent.
+ */
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->bytes_in_buffer) { // Should not happen in case of memDevice
+ num_bytes -= (long) src->bytes_in_buffer;
+ (void) qt_fill_input_buffer(cinfo);
+ /* note we assume that qt_fill_input_buffer will never return false,
+ * so suspension need not be handled.
+ */
+ }
+ src->next_input_byte += (size_t) num_bytes;
+ src->bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+static void qt_term_source(j_decompress_ptr cinfo)
+{
+ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
+ if (!src->device->isSequential())
+ src->device->seek(src->device->pos() - src->bytes_in_buffer);
+}
+
+}
+
+inline my_jpeg_source_mgr::my_jpeg_source_mgr(QIODevice *device)
+{
+ jpeg_source_mgr::init_source = qt_init_source;
+ jpeg_source_mgr::fill_input_buffer = qt_fill_input_buffer;
+ jpeg_source_mgr::skip_input_data = qt_skip_input_data;
+ jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart;
+ jpeg_source_mgr::term_source = qt_term_source;
+ this->device = device;
+ memDevice = qobject_cast<QBuffer *>(device);
+ bytes_in_buffer = 0;
+ next_input_byte = buffer;
+}
+
+
+inline static bool read_jpeg_size(int &w, int &h, j_decompress_ptr cinfo)
+{
+ (void) jpeg_calc_output_dimensions(cinfo);
+
+ w = cinfo->output_width;
+ h = cinfo->output_height;
+ return true;
+}
+
+#define HIGH_QUALITY_THRESHOLD 50
+
+inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cinfo)
+{
+
+ bool result = true;
+ switch (cinfo->output_components) {
+ case 1:
+ format = QImage::Format_Grayscale8;
+ break;
+ case 3:
+ case 4:
+ format = QImage::Format_RGB32;
+ break;
+ default:
+ result = false;
+ break;
+ }
+ cinfo->output_scanline = cinfo->output_height;
+ return result;
+}
+
+static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
+ const QSize& size)
+{
+ QImage::Format format;
+ switch (info->output_components) {
+ case 1:
+ format = QImage::Format_Grayscale8;
+ break;
+ case 3:
+ case 4:
+ format = QImage::Format_RGB32;
+ break;
+ default:
+ return false; // unsupported format
+ }
+
+ if (dest->size() != size || dest->format() != format)
+ *dest = QImage(size, format);
+
+ return !dest->isNull();
+}
+
+static bool read_jpeg_image(QImage *outImage,
+ QSize scaledSize, QRect scaledClipRect,
+ QRect clipRect, volatile int inQuality,
+ Rgb888ToRgb32Converter converter,
+ j_decompress_ptr info, struct my_error_mgr* err )
+{
+ if (!setjmp(err->setjmp_buffer)) {
+ // -1 means default quality.
+ int quality = inQuality;
+ if (quality < 0)
+ quality = 75;
+
+ // If possible, merge the scaledClipRect into either scaledSize
+ // or clipRect to avoid doing a separate scaled clipping pass.
+ // Best results are achieved by clipping before scaling, not after.
+ if (!scaledClipRect.isEmpty()) {
+ if (scaledSize.isEmpty() && clipRect.isEmpty()) {
+ // No clipping or scaling before final clip.
+ clipRect = scaledClipRect;
+ scaledClipRect = QRect();
+ } else if (scaledSize.isEmpty()) {
+ // Clipping, but no scaling: combine the clip regions.
+ scaledClipRect.translate(clipRect.topLeft());
+ clipRect = scaledClipRect.intersected(clipRect);
+ scaledClipRect = QRect();
+ } else if (clipRect.isEmpty()) {
+ // No clipping, but scaling: if we can map back to an
+ // integer pixel boundary, then clip before scaling.
+ if ((info->image_width % scaledSize.width()) == 0 &&
+ (info->image_height % scaledSize.height()) == 0) {
+ int x = scaledClipRect.x() * info->image_width /
+ scaledSize.width();
+ int y = scaledClipRect.y() * info->image_height /
+ scaledSize.height();
+ int width = (scaledClipRect.right() + 1) *
+ info->image_width / scaledSize.width() - x;
+ int height = (scaledClipRect.bottom() + 1) *
+ info->image_height / scaledSize.height() - y;
+ clipRect = QRect(x, y, width, height);
+ scaledSize = scaledClipRect.size();
+ scaledClipRect = QRect();
+ }
+ } else {
+ // Clipping and scaling: too difficult to figure out,
+ // and not a likely use case, so do it the long way.
+ }
+ }
+
+ // Determine the scale factor to pass to libjpeg for quick downscaling.
+ if (!scaledSize.isEmpty() && info->image_width && info->image_height) {
+ if (clipRect.isEmpty()) {
+ double f = qMin(double(info->image_width) / scaledSize.width(),
+ double(info->image_height) / scaledSize.height());
+
+ // libjpeg supports M/8 scaling with M=[1,16]. All downscaling factors
+ // are a speed improvement, but upscaling during decode is slower.
+ info->scale_num = qBound(1, qCeil(8/f), 8);
+ info->scale_denom = 8;
+ } else {
+ info->scale_denom = qMin(clipRect.width() / scaledSize.width(),
+ clipRect.height() / scaledSize.height());
+
+ // Only scale by powers of two when clipping so we can
+ // keep the exact pixel boundaries
+ if (info->scale_denom < 2)
+ info->scale_denom = 1;
+ else if (info->scale_denom < 4)
+ info->scale_denom = 2;
+ else if (info->scale_denom < 8)
+ info->scale_denom = 4;
+ else
+ info->scale_denom = 8;
+ info->scale_num = 1;
+
+ // Correct the scale factor so that we clip accurately.
+ // It is recommended that the clip rectangle be aligned
+ // on an 8-pixel boundary for best performance.
+ while (info->scale_denom > 1 &&
+ ((clipRect.x() % info->scale_denom) != 0 ||
+ (clipRect.y() % info->scale_denom) != 0 ||
+ (clipRect.width() % info->scale_denom) != 0 ||
+ (clipRect.height() % info->scale_denom) != 0)) {
+ info->scale_denom /= 2;
+ }
+ }
+ }
+
+ // If high quality not required, use fast decompression
+ if( quality < HIGH_QUALITY_THRESHOLD ) {
+ info->dct_method = JDCT_IFAST;
+ info->do_fancy_upsampling = FALSE;
+ }
+
+ (void) jpeg_calc_output_dimensions(info);
+
+ // Determine the clip region to extract.
+ QRect imageRect(0, 0, info->output_width, info->output_height);
+ QRect clip;
+ if (clipRect.isEmpty()) {
+ clip = imageRect;
+ } else if (info->scale_denom == info->scale_num) {
+ clip = clipRect.intersected(imageRect);
+ } else {
+ // The scale factor was corrected above to ensure that
+ // we don't miss pixels when we scale the clip rectangle.
+ clip = QRect(clipRect.x() / int(info->scale_denom),
+ clipRect.y() / int(info->scale_denom),
+ clipRect.width() / int(info->scale_denom),
+ clipRect.height() / int(info->scale_denom));
+ clip = clip.intersected(imageRect);
+ }
+
+ // Allocate memory for the clipped QImage.
+ if (!ensureValidImage(outImage, info, clip.size()))
+ longjmp(err->setjmp_buffer, 1);
+
+ // Avoid memcpy() overhead if grayscale with no clipping.
+ bool quickGray = (info->output_components == 1 &&
+ clip == imageRect);
+ if (!quickGray) {
+ // Ask the jpeg library to allocate a temporary row.
+ // The library will automatically delete it for us later.
+ // The libjpeg docs say we should do this before calling
+ // jpeg_start_decompress(). We can't use "new" here
+ // because we are inside the setjmp() block and an error
+ // in the jpeg input stream would cause a memory leak.
+ JSAMPARRAY rows = (info->mem->alloc_sarray)
+ ((j_common_ptr)info, JPOOL_IMAGE,
+ info->output_width * info->output_components, 1);
+
+ (void) jpeg_start_decompress(info);
+
+ while (info->output_scanline < info->output_height) {
+ int y = int(info->output_scanline) - clip.y();
+ if (y >= clip.height())
+ break; // We've read the entire clip region, so abort.
+
+ (void) jpeg_read_scanlines(info, rows, 1);
+
+ if (y < 0)
+ continue; // Haven't reached the starting line yet.
+
+ if (info->output_components == 3) {
+ uchar *in = rows[0] + clip.x() * 3;
+ QRgb *out = (QRgb*)outImage->scanLine(y);
+ converter(out, in, clip.width());
+ } else if (info->out_color_space == JCS_CMYK) {
+ // Convert CMYK->RGB.
+ uchar *in = rows[0] + clip.x() * 4;
+ QRgb *out = (QRgb*)outImage->scanLine(y);
+ for (int i = 0; i < clip.width(); ++i) {
+ int k = in[3];
+ *out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
+ k * in[2] / 255);
+ in += 4;
+ }
+ } else if (info->output_components == 1) {
+ // Grayscale.
+ memcpy(outImage->scanLine(y),
+ rows[0] + clip.x(), clip.width());
+ }
+ }
+ } else {
+ // Load unclipped grayscale data directly into the QImage.
+ (void) jpeg_start_decompress(info);
+ while (info->output_scanline < info->output_height) {
+ uchar *row = outImage->scanLine(info->output_scanline);
+ (void) jpeg_read_scanlines(info, &row, 1);
+ }
+ }
+
+ if (info->output_scanline == info->output_height)
+ (void) jpeg_finish_decompress(info);
+
+ if (info->density_unit == 1) {
+ outImage->setDotsPerMeterX(int(100. * info->X_density / 2.54));
+ outImage->setDotsPerMeterY(int(100. * info->Y_density / 2.54));
+ } else if (info->density_unit == 2) {
+ outImage->setDotsPerMeterX(int(100. * info->X_density));
+ outImage->setDotsPerMeterY(int(100. * info->Y_density));
+ }
+
+ if (scaledSize.isValid() && scaledSize != clip.size()) {
+ *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, quality >= HIGH_QUALITY_THRESHOLD ? Qt::SmoothTransformation : Qt::FastTransformation);
+ }
+
+ if (!scaledClipRect.isEmpty())
+ *outImage = outImage->copy(scaledClipRect);
+ return !outImage->isNull();
+ }
+ else
+ return false;
+}
+
+struct my_jpeg_destination_mgr : public jpeg_destination_mgr {
+ // Nothing dynamic - cannot rely on destruction over longjump
+ QIODevice *device;
+ JOCTET buffer[max_buf];
+
+public:
+ my_jpeg_destination_mgr(QIODevice *);
+};
+
+
+extern "C" {
+
+static void qt_init_destination(j_compress_ptr)
+{
+}
+
+static boolean qt_empty_output_buffer(j_compress_ptr cinfo)
+{
+ my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
+
+ int written = dest->device->write((char*)dest->buffer, max_buf);
+ if (written == -1)
+ (*cinfo->err->error_exit)((j_common_ptr)cinfo);
+
+ dest->next_output_byte = dest->buffer;
+ dest->free_in_buffer = max_buf;
+
+ return TRUE;
+}
+
+static void qt_term_destination(j_compress_ptr cinfo)
+{
+ my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
+ qint64 n = max_buf - dest->free_in_buffer;
+
+ qint64 written = dest->device->write((char*)dest->buffer, n);
+ if (written == -1)
+ (*cinfo->err->error_exit)((j_common_ptr)cinfo);
+}
+
+}
+
+inline my_jpeg_destination_mgr::my_jpeg_destination_mgr(QIODevice *device)
+{
+ jpeg_destination_mgr::init_destination = qt_init_destination;
+ jpeg_destination_mgr::empty_output_buffer = qt_empty_output_buffer;
+ jpeg_destination_mgr::term_destination = qt_term_destination;
+ this->device = device;
+ next_output_byte = buffer;
+ free_in_buffer = max_buf;
+}
+
+
+static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QString &description)
+{
+ QMap<QString, QString> text;
+ foreach (const QString &key, image.textKeys()) {
+ if (!key.isEmpty())
+ text.insert(key, image.text(key));
+ }
+ foreach (const QString &pair, description.split(QLatin1String("\n\n"))) {
+ int index = pair.indexOf(QLatin1Char(':'));
+ if (index >= 0 && pair.indexOf(QLatin1Char(' ')) < index) {
+ QString s = pair.simplified();
+ if (!s.isEmpty())
+ text.insert(QLatin1String("Description"), s);
+ } else {
+ QString key = pair.left(index);
+ if (!key.simplified().isEmpty())
+ text.insert(key, pair.mid(index + 2).simplified());
+ }
+ }
+ if (text.isEmpty())
+ return;
+
+ for (QMap<QString, QString>::ConstIterator it = text.constBegin(); it != text.constEnd(); ++it) {
+ QByteArray comment = it.key().toLatin1();
+ if (!comment.isEmpty())
+ comment += ": ";
+ comment += it.value().toLatin1();
+ if (comment.length() > 65530)
+ comment.truncate(65530);
+ jpeg_write_marker(cinfo, JPEG_COM, (const JOCTET *)comment.constData(), comment.size());
+ }
+}
+
+static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile int sourceQuality, const QString &description, bool optimize, bool progressive)
+{
+ bool success = false;
+ const QVector<QRgb> cmap = image.colorTable();
+
+ if (image.format() == QImage::Format_Invalid || image.format() == QImage::Format_Alpha8)
+ return false;
+
+ struct jpeg_compress_struct cinfo;
+ JSAMPROW row_pointer[1];
+ row_pointer[0] = 0;
+
+ struct my_jpeg_destination_mgr *iod_dest = new my_jpeg_destination_mgr(device);
+ struct my_error_mgr jerr;
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jerr.error_exit = my_error_exit;
+ jerr.output_message = my_output_message;
+
+ if (!setjmp(jerr.setjmp_buffer)) {
+ // WARNING:
+ // this if loop is inside a setjmp/longjmp branch
+ // do not create C++ temporaries here because the destructor may never be called
+ // if you allocate memory, make sure that you can free it (row_pointer[0])
+ jpeg_create_compress(&cinfo);
+
+ cinfo.dest = iod_dest;
+
+ cinfo.image_width = image.width();
+ cinfo.image_height = image.height();
+
+ bool gray = false;
+ switch (image.format()) {
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_Indexed8:
+ gray = true;
+ for (int i = image.colorCount(); gray && i; i--) {
+ gray = gray & qIsGray(cmap[i-1]);
+ }
+ cinfo.input_components = gray ? 1 : 3;
+ cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB;
+ break;
+ case QImage::Format_Grayscale8:
+ gray = true;
+ cinfo.input_components = 1;
+ cinfo.in_color_space = JCS_GRAYSCALE;
+ break;
+ default:
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+ }
+
+ jpeg_set_defaults(&cinfo);
+
+ qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.))
+ + qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.));
+ qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.))
+ + qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54;
+ if (diffInch < diffCm) {
+ cinfo.density_unit = 1; // dots/inch
+ cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.);
+ cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.);
+ } else {
+ cinfo.density_unit = 2; // dots/cm
+ cinfo.X_density = (image.dotsPerMeterX()+50) / 100;
+ cinfo.Y_density = (image.dotsPerMeterY()+50) / 100;
+ }
+
+ if (optimize)
+ cinfo.optimize_coding = true;
+
+ if (progressive)
+ jpeg_simple_progression(&cinfo);
+
+ int quality = sourceQuality >= 0 ? qMin(int(sourceQuality),100) : 75;
+ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+ jpeg_start_compress(&cinfo, TRUE);
+
+ set_text(image, &cinfo, description);
+
+ row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
+ int w = cinfo.image_width;
+ while (cinfo.next_scanline < cinfo.image_height) {
+ uchar *row = row_pointer[0];
+ switch (image.format()) {
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ if (gray) {
+ const uchar* data = image.constScanLine(cinfo.next_scanline);
+ if (image.format() == QImage::Format_MonoLSB) {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
+ row[i] = qRed(cmap[bit]);
+ }
+ } else {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
+ row[i] = qRed(cmap[bit]);
+ }
+ }
+ } else {
+ const uchar* data = image.constScanLine(cinfo.next_scanline);
+ if (image.format() == QImage::Format_MonoLSB) {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
+ *row++ = qRed(cmap[bit]);
+ *row++ = qGreen(cmap[bit]);
+ *row++ = qBlue(cmap[bit]);
+ }
+ } else {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
+ *row++ = qRed(cmap[bit]);
+ *row++ = qGreen(cmap[bit]);
+ *row++ = qBlue(cmap[bit]);
+ }
+ }
+ }
+ break;
+ case QImage::Format_Indexed8:
+ if (gray) {
+ const uchar* pix = image.constScanLine(cinfo.next_scanline);
+ for (int i=0; i<w; i++) {
+ *row = qRed(cmap[*pix]);
+ ++row; ++pix;
+ }
+ } else {
+ const uchar* pix = image.constScanLine(cinfo.next_scanline);
+ for (int i=0; i<w; i++) {
+ *row++ = qRed(cmap[*pix]);
+ *row++ = qGreen(cmap[*pix]);
+ *row++ = qBlue(cmap[*pix]);
+ ++pix;
+ }
+ }
+ break;
+ case QImage::Format_Grayscale8:
+ memcpy(row, image.constScanLine(cinfo.next_scanline), w);
+ break;
+ case QImage::Format_RGB888:
+ memcpy(row, image.constScanLine(cinfo.next_scanline), w * 3);
+ break;
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ {
+ const QRgb* rgb = (const QRgb*)image.constScanLine(cinfo.next_scanline);
+ for (int i=0; i<w; i++) {
+ *row++ = qRed(*rgb);
+ *row++ = qGreen(*rgb);
+ *row++ = qBlue(*rgb);
+ ++rgb;
+ }
+ }
+ break;
+ default:
+ {
+ // (Testing shows that this way is actually faster than converting to RGB888 + memcpy)
+ QImage rowImg = image.copy(0, cinfo.next_scanline, w, 1).convertToFormat(QImage::Format_RGB32);
+ const QRgb* rgb = (const QRgb*)rowImg.constScanLine(0);
+ for (int i=0; i<w; i++) {
+ *row++ = qRed(*rgb);
+ *row++ = qGreen(*rgb);
+ *row++ = qBlue(*rgb);
+ ++rgb;
+ }
+ }
+ break;
+ }
+ jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ success = true;
+ } else {
+ jpeg_destroy_compress(&cinfo);
+ success = false;
+ }
+
+ delete iod_dest;
+ delete [] row_pointer[0];
+ return success;
+}
+
+class QJpegHandlerPrivate
+{
+public:
+ enum State {
+ Ready,
+ ReadHeader,
+ ReadingEnd,
+ Error
+ };
+
+ QJpegHandlerPrivate(QJpegHandler *qq)
+ : quality(75), transformation(QImageIOHandler::TransformationNone), iod_src(0),
+ rgb888ToRgb32ConverterPtr(qt_convert_rgb888_to_rgb32), state(Ready), optimize(false), progressive(false), q(qq)
+ {}
+
+ ~QJpegHandlerPrivate()
+ {
+ if(iod_src)
+ {
+ jpeg_destroy_decompress(&info);
+ delete iod_src;
+ iod_src = 0;
+ }
+ }
+
+ bool readJpegHeader(QIODevice*);
+ bool read(QImage *image);
+
+ int quality;
+ QImageIOHandler::Transformations transformation;
+ QVariant size;
+ QImage::Format format;
+ QSize scaledSize;
+ QRect scaledClipRect;
+ QRect clipRect;
+ QString description;
+ QStringList readTexts;
+
+ struct jpeg_decompress_struct info;
+ struct my_jpeg_source_mgr * iod_src;
+ struct my_error_mgr err;
+
+ Rgb888ToRgb32Converter rgb888ToRgb32ConverterPtr;
+
+ State state;
+
+ bool optimize;
+ bool progressive;
+
+ QJpegHandler *q;
+};
+
+static bool readExifHeader(QDataStream &stream)
+{
+ char prefix[6];
+ if (stream.readRawData(prefix, sizeof(prefix)) != sizeof(prefix))
+ return false;
+ static const char exifMagic[6] = {'E', 'x', 'i', 'f', 0, 0};
+ return memcmp(prefix, exifMagic, 6) == 0;
+}
+
+/*
+ * Returns -1 on error
+ * Returns 0 if no Exif orientation was found
+ * Returns 1 orientation is horizontal (normal)
+ * Returns 2 mirror horizontal
+ * Returns 3 rotate 180
+ * Returns 4 mirror vertical
+ * Returns 5 mirror horizontal and rotate 270 CCW
+ * Returns 6 rotate 90 CW
+ * Returns 7 mirror horizontal and rotate 90 CW
+ * Returns 8 rotate 270 CW
+ */
+static int getExifOrientation(QByteArray &exifData)
+{
+ QDataStream stream(&exifData, QIODevice::ReadOnly);
+
+ if (!readExifHeader(stream))
+ return -1;
+
+ quint16 val;
+ quint32 offset;
+ const qint64 headerStart = stream.device()->pos();
+
+ // read byte order marker
+ stream >> val;
+ if (val == 0x4949) // 'II' == Intel
+ stream.setByteOrder(QDataStream::LittleEndian);
+ else if (val == 0x4d4d) // 'MM' == Motorola
+ stream.setByteOrder(QDataStream::BigEndian);
+ else
+ return -1; // unknown byte order
+
+ // read size
+ stream >> val;
+ if (val != 0x2a)
+ return -1;
+
+ stream >> offset;
+
+ // read IFD
+ while (!stream.atEnd()) {
+ quint16 numEntries;
+
+ // skip offset bytes to get the next IFD
+ const qint64 bytesToSkip = offset - (stream.device()->pos() - headerStart);
+
+ if (stream.skipRawData(bytesToSkip) != bytesToSkip)
+ return -1;
+
+ stream >> numEntries;
+
+ for (; numEntries > 0; --numEntries) {
+ quint16 tag;
+ quint16 type;
+ quint32 components;
+ quint16 value;
+ quint16 dummy;
+
+ stream >> tag >> type >> components >> value >> dummy;
+ if (tag == 0x0112) { // Tag Exif.Image.Orientation
+ if (components != 1)
+ return -1;
+ if (type != 3) // we are expecting it to be an unsigned short
+ return -1;
+ if (value < 1 || value > 8) // check for valid range
+ return -1;
+
+ // It is possible to include the orientation multiple times.
+ // Right now the first value is returned.
+ return value;
+ }
+ }
+
+ // read offset to next IFD
+ stream >> offset;
+ if (offset == 0) // this is the last IFD
+ break;
+ }
+
+ // No Exif orientation was found
+ return 0;
+}
+
+static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
+{
+ switch (exifOrientation) {
+ case 1: // normal
+ return QImageIOHandler::TransformationNone;
+ case 2: // mirror horizontal
+ return QImageIOHandler::TransformationMirror;
+ case 3: // rotate 180
+ return QImageIOHandler::TransformationRotate180;
+ case 4: // mirror vertical
+ return QImageIOHandler::TransformationFlip;
+ case 5: // mirror horizontal and rotate 270 CW
+ return QImageIOHandler::TransformationFlipAndRotate90;
+ case 6: // rotate 90 CW
+ return QImageIOHandler::TransformationRotate90;
+ case 7: // mirror horizontal and rotate 90 CW
+ return QImageIOHandler::TransformationMirrorAndRotate90;
+ case 8: // rotate 270 CW
+ return QImageIOHandler::TransformationRotate270;
+ }
+ qWarning("Invalid EXIF orientation");
+ return QImageIOHandler::TransformationNone;
+}
+
+/*!
+ \internal
+*/
+bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
+{
+ if(state == Ready)
+ {
+ state = Error;
+ iod_src = new my_jpeg_source_mgr(device);
+
+ info.err = jpeg_std_error(&err);
+ err.error_exit = my_error_exit;
+ err.output_message = my_output_message;
+
+ jpeg_create_decompress(&info);
+ info.src = iod_src;
+
+ if (!setjmp(err.setjmp_buffer)) {
+ jpeg_save_markers(&info, JPEG_COM, 0xFFFF);
+ jpeg_save_markers(&info, JPEG_APP0 + 1, 0xFFFF); // Exif uses APP1 marker
+
+ (void) jpeg_read_header(&info, TRUE);
+
+ int width = 0;
+ int height = 0;
+ read_jpeg_size(width, height, &info);
+ size = QSize(width, height);
+
+ format = QImage::Format_Invalid;
+ read_jpeg_format(format, &info);
+
+ QByteArray exifData;
+
+ for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) {
+ if (marker->marker == JPEG_COM) {
+ QString key, value;
+ QString s = QString::fromLatin1((const char *)marker->data, marker->data_length);
+ int index = s.indexOf(QLatin1String(": "));
+ if (index == -1 || s.indexOf(QLatin1Char(' ')) < index) {
+ key = QLatin1String("Description");
+ value = s;
+ } else {
+ key = s.left(index);
+ value = s.mid(index + 2);
+ }
+ if (!description.isEmpty())
+ description += QLatin1String("\n\n");
+ description += key + QLatin1String(": ") + value.simplified();
+ readTexts.append(key);
+ readTexts.append(value);
+ } else if (marker->marker == JPEG_APP0 + 1) {
+ exifData.append((const char*)marker->data, marker->data_length);
+ }
+ }
+
+ if (!exifData.isEmpty()) {
+ // Exif data present
+ int exifOrientation = getExifOrientation(exifData);
+ if (exifOrientation > 0)
+ transformation = exif2Qt(exifOrientation);
+ }
+
+ state = ReadHeader;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if(state == Error)
+ return false;
+ return true;
+}
+
+bool QJpegHandlerPrivate::read(QImage *image)
+{
+ if(state == Ready)
+ readJpegHeader(q->device());
+
+ if(state == ReadHeader)
+ {
+ bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, rgb888ToRgb32ConverterPtr, &info, &err);
+ if (success) {
+ for (int i = 0; i < readTexts.size()-1; i+=2)
+ image->setText(readTexts.at(i), readTexts.at(i+1));
+
+ state = ReadingEnd;
+ return true;
+ }
+
+ state = Error;
+ }
+
+ return false;
+
+}
+
+Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len);
+Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_ssse3(quint32 *dst, const uchar *src, int len);
+extern "C" void qt_convert_rgb888_to_rgb32_mips_dspr2_asm(quint32 *dst, const uchar *src, int len);
+
+QJpegHandler::QJpegHandler()
+ : d(new QJpegHandlerPrivate(this))
+{
+#if defined(__ARM_NEON__)
+ // from qimage_neon.cpp
+ if (qCpuHasFeature(NEON))
+ d->rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_neon;
+#endif
+
+#if defined(QT_COMPILER_SUPPORTS_SSSE3)
+ // from qimage_ssse3.cpps
+ if (qCpuHasFeature(SSSE3)) {
+ d->rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_ssse3;
+ }
+#endif // QT_COMPILER_SUPPORTS_SSSE3
+#if defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2)
+ if (qCpuHasFeature(DSPR2)) {
+ d->rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_mips_dspr2_asm;
+ }
+#endif // QT_COMPILER_SUPPORTS_DSPR2
+}
+
+QJpegHandler::~QJpegHandler()
+{
+ delete d;
+}
+
+bool QJpegHandler::canRead() const
+{
+ if(d->state == QJpegHandlerPrivate::Ready && !canRead(device()))
+ return false;
+
+ if (d->state != QJpegHandlerPrivate::Error && d->state != QJpegHandlerPrivate::ReadingEnd) {
+ setFormat("jpeg");
+ return true;
+ }
+
+ return false;
+}
+
+bool QJpegHandler::canRead(QIODevice *device)
+{
+ if (!device) {
+ qWarning("QJpegHandler::canRead() called with no device");
+ return false;
+ }
+
+ char buffer[2];
+ if (device->peek(buffer, 2) != 2)
+ return false;
+ return uchar(buffer[0]) == 0xff && uchar(buffer[1]) == 0xd8;
+}
+
+bool QJpegHandler::read(QImage *image)
+{
+ if (!canRead())
+ return false;
+ return d->read(image);
+}
+
+extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient);
+
+bool QJpegHandler::write(const QImage &image)
+{
+ if (d->transformation != QImageIOHandler::TransformationNone) {
+ // We don't support writing EXIF headers so apply the transform to the data.
+ QImage img = image;
+ qt_imageTransform(img, d->transformation);
+ return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive);
+ }
+ return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive);
+}
+
+bool QJpegHandler::supportsOption(ImageOption option) const
+{
+ return option == Quality
+ || option == ScaledSize
+ || option == ScaledClipRect
+ || option == ClipRect
+ || option == Description
+ || option == Size
+ || option == ImageFormat
+ || option == OptimizedWrite
+ || option == ProgressiveScanWrite
+ || option == ImageTransformation;
+}
+
+QVariant QJpegHandler::option(ImageOption option) const
+{
+ switch(option) {
+ case Quality:
+ return d->quality;
+ case ScaledSize:
+ return d->scaledSize;
+ case ScaledClipRect:
+ return d->scaledClipRect;
+ case ClipRect:
+ return d->clipRect;
+ case Description:
+ d->readJpegHeader(device());
+ return d->description;
+ case Size:
+ d->readJpegHeader(device());
+ return d->size;
+ case ImageFormat:
+ d->readJpegHeader(device());
+ return d->format;
+ case OptimizedWrite:
+ return d->optimize;
+ case ProgressiveScanWrite:
+ return d->progressive;
+ case ImageTransformation:
+ d->readJpegHeader(device());
+ return int(d->transformation);
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+void QJpegHandler::setOption(ImageOption option, const QVariant &value)
+{
+ switch(option) {
+ case Quality:
+ d->quality = value.toInt();
+ break;
+ case ScaledSize:
+ d->scaledSize = value.toSize();
+ break;
+ case ScaledClipRect:
+ d->scaledClipRect = value.toRect();
+ break;
+ case ClipRect:
+ d->clipRect = value.toRect();
+ break;
+ case Description:
+ d->description = value.toString();
+ break;
+ case OptimizedWrite:
+ d->optimize = value.toBool();
+ break;
+ case ProgressiveScanWrite:
+ d->progressive = value.toBool();
+ break;
+ case ImageTransformation: {
+ int transformation = value.toInt();
+ if (transformation > 0 && transformation < 8)
+ d->transformation = QImageIOHandler::Transformations(transformation);
+ }
+ default:
+ break;
+ }
+}
+
+QByteArray QJpegHandler::name() const
+{
+ return "jpeg";
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/jpeg/qjpeghandler_p.h b/src/plugins/imageformats/jpeg/qjpeghandler_p.h
new file mode 100644
index 0000000000..534ce12115
--- /dev/null
+++ b/src/plugins/imageformats/jpeg/qjpeghandler_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJPEGHANDLER_P_H
+#define QJPEGHANDLER_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 <QtGui/qimageiohandler.h>
+#include <QtCore/QSize>
+#include <QtCore/QRect>
+
+QT_BEGIN_NAMESPACE
+
+class QJpegHandlerPrivate;
+class QJpegHandler : public QImageIOHandler
+{
+public:
+ QJpegHandler();
+ ~QJpegHandler();
+
+ bool canRead() const Q_DECL_OVERRIDE;
+ bool read(QImage *image) Q_DECL_OVERRIDE;
+ bool write(const QImage &image) Q_DECL_OVERRIDE;
+
+ QByteArray name() const Q_DECL_OVERRIDE;
+
+ static bool canRead(QIODevice *device);
+
+ QVariant option(ImageOption option) const Q_DECL_OVERRIDE;
+ void setOption(ImageOption option, const QVariant &value) Q_DECL_OVERRIDE;
+ bool supportsOption(ImageOption option) const Q_DECL_OVERRIDE;
+
+private:
+ QJpegHandlerPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QJPEGHANDLER_P_H
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
index 200d5789a8..994fe8386b 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
@@ -278,7 +278,7 @@ void QIBusPlatformInputContext::updatePreeditText(const QDBusVariant &text, uint
QList<QInputMethodEvent::Attribute> attributes = t.attributes.imAttributes();
if (!t.text.isEmpty())
- attributes += QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursorPos, visible ? 1 : 0, QVariant());
+ attributes += QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursorPos, visible ? 1 : 0);
QInputMethodEvent event(t.text, attributes);
QCoreApplication::sendEvent(input, &event);
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index dc420775cf..125a03469f 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -645,7 +645,7 @@ jboolean QAndroidInputContext::commitText(const QString &text, jint newCursorPos
: localPos - text.length() + newCursorPosition;
//move the cursor
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
- newLocalPos, 0, QVariant()));
+ newLocalPos, 0));
}
}
m_blockUpdateSelection = updateSelectionWasBlocked;
@@ -691,7 +691,7 @@ jboolean QAndroidInputContext::finishComposingText()
// Moving Qt's cursor to where the preedit cursor used to be
QList<QInputMethodEvent::Attribute> attributes;
- attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, 0, QVariant()));
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, 0));
QInputMethodEvent event(QString(), attributes);
event.setCommitString(m_composingText);
@@ -848,8 +848,7 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
QList<QInputMethodEvent::Attribute> attributes;
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
newCursorPosition,
- 1,
- QVariant()));
+ 1));
// Show compose text underlined
QTextCharFormat underlined;
underlined.setFontUnderline(true);
@@ -921,7 +920,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
QVariant(underlined)));
// Keep the cursor position unchanged (don't move to end of preedit)
- attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, currentCursor - start, 1, QVariant()));
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, currentCursor - start, 1));
QInputMethodEvent event(m_composingText, attributes);
event.setCommitString(QString(), relativeStart, length);
@@ -955,7 +954,7 @@ jboolean QAndroidInputContext::setSelection(jint start, jint end)
// preedit cursor
int localOldPos = query->value(Qt::ImCursorPosition).toInt();
int pos = localCursorPos - localOldPos;
- attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, pos, 1, QVariant()));
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, pos, 1));
//but we have to tell Qt about the compose text all over again
@@ -970,8 +969,7 @@ jboolean QAndroidInputContext::setSelection(jint start, jint end)
// actually changing the selection
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
localCursorPos,
- end - start,
- QVariant()));
+ end - start));
}
QInputMethodEvent event(m_composingText, attributes);
sendInputMethodEventThreadSafe(&event);
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 80d7e31aa3..e10bd95e12 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -80,6 +80,8 @@ Qt::ScreenOrientation QAndroidPlatformIntegration::m_nativeOrientation = Qt::Pri
Qt::ApplicationState QAndroidPlatformIntegration::m_defaultApplicationState = Qt::ApplicationActive;
+bool QAndroidPlatformIntegration::m_showPasswordEnabled = false;
+
void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
{
if (resource=="JavaVM")
@@ -191,6 +193,19 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
}
QWindowSystemInterface::registerTouchDevice(m_touchDevice);
}
+
+ auto contentResolver = javaActivity.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;");
+ Q_ASSERT(contentResolver.isValid());
+ QJNIObjectPrivate txtShowPassValue = QJNIObjectPrivate::callStaticObjectMethod("android/provider/Settings$System",
+ "getString",
+ "(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;",
+ contentResolver.object(),
+ QJNIObjectPrivate::getStaticObjectField("android/provider/Settings$System", "TEXT_SHOW_PASSWORD", "Ljava/lang/String;").object());
+ if (txtShowPassValue.isValid()) {
+ bool ok = false;
+ const int txtShowPass = txtShowPassValue.toString().toInt(&ok);
+ m_showPasswordEnabled = ok ? (txtShowPass == 1) : false;
+ }
}
QGuiApplicationPrivate::instance()->setApplicationState(m_defaultApplicationState);
@@ -313,6 +328,9 @@ QPlatformServices *QAndroidPlatformIntegration::services() const
QVariant QAndroidPlatformIntegration::styleHint(StyleHint hint) const
{
switch (hint) {
+ case PasswordMaskDelay:
+ // this number is from a hard-coded value in Android code (cf. PasswordTransformationMethod)
+ return m_showPasswordEnabled ? 1500 : 0;
case ShowIsMaximized:
return true;
default:
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h
index 1f06c23d0b..bda0bee9ad 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.h
+++ b/src/plugins/platforms/android/qandroidplatformintegration.h
@@ -143,6 +143,8 @@ private:
static Qt::ApplicationState m_defaultApplicationState;
+ static bool m_showPasswordEnabled;
+
QPlatformFontDatabase *m_androidFDB;
QAndroidPlatformNativeInterface *m_androidPlatformNativeInterface;
QAndroidPlatformServices *m_androidPlatformServices;
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp
index a73550606b..155d6bfb8d 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.cpp
+++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp
@@ -379,9 +379,8 @@ void QAndroidPlatformScreen::doRedraw()
}
}
- foreach (const QRect &rect, visibleRegion.rects()) {
+ for (const QRect &rect : visibleRegion)
compositePainter.fillRect(rect, QColor(Qt::transparent));
- }
ret = ANativeWindow_unlockAndPost(m_nativeSurface);
if (ret >= 0)
diff --git a/src/plugins/platforms/bsdfb/bsdfb.json b/src/plugins/platforms/bsdfb/bsdfb.json
new file mode 100644
index 0000000000..97b3e7707e
--- /dev/null
+++ b/src/plugins/platforms/bsdfb/bsdfb.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "bsdfb" ]
+}
diff --git a/src/plugins/platforms/bsdfb/bsdfb.pro b/src/plugins/platforms/bsdfb/bsdfb.pro
new file mode 100644
index 0000000000..c24d8dd9e5
--- /dev/null
+++ b/src/plugins/platforms/bsdfb/bsdfb.pro
@@ -0,0 +1,15 @@
+TARGET = qbsdfb
+
+QT += core-private gui-private platformsupport-private
+
+SOURCES = main.cpp qbsdfbintegration.cpp qbsdfbscreen.cpp
+HEADERS = qbsdfbintegration.h qbsdfbscreen.h
+
+CONFIG += qpa/genericunixfontdatabase
+
+OTHER_FILES += bsdfb.json
+
+PLUGIN_TYPE = platforms
+PLUGIN_CLASS_NAME = QBsdFbIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
+load(qt_plugin)
diff --git a/src/plugins/platforms/bsdfb/main.cpp b/src/plugins/platforms/bsdfb/main.cpp
new file mode 100644
index 0000000000..f4ab3dee39
--- /dev/null
+++ b/src/plugins/platforms/bsdfb/main.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformintegrationplugin.h>
+#include "qbsdfbintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QBsdFbIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "bsdfb.json")
+public:
+ QPlatformIntegration *create(const QString&, const QStringList&) override;
+};
+
+QPlatformIntegration* QBsdFbIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (!system.compare(QLatin1String("bsdfb"), Qt::CaseInsensitive))
+ return new QBsdFbIntegration(paramList);
+
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
+
diff --git a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
new file mode 100644
index 0000000000..edb4f4e660
--- /dev/null
+++ b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbsdfbintegration.h"
+#include "qbsdfbscreen.h"
+
+#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
+#include <QtPlatformSupport/private/qgenericunixservices_p.h>
+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+
+#include <QtPlatformSupport/private/qfbvthandler_p.h>
+#include <QtPlatformSupport/private/qfbbackingstore_p.h>
+#include <QtPlatformSupport/private/qfbwindow_p.h>
+#include <QtPlatformSupport/private/qfbcursor_p.h>
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatforminputcontext.h>
+#include <qpa/qplatforminputcontextfactory_p.h>
+
+#if !defined(QT_NO_TSLIB)
+#include <QtPlatformSupport/private/qtslib_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QBsdFbIntegration::QBsdFbIntegration(const QStringList &paramList)
+{
+ m_fontDb.reset(new QGenericUnixFontDatabase);
+ m_services.reset(new QGenericUnixServices);
+ m_primaryScreen.reset(new QBsdFbScreen(paramList));
+}
+
+QBsdFbIntegration::~QBsdFbIntegration()
+{
+ destroyScreen(m_primaryScreen.data());
+}
+
+void QBsdFbIntegration::initialize()
+{
+ if (m_primaryScreen->initialize())
+ screenAdded(m_primaryScreen.data());
+ else
+ qWarning("bsdfb: Failed to initialize screen");
+
+ m_inputContext.reset(QPlatformInputContextFactory::create());
+ m_nativeInterface.reset(new QPlatformNativeInterface);
+ m_vtHandler.reset(new QFbVtHandler);
+
+ if (!qEnvironmentVariableIntValue("QT_QPA_FB_DISABLE_INPUT"))
+ createInputHandlers();
+}
+
+bool QBsdFbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps:
+ return true;
+ case WindowManagement:
+ return false;
+ default:
+ return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+QPlatformBackingStore *QBsdFbIntegration::createPlatformBackingStore(QWindow *window) const
+{
+ return new QFbBackingStore(window);
+}
+
+QPlatformWindow *QBsdFbIntegration::createPlatformWindow(QWindow *window) const
+{
+ return new QFbWindow(window);
+}
+
+QAbstractEventDispatcher *QBsdFbIntegration::createEventDispatcher() const
+{
+ return createUnixEventDispatcher();
+}
+
+QList<QPlatformScreen *> QBsdFbIntegration::screens() const
+{
+ QList<QPlatformScreen *> list;
+ list.append(m_primaryScreen.data());
+ return list;
+}
+
+QPlatformFontDatabase *QBsdFbIntegration::fontDatabase() const
+{
+ return m_fontDb.data();
+}
+
+QPlatformServices *QBsdFbIntegration::services() const
+{
+ return m_services.data();
+}
+
+void QBsdFbIntegration::createInputHandlers()
+{
+#ifndef QT_NO_TSLIB
+ const bool useTslib = qEnvironmentVariableIntValue("QT_QPA_FB_TSLIB");
+ if (useTslib)
+ new QTsLibMouseHandler(QLatin1String("TsLib"), QString());
+#endif
+}
+
+QPlatformNativeInterface *QBsdFbIntegration::nativeInterface() const
+{
+ return m_nativeInterface.data();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/bsdfb/qbsdfbintegration.h b/src/plugins/platforms/bsdfb/qbsdfbintegration.h
new file mode 100644
index 0000000000..2be5ea260d
--- /dev/null
+++ b/src/plugins/platforms/bsdfb/qbsdfbintegration.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBSDFBINTEGRATION_H
+#define QBSDFBINTEGRATION_H
+
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractEventDispatcher;
+class QBsdFbScreen;
+class QFbVtHandler;
+
+class QBsdFbIntegration : public QPlatformIntegration, public QPlatformNativeInterface
+{
+public:
+ explicit QBsdFbIntegration(const QStringList &paramList);
+ ~QBsdFbIntegration() override;
+
+ void initialize() override;
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
+
+ QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
+
+ QAbstractEventDispatcher *createEventDispatcher() const override;
+
+ QPlatformFontDatabase *fontDatabase() const override;
+ QPlatformServices *services() const override;
+ QPlatformInputContext *inputContext() const override { return m_inputContext.data(); }
+
+ QPlatformNativeInterface *nativeInterface() const override;
+
+ QList<QPlatformScreen *> screens() const;
+
+private:
+ void createInputHandlers();
+
+ QScopedPointer<QBsdFbScreen> m_primaryScreen;
+ QScopedPointer<QPlatformInputContext> m_inputContext;
+ QScopedPointer<QPlatformFontDatabase> m_fontDb;
+ QScopedPointer<QPlatformServices> m_services;
+ QScopedPointer<QFbVtHandler> m_vtHandler;
+ QScopedPointer<QPlatformNativeInterface> m_nativeInterface;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBSDFBINTEGRATION_H
diff --git a/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp b/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp
new file mode 100644
index 0000000000..ee2dce6867
--- /dev/null
+++ b/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbsdfbscreen.h"
+#include <QtPlatformSupport/private/qfbcursor_p.h>
+#include <QtPlatformSupport/private/qfbwindow_p.h>
+#include <QtCore/QRegularExpression>
+#include <QtGui/QPainter>
+
+#include <private/qcore_unix_p.h> // overrides QT_OPEN
+#include <qimage.h>
+#include <qdebug.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <limits.h>
+#include <signal.h>
+
+#include <sys/consio.h>
+#include <sys/fbio.h>
+
+QT_BEGIN_NAMESPACE
+
+enum {
+ DefaultDPI = 100
+};
+
+static int openFramebufferDevice(const QString &dev)
+{
+ const QByteArray devPath = QFile::encodeName(dev);
+
+ int fd = QT_OPEN(devPath.constData(), O_RDWR);
+
+ if (fd == -1)
+ fd = QT_OPEN(devPath.constData(), O_RDONLY);
+
+ return fd;
+}
+
+static QRect determineGeometry(const struct fbtype &fb, const QRect &userGeometry)
+{
+ int xoff = 0;
+ int yoff = 0;
+ int w = 0;
+ int h = 0;
+
+ if (userGeometry.isValid()) {
+ w = qMin(userGeometry.width(), fb.fb_width);
+ h = qMin(userGeometry.height(), fb.fb_height);
+
+ int xxoff = userGeometry.x(), yyoff = userGeometry.y();
+ if (xxoff != 0 || yyoff != 0) {
+ if (xxoff < 0 || xxoff + w > fb.fb_width)
+ xxoff = fb.fb_width - w;
+ if (yyoff < 0 || yyoff + h > fb.fb_height)
+ yyoff = fb.fb_height - h;
+ xoff += xxoff;
+ yoff += yyoff;
+ } else {
+ xoff += (fb.fb_width - w)/2;
+ yoff += (fb.fb_height - h)/2;
+ }
+ } else {
+ w = fb.fb_width;
+ h = fb.fb_height;
+ }
+
+ if (w == 0 || h == 0) {
+ qWarning("Unable to find screen geometry, using 320x240");
+ w = 320;
+ h = 240;
+ }
+
+ return QRect(xoff, yoff, w, h);
+}
+
+static QSizeF determinePhysicalSize(const QSize &mmSize, const QSize &res)
+{
+ int mmWidth = mmSize.width();
+ int mmHeight = mmSize.height();
+
+ if (mmWidth <= 0 && mmHeight <= 0) {
+ const int dpi = DefaultDPI;
+ mmWidth = qRound(res.width() * 25.4 / dpi);
+ mmHeight = qRound(res.height() * 25.4 / dpi);
+ } else if (mmWidth > 0 && mmHeight <= 0) {
+ mmHeight = res.height() * mmWidth/res.width();
+ } else if (mmHeight > 0 && mmWidth <= 0) {
+ mmWidth = res.width() * mmHeight/res.height();
+ }
+
+ return QSize(mmWidth, mmHeight);
+}
+
+QBsdFbScreen::QBsdFbScreen(const QStringList &args)
+ : m_arguments(args)
+{
+}
+
+QBsdFbScreen::~QBsdFbScreen()
+{
+ if (m_framebufferFd != -1) {
+ munmap(m_mmap.data - m_mmap.offset, m_mmap.size);
+ qt_safe_close(m_framebufferFd);
+ }
+}
+
+bool QBsdFbScreen::initialize()
+{
+ QRegularExpression fbRx(QLatin1String("fb=(.*)"));
+ QRegularExpression mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)"));
+ QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
+ QRegularExpression offsetRx(QLatin1String("offset=(\\d+)x(\\d+)"));
+
+ QString fbDevice;
+ QSize userMmSize;
+ QRect userGeometry;
+
+ // Parse arguments
+ for (const QString &arg : qAsConst(m_arguments)) {
+ QRegularExpressionMatch match;
+ if (arg.contains(mmSizeRx, &match))
+ userMmSize = QSize(match.captured(1).toInt(), match.captured(2).toInt());
+ else if (arg.contains(sizeRx, &match))
+ userGeometry.setSize(QSize(match.captured(1).toInt(), match.captured(2).toInt()));
+ else if (arg.contains(offsetRx, &match))
+ userGeometry.setTopLeft(QPoint(match.captured(1).toInt(), match.captured(2).toInt()));
+ else if (arg.contains(fbRx, &match))
+ fbDevice = match.captured(1);
+ }
+
+ if (!fbDevice.isEmpty()) {
+ // Open the device
+ m_framebufferFd = openFramebufferDevice(fbDevice);
+ } else {
+ m_framebufferFd = STDIN_FILENO;
+ }
+
+ if (m_framebufferFd == -1) {
+ qErrnoWarning(errno, "Failed to open framebuffer %s", qPrintable(fbDevice));
+ return false;
+ }
+
+ struct fbtype fb;
+ if (ioctl(m_framebufferFd, FBIOGTYPE, &fb) != 0) {
+ qErrnoWarning(errno, "Error reading framebuffer information");
+ return false;
+ }
+
+ int line_length = 0;
+ if (ioctl(m_framebufferFd, FBIO_GETLINEWIDTH, &line_length) != 0) {
+ qErrnoWarning(errno, "Error reading line length information");
+ return false;
+ }
+
+ mDepth = fb.fb_depth;
+
+ m_bytesPerLine = line_length;
+ const QRect geometry = determineGeometry(fb, userGeometry);
+ mGeometry = QRect(QPoint(0, 0), geometry.size());
+ switch (mDepth) {
+ case 32:
+ mFormat = QImage::Format_RGB32;
+ break;
+ case 24:
+ mFormat = QImage::Format_RGB888;
+ break;
+ case 16:
+ // falling back
+ default:
+ mFormat = QImage::Format_RGB16;
+ break;
+ }
+ mPhysicalSize = determinePhysicalSize(userMmSize, geometry.size());
+
+ // mmap the framebuffer
+ const size_t pagemask = getpagesize() - 1;
+ m_mmap.size = (m_bytesPerLine * fb.fb_height + pagemask) & ~pagemask;
+ uchar *data = static_cast<uchar*>(mmap(nullptr, m_mmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebufferFd, 0));
+ if (data == MAP_FAILED) {
+ qErrnoWarning(errno, "Failed to mmap framebuffer");
+ return false;
+ }
+
+ m_mmap.offset = geometry.y() * m_bytesPerLine + geometry.x() * mDepth / 8;
+ m_mmap.data = data + m_mmap.offset;
+
+ QFbScreen::initializeCompositor();
+ m_onscreenImage = QImage(m_mmap.data, geometry.width(), geometry.height(), m_bytesPerLine, mFormat);
+
+ mCursor = new QFbCursor(this);
+
+ return true;
+}
+
+QRegion QBsdFbScreen::doRedraw()
+{
+ const QRegion touched = QFbScreen::doRedraw();
+
+ if (touched.isEmpty())
+ return touched;
+
+ if (!m_blitter)
+ m_blitter.reset(new QPainter(&m_onscreenImage));
+
+ const auto rects = touched.rects();
+ for (const QRect &rect : rects)
+ m_blitter->drawImage(rect, *mScreenImage, rect);
+ return touched;
+}
+
+// grabWindow() grabs "from the screen" not from the backingstores.
+QPixmap QBsdFbScreen::grabWindow(WId wid, int x, int y, int width, int height) const
+{
+ if (!wid) {
+ if (width < 0)
+ width = m_onscreenImage.width() - x;
+ if (height < 0)
+ height = m_onscreenImage.height() - y;
+ return QPixmap::fromImage(m_onscreenImage).copy(x, y, width, height);
+ }
+
+ const QFbWindow *window = windowForId(wid);
+ if (window) {
+ const QRect geom = window->geometry();
+ if (width < 0)
+ width = geom.width() - x;
+ if (height < 0)
+ height = geom.height() - y;
+ QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height));
+ rect &= window->geometry();
+ return QPixmap::fromImage(m_onscreenImage).copy(rect);
+ }
+
+ return QPixmap();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/bsdfb/qbsdfbscreen.h b/src/plugins/platforms/bsdfb/qbsdfbscreen.h
new file mode 100644
index 0000000000..0d9964afd5
--- /dev/null
+++ b/src/plugins/platforms/bsdfb/qbsdfbscreen.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBSDFBSCREEN_H
+#define QBSDFBSCREEN_H
+
+#include <QtPlatformSupport/private/qfbscreen_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPainter;
+
+class QBsdFbScreen : public QFbScreen
+{
+ Q_OBJECT
+public:
+ explicit QBsdFbScreen(const QStringList &args);
+ ~QBsdFbScreen() override;
+
+ bool initialize();
+
+ QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override;
+
+ QRegion doRedraw() override;
+
+private:
+ QStringList m_arguments;
+ int m_framebufferFd = -1;
+ QImage m_onscreenImage;
+
+ int m_bytesPerLine = -1;
+
+ struct {
+ uchar *data;
+ int offset, size;
+ } m_mmap;
+
+ QScopedPointer<QPainter> m_blitter;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBSDFBSCREEN_H
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm
index c496134606..170f17504f 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm
@@ -71,11 +71,11 @@
**
****************************************************************************/
-#include <qcocoaapplication.h>
+#include "qcocoaapplication.h"
-#include <qcocoaintrospection.h>
-#include <qcocoaapplicationdelegate.h>
-#include <qcocoahelpers.h>
+#include "qcocoaintrospection.h"
+#include "qcocoaapplicationdelegate.h"
+#include "qcocoahelpers.h"
#include <qguiapplication.h>
#include <qdebug.h>
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
index fa05626d18..52a3e756b9 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
@@ -57,11 +57,8 @@ public:
QPaintDevice *paintDevice() Q_DECL_OVERRIDE;
void flush(QWindow *widget, const QRegion &region, const QPoint &offset) Q_DECL_OVERRIDE;
-#ifndef QT_NO_OPENGL
QImage toImage() const Q_DECL_OVERRIDE;
-#else
- QImage toImage() const; // No QPlatformBackingStore::toImage() for NO_OPENGL builds.
-#endif
+
void resize (const QSize &size, const QRegion &) Q_DECL_OVERRIDE;
bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE;
void beginPaint(const QRegion &region) Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index b060d6a082..20233518b3 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -96,9 +96,8 @@ bool QCocoaBackingStore::scroll(const QRegion &area, int dx, int dy)
extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
const qreal devicePixelRatio = m_qImage.devicePixelRatio();
QPoint qpoint(dx * devicePixelRatio, dy * devicePixelRatio);
- const QVector<QRect> qrects = area.rects();
- for (int i = 0; i < qrects.count(); ++i) {
- const QRect &qrect = QRect(qrects.at(i).topLeft() * devicePixelRatio, qrects.at(i).size() * devicePixelRatio);
+ for (const QRect &rect : area) {
+ const QRect qrect(rect.topLeft() * devicePixelRatio, rect.size() * devicePixelRatio);
qt_scrollRectInImage(m_qImage, qrect, qpoint);
}
return true;
@@ -109,10 +108,9 @@ void QCocoaBackingStore::beginPaint(const QRegion &region)
if (m_qImage.hasAlphaChannel()) {
QPainter p(&m_qImage);
p.setCompositionMode(QPainter::CompositionMode_Source);
- const QVector<QRect> rects = region.rects();
const QColor blank = Qt::transparent;
- for (QVector<QRect>::const_iterator it = rects.begin(), end = rects.end(); it != end; ++it)
- p.fillRect(*it, blank);
+ for (const QRect &rect : region)
+ p.fillRect(rect, blank);
}
}
diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
index 85468009f3..aaa12c6edb 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
@@ -132,7 +132,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
- (void)setDialogHelper:(QCocoaColorDialogHelper *)helper
{
mHelper = helper;
- [mColorPanel setShowsAlpha:mHelper->options()->testOption(QColorDialogOptions::ShowAlphaChannel)];
+
if (mHelper->options()->testOption(QColorDialogOptions::NoButtons)) {
[self restoreOriginalContentView];
} else if (!mStolenContentView) {
@@ -483,6 +483,14 @@ bool QCocoaColorDialogHelper::show(Qt::WindowFlags, Qt::WindowModality windowMod
{
if (windowModality == Qt::WindowModal)
windowModality = Qt::ApplicationModal;
+
+ // Workaround for Apple rdar://25792119: If you invoke
+ // -setShowsAlpha: multiple times before showing the color
+ // picker, its height grows irrevocably. Instead, only
+ // invoke it once, when we show the dialog.
+ [[NSColorPanel sharedColorPanel] setShowsAlpha:
+ options()->testOption(QColorDialogOptions::ShowAlphaChannel)];
+
sharedColorPanel()->init(this);
return sharedColorPanel()->show(windowModality, parent);
}
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm
index 872b97566f..1ebcde0584 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.mm
+++ b/src/plugins/platforms/cocoa/qcocoadrag.mm
@@ -128,7 +128,7 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o)
QPixmap pm = dragPixmap(m_drag, hotSpot);
QSize pmDeviceIndependentSize = pm.size() / pm.devicePixelRatio();
NSImage *nsimage = qt_mac_create_nsimage(pm);
- [nsimage setSize : qt_mac_toNSSize(pmDeviceIndependentSize)];
+ [nsimage setSize:pmDeviceIndependentSize.toCGSize()];
QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacInternalPasteboardMime::MIME_DND);
m_drag->mimeData()->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy"));
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 4eb35f5495..0375dd85f2 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -61,6 +61,8 @@
#include <qvarlengtharray.h>
#include <stdlib.h>
#include <qabstracteventdispatcher.h>
+#include <qsysinfo.h>
+#include <qglobal.h>
#include <QDir>
#include <qpa/qplatformnativeinterface.h>
@@ -160,6 +162,11 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
// here to make sure it gets the correct value.
[mSavePanel setDelegate:self];
+#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_11)
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_11)
+ mOpenPanel.accessoryViewDisclosed = YES;
+#endif
+
if (mOptions->isLabelExplicitlySet(QFileDialogOptions::Accept))
[mSavePanel setPrompt:[self strip:options->labelText(QFileDialogOptions::Accept)]];
if (mOptions->isLabelExplicitlySet(QFileDialogOptions::FileName))
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index ec2f7f8cf1..723e85f784 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -77,10 +77,6 @@ CGImageRef qt_mac_toCGImageMask(const QImage &qImage);
QImage qt_mac_toQImage(CGImageRef image);
QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size);
-NSSize qt_mac_toNSSize(const QSize &qtSize);
-NSRect qt_mac_toNSRect(const QRect &rect);
-QRect qt_mac_toQRect(const NSRect &rect);
-
QColor qt_mac_toQColor(const NSColor *color);
QColor qt_mac_toQColor(CGColorRef color);
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index 7480d99d19..9ccca1684c 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -202,34 +202,13 @@ NSImage *qt_mac_create_nsimage(const QIcon &icon)
HIMutableShapeRef qt_mac_QRegionToHIMutableShape(const QRegion &region)
{
HIMutableShapeRef shape = HIShapeCreateMutable();
- QVector<QRect> rects = region.rects();
- if (!rects.isEmpty()) {
- int n = rects.count();
- const QRect *qt_r = rects.constData();
- while (n--) {
- CGRect cgRect = CGRectMake(qt_r->x(), qt_r->y(), qt_r->width(), qt_r->height());
- HIShapeUnionWithRect(shape, &cgRect);
- ++qt_r;
- }
+ for (const QRect &rect : region) {
+ CGRect cgRect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
+ HIShapeUnionWithRect(shape, &cgRect);
}
return shape;
}
-NSSize qt_mac_toNSSize(const QSize &qtSize)
-{
- return NSMakeSize(qtSize.width(), qtSize.height());
-}
-
-NSRect qt_mac_toNSRect(const QRect &rect)
-{
- return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
-}
-
-QRect qt_mac_toQRect(const NSRect &rect)
-{
- return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
-}
-
QColor qt_mac_toQColor(const NSColor *color)
{
QColor qtColor;
@@ -340,38 +319,8 @@ QBrush qt_mac_toQBrush(const NSColor *color, QPalette::ColorGroup colorGroup)
// (and providing no public API to get the underlying color without this insanity)
if (qt_mac_isSystemColorOrInstance(color, @"controlColor", @"NSGradientPatternColor") ||
qt_mac_isSystemColorOrInstance(color, @"windowBackgroundColor", @"NSGradientPatternColor")) {
- static QColor newColor;
- if (!newColor.isValid()) {
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_8, __IPHONE_NA)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
- newColor = qt_mac_toQColor(color.CGColor);
- } else
-#endif
- {
- NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
- pixelsWide:1
- pixelsHigh:1
- bitsPerSample:8
- samplesPerPixel:4
- hasAlpha:YES
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:4
- bitsPerPixel:32];
- [NSGraphicsContext saveGraphicsState];
- [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]];
- NSEraseRect(NSMakeRect(0, 0, 1, 1));
- [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)];
- [NSGraphicsContext restoreGraphicsState];
- NSUInteger pixel[4];
- [offscreenRep getPixel:pixel atX:0 y:0];
- [offscreenRep release];
- newColor = QColor(pixel[0], pixel[1], pixel[2], pixel[3]);
- }
- }
-
qtBrush.setStyle(Qt::SolidPattern);
- qtBrush.setColor(newColor);
+ qtBrush.setColor(qt_mac_toQColor(color.CGColor));
return qtBrush;
}
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.h b/src/plugins/platforms/cocoa/qcocoakeymapper.h
index 93ebc5b9dc..4ba615efeb 100644
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.h
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.h
@@ -40,7 +40,7 @@
#ifndef QCOCOAKEYMAPPER_H
#define QCOCOAKEYMAPPER_H
-#include <qcocoahelpers.h>
+#include "qcocoahelpers.h"
#include <AppKit/AppKit.h>
#include <Carbon/Carbon.h>
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 0cbdc5d9c8..e8d8a473c3 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -91,11 +91,8 @@ QT_USE_NAMESPACE
@class QT_MANGLE_NAMESPACE(QNSMenu);
@class QT_MANGLE_NAMESPACE(QNSImageView);
-@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
- <NSUserNotificationCenterDelegate>
-#endif
- {
+@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject <NSUserNotificationCenterDelegate>
+{
@public
QCocoaSystemTrayIcon *systray;
NSStatusItem *item;
@@ -109,11 +106,8 @@ QT_USE_NAMESPACE
-(QRectF)geometry;
- (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton;
- (void)doubleClickSelector:(id)sender;
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification;
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification;
-#endif
@end
@interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView {
@@ -142,19 +136,11 @@ class QSystemTrayIconSys
public:
QSystemTrayIconSys(QCocoaSystemTrayIcon *sys) {
item = [[QNSStatusItem alloc] initWithSysTray:sys];
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
- [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:item];
- }
-#endif
+ [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:item];
}
~QSystemTrayIconSys() {
[[[item item] view] setHidden: YES];
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
- [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
- }
-#endif
+ [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
[item release];
}
QNSStatusItem *item;
@@ -296,71 +282,15 @@ bool QCocoaSystemTrayIcon::supportsMessages() const
void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &message,
const QIcon& icon, MessageIcon, int)
{
+ Q_UNUSED(icon);
if (!m_sys)
return;
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
- NSUserNotification *notification = [[NSUserNotification alloc] init];
- notification.title = [NSString stringWithUTF8String:title.toUtf8().data()];
- notification.informativeText = [NSString stringWithUTF8String:message.toUtf8().data()];
-
- [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
+ NSUserNotification *notification = [[NSUserNotification alloc] init];
+ notification.title = [NSString stringWithUTF8String:title.toUtf8().data()];
+ notification.informativeText = [NSString stringWithUTF8String:message.toUtf8().data()];
- return;
- }
-#endif
-
-#ifdef QT_MAC_SYSTEMTRAY_USE_GROWL
- // Make sure that we have Growl installed on the machine we are running on.
- QCFType<CFURLRef> cfurl;
- OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator,
- CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
- if (status == kLSApplicationNotFoundErr)
- return;
- QCFType<CFBundleRef> bundle = CFBundleCreate(0, cfurl);
-
- if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"),
- kCFCompareCaseInsensitive | kCFCompareBackwards) != kCFCompareEqualTo)
- return;
- QPixmap notificationIconPixmap = icon.pixmap(32, 32);
- QTemporaryFile notificationIconFile;
- QString notificationType(QLatin1String("Notification")), notificationIcon, notificationApp(qt_mac_applicationName());
- if (notificationApp.isEmpty())
- notificationApp = QLatin1String("Application");
- if (!notificationIconPixmap.isNull() && notificationIconFile.open()) {
- QImageWriter writer(&notificationIconFile, "PNG");
- if (writer.write(notificationIconPixmap.toImage()))
- notificationIcon = QLatin1String("image from location \"file://") + notificationIconFile.fileName() + QLatin1String("\"");
- }
- const QString script(QLatin1String(
- "tell application \"System Events\"\n"
- "set isRunning to (count of (every process whose bundle identifier is \"com.Growl.GrowlHelperApp\")) > 0\n"
- "end tell\n"
- "if isRunning\n"
- "tell application id \"com.Growl.GrowlHelperApp\"\n"
- "-- Make a list of all the notification types (all)\n"
- "set the allNotificationsList to {\"") + notificationType + QLatin1String("\"}\n"
-
- "-- Make a list of the notifications (enabled)\n"
- "set the enabledNotificationsList to {\"") + notificationType + QLatin1String("\"}\n"
-
- "-- Register our script with growl.\n"
- "register as application \"") + notificationApp + QLatin1String("\" all notifications allNotificationsList default notifications enabledNotificationsList\n"
-
- "-- Send a Notification...\n") +
- QLatin1String("notify with name \"") + notificationType +
- QLatin1String("\" title \"") + title +
- QLatin1String("\" description \"") + message +
- QLatin1String("\" application name \"") + notificationApp +
- QLatin1String("\" ") + notificationIcon +
- QLatin1String("\nend tell\nend if"));
- qt_mac_execute_apple_script(script, 0);
-#else
- Q_UNUSED(icon);
- Q_UNUSED(title);
- Q_UNUSED(message);
-#endif
+ [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
}
QT_END_NAMESPACE
@@ -499,7 +429,6 @@ QT_END_NAMESPACE
emit systray->activated(QPlatformSystemTrayIcon::DoubleClick);
}
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification {
Q_UNUSED(center);
Q_UNUSED(notification);
@@ -511,7 +440,6 @@ QT_END_NAMESPACE
Q_UNUSED(notification);
emit systray->messageClicked();
}
-#endif
@end
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index d9e94735ac..6415233250 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -275,6 +275,7 @@ protected:
void syncWindowState(Qt::WindowState newState);
void reinsertChildWindow(QCocoaWindow *child);
void removeChildWindow(QCocoaWindow *child);
+ bool isNativeWindowTypeInconsistent();
// private:
public: // for QNSView
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 91ce91004f..86df38c583 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -505,7 +505,7 @@ QRect QCocoaWindow::geometry() const
NSRect screenRect = [[m_contentView window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
NSPoint screenPoint = screenRect.origin;
QPoint position = qt_mac_flipPoint(screenPoint).toPoint();
- QSize size = qt_mac_toQRect([m_contentView bounds]).size();
+ QSize size = QRectF::fromCGRect([m_contentView bounds]).toRect().size();
return QRect(position, size);
}
@@ -652,7 +652,7 @@ void QCocoaWindow::setVisible(bool visible)
if (visible) {
// We need to recreate if the modality has changed as the style mask will need updating
- if (m_windowModality != window()->modality())
+ if (m_windowModality != window()->modality() || isNativeWindowTypeInconsistent())
recreateWindow(parent());
// Register popup windows. The Cocoa platform plugin will forward mouse events
@@ -1107,11 +1107,10 @@ void QCocoaWindow::propagateSizeHints()
// sizeIncrement is observed to take values of (-1, -1) and (0, 0) for windows that should be
// resizable and that have no specific size increment set. Cocoa expects (1.0, 1.0) in this case.
- const QSize sizeIncrement = windowSizeIncrement();
- if (!sizeIncrement.isEmpty())
- [m_nsWindow setResizeIncrements : qt_mac_toNSSize(sizeIncrement)];
- else
- [m_nsWindow setResizeIncrements : NSMakeSize(1.0, 1.0)];
+ QSize sizeIncrement = windowSizeIncrement();
+ if (sizeIncrement.isEmpty())
+ sizeIncrement = QSize(1, 1);
+ [m_nsWindow setResizeIncrements:sizeIncrement.toCGSize()];
QRect rect = geometry();
QSize baseSize = windowBaseSize();
@@ -1532,6 +1531,17 @@ void QCocoaWindow::removeChildWindow(QCocoaWindow *child)
[m_nsWindow removeChildWindow:child->m_nsWindow];
}
+bool QCocoaWindow::isNativeWindowTypeInconsistent()
+{
+ if (!m_nsWindow)
+ return false;
+
+ const bool isPanel = [m_nsWindow isKindOfClass:[QNSPanel class]];
+ const bool usePanel = shouldUseNSPanel();
+
+ return isPanel != usePanel;
+}
+
void QCocoaWindow::removeMonitor()
{
if (!monitor)
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index 00d65ea7f8..02ae64a58e 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -85,7 +85,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
bool m_resendKeyEvent;
bool m_scrolling;
bool m_updatingDrag;
- bool m_exposedOnMoveToWindow;
NSEvent *m_currentlyInterpretedKeyEvent;
bool m_isMenuView;
QSet<quint32> m_acceptedKeyDowns;
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 3469166fdc..7834c2991d 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -39,8 +39,6 @@
#include <QtCore/qglobal.h>
-#include <dlfcn.h>
-
#include "qnsview.h"
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
@@ -72,9 +70,6 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
static QTouchDevice *touchDevice = 0;
-// ### HACK Remove once 10.8 is unsupported
-static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
-
static bool _q_dontOverrideCtrlLMB = false;
@interface NSEvent (Qt_Compile_Leopard_DeviceDelta)
@@ -134,10 +129,6 @@ static bool _q_dontOverrideCtrlLMB = false;
+ (void)initialize
{
- NSString **notificationNameVar = (NSString **)dlsym(RTLD_NEXT, "NSWindowDidChangeOcclusionStateNotification");
- if (notificationNameVar)
- _q_NSWindowDidChangeOcclusionStateNotification = *notificationNameVar;
-
_q_dontOverrideCtrlLMB = qt_mac_resolveOption(false, "QT_MAC_DONT_OVERRIDE_CTRL_LMB");
}
@@ -291,18 +282,6 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void)viewDidMoveToWindow
{
m_backingStore = Q_NULLPTR;
- m_isMenuView = [self.window.className isEqualToString:@"NSCarbonMenuWindow"];
- if (self.window) {
- // This is the case of QWidgetAction's generated QWidget inserted in an NSMenu.
- // 10.9 and newer get the NSWindowDidChangeOcclusionStateNotification
- if (!_q_NSWindowDidChangeOcclusionStateNotification && m_isMenuView) {
- m_exposedOnMoveToWindow = true;
- m_platformWindow->exposeWindow();
- }
- } else if (m_exposedOnMoveToWindow) {
- m_exposedOnMoveToWindow = false;
- m_platformWindow->obscureWindow();
- }
}
- (void)viewWillMoveToWindow:(NSWindow *)newWindow
@@ -343,9 +322,9 @@ static bool _q_dontOverrideCtrlLMB = false;
if (m_platformWindow->m_isNSWindowChild) {
return;
#if 0
- //geometry = qt_mac_toQRect([self frame]);
+ //geometry = QRectF::fromCGRect([self frame]).toRect();
qDebug() << "nsview updateGeometry" << m_platformWindow->window();
- QRect screenRect = qt_mac_toQRect([m_platformWindow->m_nsWindow convertRectToScreen:[self frame]]);
+ QRect screenRect = QRectF::fromCGRect([m_platformWindow->m_nsWindow convertRectToScreen:[self frame]]).toRect();
qDebug() << "screenRect" << screenRect;
screenRect.moveTop(qt_mac_flipYCoordinate(screenRect.y() + screenRect.height()));
@@ -360,10 +339,10 @@ static bool _q_dontOverrideCtrlLMB = false;
geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height);
} else if (m_platformWindow->m_contentViewIsToBeEmbedded) {
// embedded child window, use the frame rect ### merge with case below
- geometry = qt_mac_toQRect([self bounds]);
+ geometry = QRectF::fromCGRect([self bounds]).toRect();
} else {
// child window, use the frame rect
- geometry = qt_mac_toQRect([self frame]);
+ geometry = QRectF::fromCGRect([self frame]).toRect();
}
if (m_platformWindow->m_nsWindow && geometry == m_platformWindow->geometry())
@@ -432,7 +411,7 @@ static bool _q_dontOverrideCtrlLMB = false;
// set the active window to zero here, the new key window's
// NSWindowDidBecomeKeyNotification hander will change the active window
NSWindow *keyWindow = [NSApp keyWindow];
- if (!keyWindow) {
+ if (!keyWindow || keyWindow == windowNotification.object) {
// no new key window, go ahead and set the active window to zero
if (!m_platformWindow->windowIsPopupType() && !m_isMenuView)
QWindowSystemInterface::handleWindowActivated(0);
@@ -446,14 +425,7 @@ static bool _q_dontOverrideCtrlLMB = false;
m_platformWindow->obscureWindow();
} else if ([notificationName isEqualToString: @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification"]) {
m_platformWindow->exposeWindow();
- } else if (_q_NSWindowDidChangeOcclusionStateNotification
- && [notificationName isEqualToString:_q_NSWindowDidChangeOcclusionStateNotification]) {
-#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
-// ### HACK Remove the enum declaration, the warning disabling and the cast further down once 10.8 is unsupported
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_CLANG("-Wobjc-method-access")
- enum { NSWindowOcclusionStateVisible = 1UL << 1 };
-#endif
+ } else if ([notificationName isEqualToString:NSWindowDidChangeOcclusionStateNotification]) {
// Several unit tests expect paint and/or expose events for windows that are
// sometimes (unpredictably) occluded and some unit tests depend on QWindow::isExposed -
// don't send Expose/Obscure events when running under QTestLib.
@@ -466,9 +438,6 @@ QT_WARNING_DISABLE_CLANG("-Wobjc-method-access")
m_platformWindow->obscureWindow();
}
}
-#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
-QT_WARNING_POP
-#endif
} else if (notificationName == NSWindowDidChangeScreenNotification) {
if (m_window) {
NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen];
@@ -525,7 +494,7 @@ QT_WARNING_POP
m_backingStore = backingStore;
m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio();
- foreach (QRect rect, region.rects())
+ for (const QRect &rect : region)
[self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
}
@@ -586,7 +555,7 @@ QT_WARNING_POP
- (void) drawRect:(NSRect)dirtyRect
{
- qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_window << qt_mac_toQRect(dirtyRect);
+ qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_window << QRectF::fromCGRect(dirtyRect);
#ifndef QT_NO_OPENGL
if (m_glContext && m_shouldSetGLContextinDrawRect) {
@@ -1395,7 +1364,6 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
[event magnification], windowPoint, screenPoint);
}
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
- (void)smartMagnifyWithEvent:(NSEvent *)event
{
static bool zoomIn = true;
@@ -1408,7 +1376,6 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
zoomIn ? 1.0f : 0.0f, windowPoint, screenPoint);
zoomIn = !zoomIn;
}
-#endif
- (void)rotateWithEvent:(NSEvent *)event
{
@@ -1524,16 +1491,12 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
NSEventPhase phase = [theEvent phase];
Qt::ScrollPhase ph = Qt::ScrollUpdate;
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
- if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
- // On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin.
- if (phase == NSEventPhaseMayBegin) {
- m_scrolling = true;
- ph = Qt::ScrollBegin;
- }
- }
-#endif
- if (phase == NSEventPhaseBegan) {
+
+ // MayBegin is likely to happen. We treat it the same as an actual begin.
+ if (phase == NSEventPhaseMayBegin) {
+ m_scrolling = true;
+ ph = Qt::ScrollBegin;
+ } else if (phase == NSEventPhaseBegan) {
// If MayBegin did not happen, Began is the actual beginning.
if (!m_scrolling)
ph = Qt::ScrollBegin;
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
index 395c25c915..759c4d26a5 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
@@ -88,10 +88,7 @@ static void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransfor
if (rgn.isEmpty()) {
CGContextAddRect(hd, CGRectMake(0, 0, 0, 0));
} else {
- QVector<QRect> rects = rgn.rects();
- const int count = rects.size();
- for (int i = 0; i < count; i++) {
- const QRect &r = rects[i];
+ for (const QRect &r : rgn) {
CGRect mac_r = CGRectMake(r.x(), r.y(), r.width(), r.height());
CGContextAddRect(hd, mac_r);
}
diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro
index 005a4da6db..f4c3b5cc3b 100644
--- a/src/plugins/platforms/direct2d/direct2d.pro
+++ b/src/plugins/platforms/direct2d/direct2d.pro
@@ -4,7 +4,7 @@ QT *= core-private
QT *= gui-private
QT *= platformsupport-private
-LIBS *= -ld2d1 -ld3d11 -ldwrite -lVersion -lgdi32
+LIBS += -ldwmapi -ld2d1 -ld3d11 -ldwrite -lVersion -lgdi32
include(../windows/windows.pri)
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
index 97eadb207b..38f2352934 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
@@ -95,7 +95,7 @@ void QWindowsDirect2DBackingStore::beginPaint(const QRegion &region)
painter.setCompositionMode(QPainter::CompositionMode_Source);
- foreach (const QRect &r, region.rects())
+ for (const QRect &r : region)
painter.fillRect(r, clear);
}
@@ -127,10 +127,14 @@ void QWindowsDirect2DBackingStore::resize(const QSize &size, const QRegion &regi
QPixmap *newPixmap = nativeWindow(window())->pixmap();
if (!old.isNull()) {
- foreach (const QRect &rect, region.rects()) {
+ for (const QRect &rect : region)
platformPixmap(newPixmap)->copy(old.handle(), rect);
- }
}
}
+QImage QWindowsDirect2DBackingStore::toImage() const
+{
+ return nativeWindow(window())->pixmap()->toImage();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h
index 9d754866cc..670c4e9840 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h
@@ -60,6 +60,8 @@ public:
QPaintDevice *paintDevice() Q_DECL_OVERRIDE;
void flush(QWindow *targetWindow, const QRegion &region, const QPoint &offset) Q_DECL_OVERRIDE;
void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE;
+
+ QImage toImage() const override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
index 4e677166b2..c750b02078 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
@@ -122,7 +122,7 @@ void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion
QRegion clipped = region;
clipped &= QRect(QPoint(), size);
- foreach (const QRect &rect, clipped.rects()) {
+ for (const QRect &rect : clipped) {
QRectF rectF(rect);
dc->DrawBitmap(bitmap->bitmap(),
to_d2d_rect_f(rectF),
diff --git a/src/plugins/platforms/directfb/qdirectfbbackingstore.cpp b/src/plugins/platforms/directfb/qdirectfbbackingstore.cpp
index 0bcf93aa3d..8d5e1e50c4 100644
--- a/src/plugins/platforms/directfb/qdirectfbbackingstore.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbbackingstore.cpp
@@ -70,9 +70,7 @@ void QDirectFbBackingStore::flush(QWindow *, const QRegion &region, const QPoint
{
m_pmdata->blittable()->unlock();
- QVector<QRect> rects = region.rects();
- for (int i = 0 ; i < rects.size(); i++) {
- const QRect rect = rects.at(i);
+ for (const QRect &rect : region) {
DFBRegion dfbReg(rect.x() + offset.x(),rect.y() + offset.y(),rect.right() + offset.x(),rect.bottom() + offset.y());
m_dfbSurface->Flip(m_dfbSurface.data(), &dfbReg, DFBSurfaceFlipFlags(DSFLIP_BLIT|DSFLIP_ONSYNC));
}
@@ -108,13 +106,15 @@ bool QDirectFbBackingStore::scroll(const QRegion &area, int dx, int dy)
if (area.rectCount() == 1) {
scrollSurface(m_dfbSurface.data(), area.boundingRect(), dx, dy);
} else {
- const QVector<QRect> rects = area.rects();
- const int n = rects.size();
- for (int i=0; i<n; ++i) {
- scrollSurface(m_dfbSurface.data(), rects.at(i), dx, dy);
- }
+ for (const QRect &rect : area)
+ scrollSurface(m_dfbSurface.data(), rect, dx, dy);
}
return true;
}
+QImage QDirectFbBackingStore::toImage() const
+{
+ return m_pixmap.data()->toImage();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/directfb/qdirectfbbackingstore.h b/src/plugins/platforms/directfb/qdirectfbbackingstore.h
index 33ab1c111d..af1ce92e64 100644
--- a/src/plugins/platforms/directfb/qdirectfbbackingstore.h
+++ b/src/plugins/platforms/directfb/qdirectfbbackingstore.h
@@ -59,6 +59,8 @@ public:
void resize (const QSize &size, const QRegion &staticContents);
bool scroll(const QRegion &area, int dx, int dy);
+ QImage toImage() const override;
+
private:
void lockSurfaceToImage();
diff --git a/src/plugins/platforms/eglfs/api/api.pri b/src/plugins/platforms/eglfs/api/api.pri
new file mode 100644
index 0000000000..957dee554c
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/api.pri
@@ -0,0 +1,15 @@
+
+SOURCES += $$PWD/qeglfswindow.cpp \
+ $$PWD/qeglfsscreen.cpp \
+ $$PWD/qeglfscursor.cpp \
+ $$PWD/qeglfshooks.cpp \
+ $$PWD/qeglfsdeviceintegration.cpp
+
+HEADERS += $$PWD/qeglfswindow_p.h \
+ $$PWD/qeglfsscreen_p.h \
+ $$PWD/qeglfscursor_p.h \
+ $$PWD/qeglfshooks_p.h \
+ $$PWD/qeglfsdeviceintegration_p.h \
+ $$PWD/qeglfsglobal.h
+
+INCLUDEPATH += $$PWD
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.cpp b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
index 6c8c35b1dc..ffee21a9b0 100644
--- a/src/plugins/platforms/eglfs/qeglfscursor.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
@@ -37,9 +37,9 @@
**
****************************************************************************/
-#include "qeglfscursor.h"
+#include "qeglfscursor_p.h"
#include "qeglfsintegration.h"
-#include "qeglfsscreen.h"
+#include "qeglfsscreen_p.h"
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QOpenGLContext>
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.h b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h
index bb30d53d6c..bb30d53d6c 100644
--- a/src/plugins/platforms/eglfs/qeglfscursor.h
+++ b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h
diff --git a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
index 5cbc5dbdb0..c6aab9d86c 100644
--- a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
@@ -37,10 +37,12 @@
**
****************************************************************************/
-#include "qeglfsdeviceintegration.h"
+#include "qeglfsdeviceintegration_p.h"
#include "qeglfsintegration.h"
-#include "qeglfscursor.h"
-#include "qeglfswindow.h"
+#include "qeglfscursor_p.h"
+#include "qeglfswindow_p.h"
+#include "qeglfshooks_p.h"
+
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QGuiApplication>
#include <private/qguiapplication_p.h>
@@ -64,14 +66,15 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(qLcEglDevDebug, "qt.qpa.egldeviceintegration")
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
- (QEGLDeviceIntegrationFactoryInterface_iid, QLatin1String("/egldeviceintegrations"), Qt::CaseInsensitive))
+ (QEglFSDeviceIntegrationFactoryInterface_iid, QLatin1String("/egldeviceintegrations"), Qt::CaseInsensitive))
#ifndef QT_NO_LIBRARY
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader,
- (QEGLDeviceIntegrationFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive))
+ (QEglFSDeviceIntegrationFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive))
+
#endif // QT_NO_LIBRARY
-QStringList QEGLDeviceIntegrationFactory::keys(const QString &pluginPath)
+QStringList QEglFSDeviceIntegrationFactory::keys(const QString &pluginPath)
{
QStringList list;
#ifndef QT_NO_LIBRARY
@@ -95,19 +98,19 @@ QStringList QEGLDeviceIntegrationFactory::keys(const QString &pluginPath)
return list;
}
-QEGLDeviceIntegration *QEGLDeviceIntegrationFactory::create(const QString &key, const QString &pluginPath)
+QEglFSDeviceIntegration *QEglFSDeviceIntegrationFactory::create(const QString &key, const QString &pluginPath)
{
- QEGLDeviceIntegration *integration = Q_NULLPTR;
+ QEglFSDeviceIntegration *integration = Q_NULLPTR;
#ifndef QT_NO_LIBRARY
if (!pluginPath.isEmpty()) {
QCoreApplication::addLibraryPath(pluginPath);
- integration = qLoadPlugin<QEGLDeviceIntegration, QEGLDeviceIntegrationPlugin>(directLoader(), key);
+ integration = qLoadPlugin<QEglFSDeviceIntegration, QEglFSDeviceIntegrationPlugin>(directLoader(), key);
}
#else
Q_UNUSED(pluginPath);
#endif
if (!integration)
- integration = qLoadPlugin<QEGLDeviceIntegration, QEGLDeviceIntegrationPlugin>(loader(), key);
+ integration = qLoadPlugin<QEglFSDeviceIntegration, QEglFSDeviceIntegrationPlugin>(loader(), key);
if (integration)
qCDebug(qLcEglDevDebug) << "Using EGL device integration" << key;
else
@@ -118,7 +121,7 @@ QEGLDeviceIntegration *QEGLDeviceIntegrationFactory::create(const QString &key,
static int framebuffer = -1;
-QByteArray QEGLDeviceIntegration::fbDeviceName() const
+QByteArray QEglFSDeviceIntegration::fbDeviceName() const
{
#ifdef Q_OS_LINUX
QByteArray fbDev = qgetenv("QT_QPA_EGLFS_FB");
@@ -131,7 +134,7 @@ QByteArray QEGLDeviceIntegration::fbDeviceName() const
#endif
}
-int QEGLDeviceIntegration::framebufferIndex() const
+int QEglFSDeviceIntegration::framebufferIndex() const
{
int fbIndex = 0;
#ifndef QT_NO_REGULAREXPRESSION
@@ -143,7 +146,7 @@ int QEGLDeviceIntegration::framebufferIndex() const
return fbIndex;
}
-void QEGLDeviceIntegration::platformInit()
+void QEglFSDeviceIntegration::platformInit()
{
#ifdef Q_OS_LINUX
QByteArray fbDev = fbDeviceName();
@@ -161,7 +164,7 @@ void QEGLDeviceIntegration::platformInit()
#endif
}
-void QEGLDeviceIntegration::platformDestroy()
+void QEglFSDeviceIntegration::platformDestroy()
{
#ifdef Q_OS_LINUX
if (framebuffer != -1)
@@ -169,27 +172,27 @@ void QEGLDeviceIntegration::platformDestroy()
#endif
}
-EGLNativeDisplayType QEGLDeviceIntegration::platformDisplay() const
+EGLNativeDisplayType QEglFSDeviceIntegration::platformDisplay() const
{
return EGL_DEFAULT_DISPLAY;
}
-EGLDisplay QEGLDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
+EGLDisplay QEglFSDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
{
return eglGetDisplay(nativeDisplay);
}
-bool QEGLDeviceIntegration::usesDefaultScreen()
+bool QEglFSDeviceIntegration::usesDefaultScreen()
{
return true;
}
-void QEGLDeviceIntegration::screenInit()
+void QEglFSDeviceIntegration::screenInit()
{
// Nothing to do here. Called only when usesDefaultScreen is false.
}
-void QEGLDeviceIntegration::screenDestroy()
+void QEglFSDeviceIntegration::screenDestroy()
{
QGuiApplication *app = qGuiApp;
QEglFSIntegration *platformIntegration = static_cast<QEglFSIntegration *>(
@@ -198,17 +201,17 @@ void QEGLDeviceIntegration::screenDestroy()
platformIntegration->removeScreen(app->screens().last()->handle());
}
-QSizeF QEGLDeviceIntegration::physicalScreenSize() const
+QSizeF QEglFSDeviceIntegration::physicalScreenSize() const
{
return q_physicalScreenSizeFromFb(framebuffer, screenSize());
}
-QSize QEGLDeviceIntegration::screenSize() const
+QSize QEglFSDeviceIntegration::screenSize() const
{
return q_screenSizeFromFb(framebuffer);
}
-QDpi QEGLDeviceIntegration::logicalDpi() const
+QDpi QEglFSDeviceIntegration::logicalDpi() const
{
const QSizeF ps = physicalScreenSize();
const QSize s = screenSize();
@@ -220,42 +223,42 @@ QDpi QEGLDeviceIntegration::logicalDpi() const
return QDpi(100, 100);
}
-qreal QEGLDeviceIntegration::pixelDensity() const
+qreal QEglFSDeviceIntegration::pixelDensity() const
{
return qRound(logicalDpi().first / qreal(100));
}
-Qt::ScreenOrientation QEGLDeviceIntegration::nativeOrientation() const
+Qt::ScreenOrientation QEglFSDeviceIntegration::nativeOrientation() const
{
return Qt::PrimaryOrientation;
}
-Qt::ScreenOrientation QEGLDeviceIntegration::orientation() const
+Qt::ScreenOrientation QEglFSDeviceIntegration::orientation() const
{
return Qt::PrimaryOrientation;
}
-int QEGLDeviceIntegration::screenDepth() const
+int QEglFSDeviceIntegration::screenDepth() const
{
return q_screenDepthFromFb(framebuffer);
}
-QImage::Format QEGLDeviceIntegration::screenFormat() const
+QImage::Format QEglFSDeviceIntegration::screenFormat() const
{
return screenDepth() == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
}
-qreal QEGLDeviceIntegration::refreshRate() const
+qreal QEglFSDeviceIntegration::refreshRate() const
{
return q_refreshRateFromFb(framebuffer);
}
-EGLint QEGLDeviceIntegration::surfaceType() const
+EGLint QEglFSDeviceIntegration::surfaceType() const
{
return EGL_WINDOW_BIT;
}
-QSurfaceFormat QEGLDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
+QSurfaceFormat QEglFSDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
{
QSurfaceFormat format = inputFormat;
@@ -269,17 +272,17 @@ QSurfaceFormat QEGLDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inp
return format;
}
-bool QEGLDeviceIntegration::filterConfig(EGLDisplay, EGLConfig) const
+bool QEglFSDeviceIntegration::filterConfig(EGLDisplay, EGLConfig) const
{
return true;
}
-QEglFSWindow *QEGLDeviceIntegration::createWindow(QWindow *window) const
+QEglFSWindow *QEglFSDeviceIntegration::createWindow(QWindow *window) const
{
return new QEglFSWindow(window);
}
-EGLNativeWindowType QEGLDeviceIntegration::createNativeWindow(QPlatformWindow *platformWindow,
+EGLNativeWindowType QEglFSDeviceIntegration::createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size,
const QSurfaceFormat &format)
{
@@ -289,29 +292,29 @@ EGLNativeWindowType QEGLDeviceIntegration::createNativeWindow(QPlatformWindow *p
return 0;
}
-EGLNativeWindowType QEGLDeviceIntegration::createNativeOffscreenWindow(const QSurfaceFormat &format)
+EGLNativeWindowType QEglFSDeviceIntegration::createNativeOffscreenWindow(const QSurfaceFormat &format)
{
Q_UNUSED(format);
return 0;
}
-void QEGLDeviceIntegration::destroyNativeWindow(EGLNativeWindowType window)
+void QEglFSDeviceIntegration::destroyNativeWindow(EGLNativeWindowType window)
{
Q_UNUSED(window);
}
-bool QEGLDeviceIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+bool QEglFSDeviceIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
Q_UNUSED(cap);
return false;
}
-QPlatformCursor *QEGLDeviceIntegration::createCursor(QPlatformScreen *screen) const
+QPlatformCursor *QEglFSDeviceIntegration::createCursor(QPlatformScreen *screen) const
{
return new QEglFSCursor(screen);
}
-void QEGLDeviceIntegration::waitForVSync(QPlatformSurface *surface) const
+void QEglFSDeviceIntegration::waitForVSync(QPlatformSurface *surface) const
{
Q_UNUSED(surface);
@@ -325,24 +328,42 @@ void QEGLDeviceIntegration::waitForVSync(QPlatformSurface *surface) const
#endif
}
-void QEGLDeviceIntegration::presentBuffer(QPlatformSurface *surface)
+void QEglFSDeviceIntegration::presentBuffer(QPlatformSurface *surface)
{
Q_UNUSED(surface);
}
-bool QEGLDeviceIntegration::supportsPBuffers() const
+bool QEglFSDeviceIntegration::supportsPBuffers() const
{
return true;
}
-bool QEGLDeviceIntegration::supportsSurfacelessContexts() const
+bool QEglFSDeviceIntegration::supportsSurfacelessContexts() const
{
return true;
}
-void *QEGLDeviceIntegration::wlDisplay() const
+void *QEglFSDeviceIntegration::wlDisplay() const
{
return Q_NULLPTR;
}
+EGLConfig QEglFSDeviceIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format)
+{
+ class Chooser : public QEglConfigChooser {
+ public:
+ Chooser(EGLDisplay display)
+ : QEglConfigChooser(display) { }
+ bool filterConfig(EGLConfig config) const Q_DECL_OVERRIDE {
+ return qt_egl_device_integration()->filterConfig(display(), config)
+ && QEglConfigChooser::filterConfig(config);
+ }
+ };
+
+ Chooser chooser(display);
+ chooser.setSurfaceType(qt_egl_device_integration()->surfaceType());
+ chooser.setSurfaceFormat(format);
+ return chooser.chooseConfig();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h
index f1a5bde331..819e4818ab 100644
--- a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h
@@ -63,12 +63,12 @@ QT_BEGIN_NAMESPACE
class QPlatformSurface;
class QEglFSWindow;
-#define QEGLDeviceIntegrationFactoryInterface_iid "org.qt-project.qt.qpa.egl.QEGLDeviceIntegrationFactoryInterface.5.5"
+#define QEglFSDeviceIntegrationFactoryInterface_iid "org.qt-project.qt.qpa.egl.QEglFSDeviceIntegrationFactoryInterface.5.5"
-class Q_EGLFS_EXPORT QEGLDeviceIntegration
+class Q_EGLFS_EXPORT QEglFSDeviceIntegration
{
public:
- virtual ~QEGLDeviceIntegration() { }
+ virtual ~QEglFSDeviceIntegration() { }
virtual void platformInit();
virtual void platformDestroy();
@@ -105,25 +105,27 @@ public:
virtual bool supportsSurfacelessContexts() const;
virtual void *wlDisplay() const;
+
+ static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format);
};
-class Q_EGLFS_EXPORT QEGLDeviceIntegrationPlugin : public QObject
+class Q_EGLFS_EXPORT QEglFSDeviceIntegrationPlugin : public QObject
{
Q_OBJECT
public:
- virtual QEGLDeviceIntegration *create() = 0;
+ virtual QEglFSDeviceIntegration *create() = 0;
// the pattern expected by qLoadPlugin calls for a QString argument.
// we don't need it, so don't bother subclasses with it:
- QEGLDeviceIntegration *create(const QString &) { return create(); }
+ QEglFSDeviceIntegration *create(const QString &) { return create(); }
};
-class Q_EGLFS_EXPORT QEGLDeviceIntegrationFactory
+class Q_EGLFS_EXPORT QEglFSDeviceIntegrationFactory
{
public:
static QStringList keys(const QString &pluginPath = QString());
- static QEGLDeviceIntegration *create(const QString &name, const QString &platformPluginPath = QString());
+ static QEglFSDeviceIntegration *create(const QString &name, const QString &platformPluginPath = QString());
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfsglobal.h b/src/plugins/platforms/eglfs/api/qeglfsglobal.h
index d6aba565ce..2b5effc2f1 100644
--- a/src/plugins/platforms/eglfs/qeglfsglobal.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsglobal.h
@@ -40,7 +40,11 @@
#ifndef QEGLFSGLOBAL_H
#define QEGLFSGLOBAL_H
-#include <qglobal.h>
+#include <QtCore/qglobal.h>
+
+#include <EGL/egl.h>
+
+QT_BEGIN_NAMESPACE
#ifdef QT_BUILD_EGL_DEVICE_LIB
#define Q_EGLFS_EXPORT Q_DECL_EXPORT
@@ -48,7 +52,6 @@
#define Q_EGLFS_EXPORT Q_DECL_IMPORT
#endif
-#include <EGL/egl.h>
#undef Status
#undef None
#undef Bool
@@ -61,4 +64,6 @@
#undef Expose
#undef Unsorted
+QT_END_NAMESPACE
+
#endif
diff --git a/src/plugins/platforms/eglfs/qeglfshooks.cpp b/src/plugins/platforms/eglfs/api/qeglfshooks.cpp
index 87285428df..b67d8fab54 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfshooks.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "qeglfshooks.h"
+#include "qeglfshooks_p.h"
#include <QLoggingCategory>
QT_BEGIN_NAMESPACE
@@ -46,7 +46,7 @@ Q_DECLARE_LOGGING_CATEGORY(qLcEglDevDebug)
#ifdef EGLFS_PLATFORM_HOOKS
-QEGLDeviceIntegration *qt_egl_device_integration()
+QEglFSDeviceIntegration *qt_egl_device_integration()
{
extern QEglFSHooks *platformHooks;
return platformHooks;
@@ -59,16 +59,16 @@ class DeviceIntegration
public:
DeviceIntegration();
~DeviceIntegration() { delete m_integration; }
- QEGLDeviceIntegration *integration() { return m_integration; }
+ QEglFSDeviceIntegration *integration() { return m_integration; }
private:
- QEGLDeviceIntegration *m_integration;
+ QEglFSDeviceIntegration *m_integration;
};
Q_GLOBAL_STATIC(DeviceIntegration, deviceIntegration)
DeviceIntegration::DeviceIntegration() : m_integration(0)
{
- QStringList pluginKeys = QEGLDeviceIntegrationFactory::keys();
+ QStringList pluginKeys = QEglFSDeviceIntegrationFactory::keys();
if (!pluginKeys.isEmpty()) {
// Some built-in logic: Prioritize either X11 or KMS/DRM.
if (qEnvironmentVariableIsSet("DISPLAY")) {
@@ -113,7 +113,7 @@ DeviceIntegration::DeviceIntegration() : m_integration(0)
while (!m_integration && !pluginKeys.isEmpty()) {
QString key = pluginKeys.takeFirst();
qCDebug(qLcEglDevDebug) << "Trying to load device EGL integration" << key;
- m_integration = QEGLDeviceIntegrationFactory::create(key);
+ m_integration = QEglFSDeviceIntegrationFactory::create(key);
}
}
}
@@ -122,11 +122,11 @@ DeviceIntegration::DeviceIntegration() : m_integration(0)
// Use a default, non-specialized device integration when no plugin is available.
// For some systems this is sufficient.
qCDebug(qLcEglDevDebug) << "Using base device integration";
- m_integration = new QEGLDeviceIntegration;
+ m_integration = new QEglFSDeviceIntegration;
}
}
-QEGLDeviceIntegration *qt_egl_device_integration()
+QEglFSDeviceIntegration *qt_egl_device_integration()
{
return deviceIntegration()->integration();
}
diff --git a/src/plugins/platforms/eglfs/qeglfshooks.h b/src/plugins/platforms/eglfs/api/qeglfshooks_p.h
index cc6c325b58..e379f7a76d 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks.h
+++ b/src/plugins/platforms/eglfs/api/qeglfshooks_p.h
@@ -40,16 +40,27 @@
#ifndef QEGLFSHOOKS_H
#define QEGLFSHOOKS_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 "qeglfsglobal.h"
-#include "qeglfsdeviceintegration.h"
+#include "qeglfsdeviceintegration_p.h"
QT_BEGIN_NAMESPACE
-class QEglFSHooks : public QEGLDeviceIntegration
+class QEglFSHooks : public QEglFSDeviceIntegration
{
};
-Q_EGLFS_EXPORT QEGLDeviceIntegration *qt_egl_device_integration();
+Q_EGLFS_EXPORT QEglFSDeviceIntegration *qt_egl_device_integration();
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
index a1ab854db1..d636a783ec 100644
--- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
@@ -43,9 +43,9 @@
#include <qpa/qplatformcursor.h>
#include <QtPlatformSupport/private/qopenglcompositor_p.h>
-#include "qeglfsscreen.h"
-#include "qeglfswindow.h"
-#include "qeglfshooks.h"
+#include "qeglfsscreen_p.h"
+#include "qeglfswindow_p.h"
+#include "qeglfshooks_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h
index 57d68ca572..092d853ffd 100644
--- a/src/plugins/platforms/eglfs/qeglfsscreen.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h
@@ -40,9 +40,22 @@
#ifndef QEGLFSSCREEN_H
#define QEGLFSSCREEN_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 "qeglfsglobal.h"
#include <QtCore/QPointer>
+#include <qpa/qplatformscreen.h>
+
QT_BEGIN_NAMESPACE
class QEglFSWindow;
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
index 556d3942cd..f602c1b976 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
@@ -46,9 +46,10 @@
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QtPlatformSupport/private/qopenglcompositorbackingstore_p.h>
-#include "qeglfswindow.h"
-#include "qeglfscursor.h"
-#include "qeglfshooks.h"
+#include "qeglfswindow_p.h"
+#include "qeglfscursor_p.h"
+#include "qeglfshooks_p.h"
+#include "qeglfsdeviceintegration_p.h"
QT_BEGIN_NAMESPACE
@@ -186,7 +187,7 @@ void QEglFSWindow::resetSurface()
EGLDisplay display = screen()->display();
QSurfaceFormat platformFormat = qt_egl_device_integration()->surfaceFormatFor(window()->requestedFormat());
- m_config = QEglFSIntegration::chooseConfig(display, platformFormat);
+ m_config = QEglFSDeviceIntegration::chooseConfig(display, platformFormat);
m_format = q_glFormatFromConfig(display, m_config, platformFormat);
m_window = qt_egl_device_integration()->createNativeWindow(this, screen()->geometry().size(), m_format);
m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL);
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
index d607c8bd62..aea4ed4806 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.h
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
@@ -40,9 +40,20 @@
#ifndef QEGLFSWINDOW_H
#define QEGLFSWINDOW_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 "qeglfsglobal.h"
#include "qeglfsintegration.h"
-#include "qeglfsscreen.h"
+#include "qeglfsscreen_p.h"
#include <qpa/qplatformwindow.h>
#include <QtPlatformSupport/private/qopenglcompositor_p.h>
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro
index e2ebf9f7ee..cd97c2c5a3 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro
@@ -1,6 +1,6 @@
TARGET = qeglfs-brcm-integration
-QT += core-private gui-private platformsupport-private eglfs_device_lib-private
+QT += core-private gui-private platformsupport-private eglfsdeviceintegration-private
INCLUDEPATH += $$PWD/../..
CONFIG += egl
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h
index 8f78b51190..5af628dedd 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h
@@ -40,11 +40,11 @@
#ifndef QEGLFSBRCMINTEGRATION_H
#define QEGLFSBRCMINTEGRATION_H
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
QT_BEGIN_NAMESPACE
-class QEglFSBrcmIntegration : public QEGLDeviceIntegration
+class QEglFSBrcmIntegration : public QEglFSDeviceIntegration
{
public:
void platformInit() Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp
index 0bd54ba239..80d7631931 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp
@@ -37,18 +37,18 @@
**
****************************************************************************/
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsbrcmintegration.h"
QT_BEGIN_NAMESPACE
-class QEglFSBrcmIntegrationPlugin : public QEGLDeviceIntegrationPlugin
+class QEglFSBrcmIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID QEGLDeviceIntegrationFactoryInterface_iid FILE "eglfs_brcm.json")
+ Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_brcm.json")
public:
- QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSBrcmIntegration; }
+ QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSBrcmIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
index 979bfe3ea9..b0d631a9d1 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
@@ -4,7 +4,7 @@ PLUGIN_TYPE = egldeviceintegrations
PLUGIN_CLASS_NAME = QEglFSKmsGbmIntegrationPlugin
load(qt_plugin)
-QT += core-private gui-private platformsupport-private eglfs_device_lib-private eglfs_kms_support-private
+QT += core-private gui-private platformsupport-private eglfsdeviceintegration-private eglfs_kms_support-private
INCLUDEPATH += $$PWD/../.. $$PWD/../eglfs_kms_support
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
index 1c0a8e1b5f..a5ab73cca4 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
@@ -43,7 +43,7 @@
#include "qeglfskmsgbmdevice.h"
#include "qeglfskmsgbmscreen.h"
#include "qeglfskmsgbmcursor.h"
-#include "qeglfscursor.h"
+#include "private/qeglfscursor_p.h"
#include <QtPlatformSupport/private/qdevicediscovery_p.h>
#include <QtCore/QLoggingCategory>
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp
index 8e8779ca10..f34e4859c6 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp
@@ -38,18 +38,18 @@
**
****************************************************************************/
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfskmsgbmintegration.h"
QT_BEGIN_NAMESPACE
-class QEglFSKmsGbmIntegrationPlugin : public QEGLDeviceIntegrationPlugin
+class QEglFSKmsGbmIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID QEGLDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms.json")
+ Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms.json")
public:
- QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsGbmIntegration; }
+ QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsGbmIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
index 3a380b7525..8eabd2d4b7 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
@@ -1,6 +1,6 @@
TARGET = qeglfs-kms-egldevice-integration
-QT += core-private gui-private platformsupport-private eglfs_device_lib-private eglfs_kms_support-private
+QT += core-private gui-private platformsupport-private eglfsdeviceintegration-private eglfs_kms_support-private
INCLUDEPATH += $$PWD/../.. $$PWD/../eglfs_kms_support
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
index 838569d5c6..28967d71ff 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
@@ -40,7 +40,7 @@
#include "qeglfskmsegldeviceintegration.h"
#include <QtPlatformSupport/private/qeglconvenience_p.h>
-#include "qeglfswindow.h"
+#include "private/qeglfswindow_p.h"
#include "qeglfskmsegldevice.h"
#include "qeglfskmsscreen.h"
#include <QLoggingCategory>
@@ -189,7 +189,7 @@ void QEglJetsonTK1Window::resetSurface()
if (!m_integration->m_funcs->stream_consumer_output(display, m_egl_stream, layer))
qWarning("resetSurface: Unable to connect stream");
- m_config = QEglFSIntegration::chooseConfig(display, m_integration->surfaceFormatFor(window()->requestedFormat()));
+ m_config = QEglFSDeviceIntegration::chooseConfig(display, m_integration->surfaceFormatFor(window()->requestedFormat()));
m_format = q_glFormatFromConfig(display, m_config);
qCDebug(qLcEglfsKmsDebug) << "Stream producer format is" << m_format;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
index 63571f796f..42fec073f1 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
@@ -41,13 +41,13 @@
QT_BEGIN_NAMESPACE
-class QEglFSKmsEglDeviceIntegrationPlugin : public QEGLDeviceIntegrationPlugin
+class QEglFSKmsEglDeviceIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID QEGLDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms_egldevice.json")
+ Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms_egldevice.json")
public:
- QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsEglDeviceIntegration; }
+ QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsEglDeviceIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
index 6355fe6abd..6dd857a4e4 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
@@ -2,7 +2,7 @@ TARGET = QtEglFsKmsSupport
CONFIG += no_module_headers internal_module
load(qt_module)
-QT += core-private gui-private platformsupport-private eglfs_device_lib-private
+QT += core-private gui-private platformsupport-private eglfsdeviceintegration-private
INCLUDEPATH += $$PWD/../..
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
index 07ea7d4439..7389050efc 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
@@ -42,8 +42,8 @@
#include "qeglfskmsintegration.h"
#include "qeglfskmsdevice.h"
#include "qeglfskmsscreen.h"
-#include "qeglfswindow.h"
-#include "qeglfscursor.h"
+#include "private/qeglfswindow_p.h"
+#include "private/qeglfscursor_p.h"
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QtCore/QJsonDocument>
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
index 34ac5385a5..81386881ff 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
@@ -42,7 +42,7 @@
#ifndef QEGLFSKMSINTEGRATION_H
#define QEGLFSKMSINTEGRATION_H
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
#include <QtCore/QMap>
#include <QtCore/QVariant>
#include <QtCore/QLoggingCategory>
@@ -53,7 +53,7 @@ class QEglFSKmsDevice;
Q_EGLFS_EXPORT Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-class Q_EGLFS_EXPORT QEglFSKmsIntegration : public QEGLDeviceIntegration
+class Q_EGLFS_EXPORT QEglFSKmsIntegration : public QEglFSDeviceIntegration
{
public:
QEglFSKmsIntegration();
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
index aa698e1b5d..9679f70260 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
@@ -43,7 +43,7 @@
#define QEGLFSKMSSCREEN_H
#include "qeglfskmsintegration.h"
-#include "qeglfsscreen.h"
+#include "private/qeglfsscreen_p.h"
#include <QtCore/QList>
#include <QtCore/QMutex>
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro
index 7fc4568ae3..1e58b5fdcd 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro
@@ -1,6 +1,6 @@
TARGET = qeglfs-mali-integration
-QT += core-private gui-private platformsupport-private eglfs_device_lib-private
+QT += core-private gui-private platformsupport-private eglfsdeviceintegration-private
# Avoid X11 header collision
DEFINES += MESA_EGL_NO_X11_HEADERS
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp
index ffdb7a686b..cd468c989f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp
@@ -56,7 +56,7 @@ struct fbdev_window {
void QEglFSMaliIntegration::platformInit()
{
// Keep the non-overridden base class functions based on fb0 working.
- QEGLDeviceIntegration::platformInit();
+ QEglFSDeviceIntegration::platformInit();
int fd = qt_safe_open("/dev/fb0", O_RDWR, 0);
if (fd == -1)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h
index 35a2c64951..56883a3676 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h
@@ -40,11 +40,11 @@
#ifndef QEGLFSMALIINTEGRATION_H
#define QEGLFSMALIINTEGRATION_H
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
QT_BEGIN_NAMESPACE
-class QEglFSMaliIntegration : public QEGLDeviceIntegration
+class QEglFSMaliIntegration : public QEglFSDeviceIntegration
{
public:
void platformInit() Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp
index 0754e1af5b..a3c804f54d 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp
@@ -37,18 +37,18 @@
**
****************************************************************************/
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsmaliintegration.h"
QT_BEGIN_NAMESPACE
-class QEglFSMaliIntegrationPlugin : public QEGLDeviceIntegrationPlugin
+class QEglFSMaliIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID QEGLDeviceIntegrationFactoryInterface_iid FILE "eglfs_mali.json")
+ Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_mali.json")
public:
- QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSMaliIntegration; }
+ QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSMaliIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro
index 6fac2f529a..a53aac2041 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro
@@ -1,6 +1,6 @@
TARGET = qeglfs-viv-integration
-QT += core-private gui-private platformsupport-private eglfs_device_lib-private
+QT += core-private gui-private platformsupport-private eglfsdeviceintegration-private
INCLUDEPATH += $$PWD/../..
CONFIG += egl
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp
index ca97f6c8f9..f2fcc0d3ff 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp
@@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE
void QEglFSVivIntegration::platformInit()
{
- QEGLDeviceIntegration::platformInit();
+ QEglFSDeviceIntegration::platformInit();
int width, height;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h
index 4a8cd5c385..2e98c2b4b1 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h
@@ -40,11 +40,11 @@
#ifndef QEGLFSVIVINTEGRATION_H
#define QEGLFSVIVINTEGRATION_H
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
QT_BEGIN_NAMESPACE
-class QEglFSVivIntegration : public QEGLDeviceIntegration
+class QEglFSVivIntegration : public QEglFSDeviceIntegration
{
public:
void platformInit() Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp
index d1c9fb4086..ebe2091b1e 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp
@@ -37,18 +37,18 @@
**
****************************************************************************/
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsvivintegration.h"
QT_BEGIN_NAMESPACE
-class QEglFSVivIntegrationPlugin : public QEGLDeviceIntegrationPlugin
+class QEglFSVivIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID QEGLDeviceIntegrationFactoryInterface_iid FILE "eglfs_viv.json")
+ Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_viv.json")
public:
- QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSVivIntegration; }
+ QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSVivIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/eglfs_viv_wl.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/eglfs_viv_wl.pro
index 44f75c40e0..38259f4a5d 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/eglfs_viv_wl.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/eglfs_viv_wl.pro
@@ -1,6 +1,6 @@
TARGET = qeglfs-viv-wl-integration
-QT += core-private gui-private platformsupport-private eglfs_device_lib-private
+QT += core-private gui-private platformsupport-private eglfsdeviceintegration-private
INCLUDEPATH += $$PWD/../..
CONFIG += egl
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp
index 5c113456e4..61e2f17766 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp
@@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE
void QEglFSVivWaylandIntegration::platformInit()
{
- QEGLDeviceIntegration::platformInit();
+ QEglFSDeviceIntegration::platformInit();
int width, height;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h
index 40eacc8f2f..9abbe817a6 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h
@@ -40,12 +40,12 @@
#ifndef QEGLFSVIVINTEGRATION_H
#define QEGLFSVIVINTEGRATION_H
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
struct wl_display;
QT_BEGIN_NAMESPACE
-class QEglFSVivWaylandIntegration : public QEGLDeviceIntegration
+class QEglFSVivWaylandIntegration : public QEglFSDeviceIntegration
{
public:
void platformInit() Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp
index 02ef9c566c..3b26feda07 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp
@@ -37,18 +37,18 @@
**
****************************************************************************/
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsvivwlintegration.h"
QT_BEGIN_NAMESPACE
-class QEglFSVivWaylandIntegrationPlugin : public QEGLDeviceIntegrationPlugin
+class QEglFSVivWaylandIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID QEGLDeviceIntegrationFactoryInterface_iid FILE "eglfs_viv_wl.json")
+ Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_viv_wl.json")
public:
- QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSVivWaylandIntegration; }
+ QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSVivWaylandIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro
index 83f0c74910..21af6eb736 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro
@@ -1,6 +1,6 @@
TARGET = qeglfs-x11-integration
-QT += core-private gui-private platformsupport-private eglfs_device_lib-private
+QT += core-private gui-private platformsupport-private eglfsdeviceintegration-private
# Avoid X11 header collision
DEFINES += MESA_EGL_NO_X11_HEADERS
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h
index a3d0b01baf..c0f0ee5f22 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h
@@ -40,7 +40,7 @@
#ifndef QEGLFSX11INTEGRATION_H
#define QEGLFSX11INTEGRATION_H
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformwindow.h>
@@ -64,7 +64,7 @@ namespace Atoms {
class EventReader;
-class QEglFSX11Integration : public QEGLDeviceIntegration
+class QEglFSX11Integration : public QEglFSDeviceIntegration
{
public:
QEglFSX11Integration() : m_connection(0), m_window(0), m_eventReader(0) {}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp
index 314a85694b..c15e05b657 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp
@@ -37,18 +37,18 @@
**
****************************************************************************/
-#include "qeglfsdeviceintegration.h"
+#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsx11integration.h"
QT_BEGIN_NAMESPACE
-class QEglFSX11IntegrationPlugin : public QEGLDeviceIntegrationPlugin
+class QEglFSX11IntegrationPlugin : public QEglFSDeviceIntegrationPlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID QEGLDeviceIntegrationFactoryInterface_iid FILE "eglfs_x11.json")
+ Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_x11.json")
public:
- QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSX11Integration; }
+ QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSX11Integration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/eglfs-plugin.pro b/src/plugins/platforms/eglfs/eglfs-plugin.pro
index a628cdccd9..90b8a9fb32 100644
--- a/src/plugins/platforms/eglfs/eglfs-plugin.pro
+++ b/src/plugins/platforms/eglfs/eglfs-plugin.pro
@@ -1,6 +1,6 @@
TARGET = qeglfs
-QT += platformsupport-private eglfs_device_lib-private
+QT += platformsupport-private eglfsdeviceintegration-private
SOURCES += $$PWD/qeglfsmain.cpp
diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro
index 03c96ca1d9..d91ffd60a1 100644
--- a/src/plugins/platforms/eglfs/eglfs.pro
+++ b/src/plugins/platforms/eglfs/eglfs.pro
@@ -1,6 +1,6 @@
TEMPLATE = subdirs
CONFIG += ordered
-SUBDIRS += eglfs_device_lib.pro
+SUBDIRS += eglfsdeviceintegration.pro
SUBDIRS += eglfs-plugin.pro
SUBDIRS += deviceintegration
diff --git a/src/plugins/platforms/eglfs/eglfs_device_lib.pro b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro
index f784020fb6..05f4196728 100644
--- a/src/plugins/platforms/eglfs/eglfs_device_lib.pro
+++ b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro
@@ -3,8 +3,9 @@
# have to keep the QObject magic like qobject_cast working.
# Hence this header-less, private-only module.
-TARGET = QtEglDeviceIntegration
-CONFIG += no_module_headers internal_module
+TARGET = QtEglFSDeviceIntegration
+CONFIG += internal_module
+MODULE = eglfsdeviceintegration
QT += core-private gui-private platformsupport-private
LIBS += $$QMAKE_LIBS_DYNLOAD
@@ -15,22 +16,14 @@ DEFINES += MESA_EGL_NO_X11_HEADERS
DEFINES += QT_BUILD_EGL_DEVICE_LIB
SOURCES += $$PWD/qeglfsintegration.cpp \
- $$PWD/qeglfswindow.cpp \
- $$PWD/qeglfsscreen.cpp \
- $$PWD/qeglfscursor.cpp \
- $$PWD/qeglfshooks.cpp \
$$PWD/qeglfscontext.cpp \
$$PWD/qeglfsoffscreenwindow.cpp \
- $$PWD/qeglfsdeviceintegration.cpp
HEADERS += $$PWD/qeglfsintegration.h \
- $$PWD/qeglfswindow.h \
- $$PWD/qeglfsscreen.h \
- $$PWD/qeglfscursor.h \
- $$PWD/qeglfshooks.h \
$$PWD/qeglfscontext.h \
$$PWD/qeglfsoffscreenwindow.h \
- $$PWD/qeglfsdeviceintegration.h
+
+include($$PWD/api/api.pri)
QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp
index 6acb362bf0..8d479873cf 100644
--- a/src/plugins/platforms/eglfs/qeglfscontext.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp
@@ -43,9 +43,9 @@
#include <QtPlatformSupport/private/qeglpbuffer_p.h>
#include "qeglfscontext.h"
-#include "qeglfswindow.h"
-#include "qeglfshooks.h"
-#include "qeglfscursor.h"
+#include "qeglfswindow_p.h"
+#include "qeglfshooks_p.h"
+#include "qeglfscursor_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
index 6f38a96f45..8c8ef99bc2 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
@@ -52,11 +52,11 @@
#include <private/qgenericunixthemes_p.h>
#include "qeglfsintegration.h"
-#include "qeglfswindow.h"
-#include "qeglfshooks.h"
+#include "qeglfswindow_p.h"
+#include "qeglfshooks_p.h"
#include "qeglfscontext.h"
#include "qeglfsoffscreenwindow.h"
-#include "qeglfscursor.h"
+#include "qeglfscursor_p.h"
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
@@ -205,7 +205,7 @@ QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLCo
QEglFSContext *ctx;
QSurfaceFormat adjustedFormat = qt_egl_device_integration()->surfaceFormatFor(context->format());
if (nativeHandle.isNull()) {
- EGLConfig config = QEglFSIntegration::chooseConfig(dpy, adjustedFormat);
+ EGLConfig config = QEglFSDeviceIntegration::chooseConfig(dpy, adjustedFormat);
ctx = new QEglFSContext(adjustedFormat, share, dpy, &config, QVariant());
} else {
ctx = new QEglFSContext(adjustedFormat, share, dpy, 0, nativeHandle);
@@ -436,22 +436,4 @@ EGLNativeDisplayType QEglFSIntegration::nativeDisplay() const
return qt_egl_device_integration()->platformDisplay();
}
-EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format)
-{
- class Chooser : public QEglConfigChooser {
- public:
- Chooser(EGLDisplay display)
- : QEglConfigChooser(display) { }
- bool filterConfig(EGLConfig config) const Q_DECL_OVERRIDE {
- return qt_egl_device_integration()->filterConfig(display(), config)
- && QEglConfigChooser::filterConfig(config);
- }
- };
-
- Chooser chooser(display);
- chooser.setSurfaceType(qt_egl_device_integration()->surfaceType());
- chooser.setSurfaceFormat(format);
- return chooser.chooseConfig();
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h
index 678452a8db..9c5439a22f 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.h
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.h
@@ -92,8 +92,6 @@ public:
void addScreen(QPlatformScreen *screen);
void removeScreen(QPlatformScreen *screen);
- static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format);
-
private:
EGLNativeDisplayType nativeDisplay() const;
void createInputHandlers();
diff --git a/src/plugins/platforms/eglfs/qeglfsoffscreenwindow.cpp b/src/plugins/platforms/eglfs/qeglfsoffscreenwindow.cpp
index 11b101970b..0334ac9785 100644
--- a/src/plugins/platforms/eglfs/qeglfsoffscreenwindow.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsoffscreenwindow.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qeglfsoffscreenwindow.h"
-#include "qeglfshooks.h"
+#include "qeglfshooks_p.h"
#include <QtGui/QOffscreenSurface>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro
index 7b0a573ffa..2c85a68f0b 100644
--- a/src/plugins/platforms/ios/ios.pro
+++ b/src/plugins/platforms/ios/ios.pro
@@ -1,7 +1,7 @@
TARGET = qios
QT += core-private gui-private platformsupport-private
-LIBS += -framework Foundation -framework UIKit -framework QuartzCore -framework AssetsLibrary -framework AudioToolbox
+LIBS += -framework Foundation -framework UIKit -framework QuartzCore -framework AudioToolbox
OBJECTIVE_SOURCES = \
plugin.mm \
@@ -19,15 +19,9 @@ OBJECTIVE_SOURCES = \
qiosglobal.mm \
qiosservices.mm \
quiview.mm \
- qiosclipboard.mm \
quiaccessibilityelement.mm \
qiosplatformaccessibility.mm \
- qiostextresponder.mm \
- qiosmenu.mm \
- qiosfileengineassetslibrary.mm \
- qiosfiledialog.mm \
- qiosmessagedialog.mm \
- qiostextinputoverlay.mm
+ qiostextresponder.mm
HEADERS = \
qiosintegration.h \
@@ -44,16 +38,28 @@ HEADERS = \
qiosglobal.h \
qiosservices.h \
quiview.h \
- qiosclipboard.h \
quiaccessibilityelement.h \
qiosplatformaccessibility.h \
qiostextresponder.h \
- qiosmenu.h \
- qiosfileenginefactory.h \
- qiosfileengineassetslibrary.h \
- qiosfiledialog.h \
- qiosmessagedialog.h \
- qiostextinputoverlay.h
+ qiosfileenginefactory.h
+
+!tvos {
+ LIBS += -framework AssetsLibrary
+ OBJECTIVE_SOURCES += \
+ qiosclipboard.mm \
+ qiosmenu.mm \
+ qiosfileengineassetslibrary.mm \
+ qiosfiledialog.mm \
+ qiosmessagedialog.mm \
+ qiostextinputoverlay.mm
+ HEADERS += \
+ qiosclipboard.h \
+ qiosmenu.h \
+ qiosfileengineassetslibrary.h \
+ qiosfiledialog.h \
+ qiosmessagedialog.h \
+ qiostextinputoverlay.h
+}
OTHER_FILES = \
quiview_textinput.mm \
diff --git a/src/plugins/platforms/ios/plugin.mm b/src/plugins/platforms/ios/plugin.mm
index b854dfdaa0..83760f2f39 100644
--- a/src/plugins/platforms/ios/plugin.mm
+++ b/src/plugins/platforms/ios/plugin.mm
@@ -54,8 +54,10 @@ class QIOSIntegrationPlugin : public QPlatformIntegrationPlugin
QPlatformIntegration * QIOSIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
- if (!system.compare(QLatin1String("ios"), Qt::CaseInsensitive))
+ if (!system.compare(QLatin1String("ios"), Qt::CaseInsensitive)
+ || !system.compare(QLatin1String("tvos"), Qt::CaseInsensitive)) {
return new QIOSIntegration;
+ }
return 0;
}
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
index 8d82364cc0..f49f81912e 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.mm
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -493,7 +493,7 @@ void QIOSEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity)
Q_UNUSED(activity);
Q_ASSERT(activity == kCFRunLoopExit);
- if (m_processEventLevel == 1 && !QThreadData::current()->eventLoops.top()->isRunning()) {
+ if (m_processEventLevel == 1 && !currentEventLoop()->isRunning()) {
qEventDispatcherDebug() << "Root runloop level exited";
interruptEventLoopExec();
}
diff --git a/src/plugins/platforms/ios/qiosfileenginefactory.h b/src/plugins/platforms/ios/qiosfileenginefactory.h
index b71fa64460..87665ac603 100644
--- a/src/plugins/platforms/ios/qiosfileenginefactory.h
+++ b/src/plugins/platforms/ios/qiosfileenginefactory.h
@@ -51,8 +51,12 @@ public:
{
static QLatin1String assetsScheme("assets-library:");
+#ifndef Q_OS_TVOS
if (fileName.toLower().startsWith(assetsScheme))
return new QIOSFileEngineAssetsLibrary(fileName);
+#else
+ Q_UNUSED(fileName);
+#endif
return 0;
}
diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h
index 0fe81ceb91..50bedd7b28 100644
--- a/src/plugins/platforms/ios/qiosglobal.h
+++ b/src/plugins/platforms/ios/qiosglobal.h
@@ -61,13 +61,10 @@ class QPlatformScreen;
bool isQtApplication();
-CGRect toCGRect(const QRectF &rect);
-QRectF fromCGRect(const CGRect &rect);
-CGPoint toCGPoint(const QPointF &point);
-QPointF fromCGPoint(const CGPoint &point);
-
+#ifndef Q_OS_TVOS
Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation);
UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation);
+#endif
int infoPlistValue(NSString* key, int defaultValue);
diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm
index c2f3d6b9e1..7ca3c66971 100644
--- a/src/plugins/platforms/ios/qiosglobal.mm
+++ b/src/plugins/platforms/ios/qiosglobal.mm
@@ -58,26 +58,7 @@ bool isQtApplication()
return isQt;
}
-CGRect toCGRect(const QRectF &rect)
-{
- return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
-}
-
-QRectF fromCGRect(const CGRect &rect)
-{
- return QRectF(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
-}
-
-CGPoint toCGPoint(const QPointF &point)
-{
- return CGPointMake(point.x(), point.y());
-}
-
-QPointF fromCGPoint(const CGPoint &point)
-{
- return QPointF(point.x, point.y);
-}
-
+#ifndef Q_OS_TVOS
Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation)
{
Qt::ScreenOrientation qtOrientation;
@@ -124,6 +105,7 @@ UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation)
}
return uiOrientation;
}
+#endif
int infoPlistValue(NSString* key, int defaultValue)
{
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index ef93d68cf0..c6cbb9b101 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -117,6 +117,7 @@ static QUIView *focusView()
self.cancelsTouchesInView = NO;
self.delaysTouchesEnded = NO;
+#ifndef Q_OS_TVOS
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
@@ -134,6 +135,7 @@ static QUIView *focusView()
[notificationCenter addObserver:self
selector:@selector(keyboardDidChangeFrame:)
name:UIKeyboardDidChangeFrameNotification object:nil];
+#endif
}
return self;
@@ -377,6 +379,9 @@ void QIOSInputContext::clearCurrentFocusObject()
void QIOSInputContext::updateKeyboardState(NSNotification *notification)
{
+#ifdef Q_OS_TVOS
+ Q_UNUSED(notification);
+#else
static CGRect currentKeyboardRect = CGRectZero;
KeyboardState previousState = m_keyboardState;
@@ -412,7 +417,7 @@ void QIOSInputContext::updateKeyboardState(NSNotification *notification)
m_keyboardState.animationDuration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
m_keyboardState.keyboardAnimating = m_keyboardState.animationDuration > 0 && !atEndOfKeyboardTransition;
- qImDebug() << qPrintable(QString::fromNSString(notification.name)) << "from" << fromCGRect(frameBegin) << "to" << fromCGRect(frameEnd)
+ qImDebug() << qPrintable(QString::fromNSString(notification.name)) << "from" << QRectF::fromCGRect(frameBegin) << "to" << QRectF::fromCGRect(frameEnd)
<< "(curve =" << m_keyboardState.animationCurve << "duration =" << m_keyboardState.animationDuration << "s)";
} else {
qImDebug("No notification to update keyboard state based on, just updating keyboard rect");
@@ -421,7 +426,7 @@ void QIOSInputContext::updateKeyboardState(NSNotification *notification)
if (!focusView() || CGRectIsEmpty(currentKeyboardRect))
m_keyboardState.keyboardRect = QRectF();
else // QInputmethod::keyboardRectangle() is documented to be in window coordinates.
- m_keyboardState.keyboardRect = fromCGRect([focusView() convertRect:currentKeyboardRect fromView:nil]);
+ m_keyboardState.keyboardRect = QRectF::fromCGRect([focusView() convertRect:currentKeyboardRect fromView:nil]);
// Emit for all changed properties
if (m_keyboardState.keyboardVisible != previousState.keyboardVisible)
@@ -430,6 +435,7 @@ void QIOSInputContext::updateKeyboardState(NSNotification *notification)
emitAnimatingChanged();
if (m_keyboardState.keyboardRect != previousState.keyboardRect)
emitKeyboardRectChanged();
+#endif
}
bool QIOSInputContext::isInputPanelVisible() const
@@ -549,7 +555,11 @@ void QIOSInputContext::scroll(int y)
if (keyboardScrollIsActive && !originalWindowLevels.contains(window))
originalWindowLevels.insert(window, window.windowLevel);
+#ifndef Q_OS_TVOS
UIWindowLevel windowLevelAdjustment = keyboardScrollIsActive ? UIWindowLevelStatusBar : 0;
+#else
+ UIWindowLevel windowLevelAdjustment = 0;
+#endif
window.windowLevel = originalWindowLevels.value(window) + windowLevelAdjustment;
if (!keyboardScrollIsActive)
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index a50d9aa571..36c3bbf6f1 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -46,7 +46,9 @@
#include "qiosapplicationstate.h"
#include "qiosfileenginefactory.h"
+#ifndef Q_OS_TVOS
#include "qiostextinputoverlay.h"
+#endif
QT_BEGIN_NAMESPACE
@@ -102,14 +104,18 @@ public:
private:
QPlatformFontDatabase *m_fontDatabase;
+#ifndef Q_OS_TVOS
QPlatformClipboard *m_clipboard;
+#endif
QPlatformInputContext *m_inputContext;
QTouchDevice *m_touchDevice;
QIOSApplicationState m_applicationState;
QIOSServices *m_platformServices;
mutable QPlatformAccessibility *m_accessibility;
QIOSFileEngineFactory m_fileEngineFactory;
+#ifndef Q_OS_TVOS
QIOSTextInputOverlay m_textInputOverlay;
+#endif
bool m_debugWindowManagement;
};
@@ -117,4 +123,3 @@ private:
QT_END_NAMESPACE
#endif
-
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index fa12d54b28..297b549ec2 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -45,7 +45,9 @@
#include "qiosscreen.h"
#include "qiosplatformaccessibility.h"
#include "qioscontext.h"
+#ifndef Q_OS_TVOS
#include "qiosclipboard.h"
+#endif
#include "qiosinputcontext.h"
#include "qiostheme.h"
#include "qiosservices.h"
@@ -72,7 +74,9 @@ QIOSIntegration *QIOSIntegration::instance()
QIOSIntegration::QIOSIntegration()
: m_fontDatabase(new QCoreTextFontDatabase)
+#ifndef Q_OS_TVOS
, m_clipboard(new QIOSClipboard)
+#endif
, m_inputContext(0)
, m_platformServices(new QIOSServices)
, m_accessibility(0)
@@ -127,8 +131,10 @@ QIOSIntegration::~QIOSIntegration()
delete m_fontDatabase;
m_fontDatabase = 0;
+#ifndef Q_OS_TVOS
delete m_clipboard;
m_clipboard = 0;
+#endif
QMacInternalPasteboardMime::destroyMimeTypes();
delete m_inputContext;
@@ -217,7 +223,11 @@ QPlatformFontDatabase * QIOSIntegration::fontDatabase() const
QPlatformClipboard *QIOSIntegration::clipboard() const
{
+#ifndef Q_OS_TVOS
return m_clipboard;
+#else
+ return 0;
+#endif
}
QPlatformInputContext *QIOSIntegration::inputContext() const
diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm
index db1b5b8cc8..d5211cdd8a 100644
--- a/src/plugins/platforms/ios/qiosmenu.mm
+++ b/src/plugins/platforms/ios/qiosmenu.mm
@@ -570,7 +570,7 @@ void QIOSMenu::repositionMenu()
switch (m_effectiveMenuType) {
case EditMenu: {
UIView *view = reinterpret_cast<UIView *>(m_parentWindow->winId());
- [[UIMenuController sharedMenuController] setTargetRect:toCGRect(m_targetRect) inView:view];
+ [[UIMenuController sharedMenuController] setTargetRect:m_targetRect.toCGRect() inView:view];
[[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES];
break; }
default:
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index d53f0df846..b9c77e9bba 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -143,21 +143,25 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
self = [super init];
if (self) {
m_screen = screen;
+#ifndef Q_OS_TVOS
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(orientationChanged:)
name:@"UIDeviceOrientationDidChangeNotification" object:nil];
+#endif
}
return self;
}
- (void)dealloc
{
+#ifndef Q_OS_TVOS
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:@"UIDeviceOrientationDidChangeNotification" object:nil];
+#endif
[super dealloc];
}
@@ -256,9 +260,14 @@ void QIOSScreen::updateProperties()
QRect previousGeometry = m_geometry;
QRect previousAvailableGeometry = m_availableGeometry;
- m_geometry = fromCGRect(m_uiScreen.bounds).toRect();
- m_availableGeometry = fromCGRect(m_uiScreen.applicationFrame).toRect();
+ m_geometry = QRectF::fromCGRect(m_uiScreen.bounds).toRect();
+#ifdef Q_OS_TVOS
+ m_availableGeometry = m_geometry;
+#else
+ m_availableGeometry = QRectF::fromCGRect(m_uiScreen.applicationFrame).toRect();
+#endif
+#ifndef Q_OS_TVOS
if (m_uiScreen == [UIScreen mainScreen]) {
Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation));
@@ -286,6 +295,7 @@ void QIOSScreen::updateProperties()
m_availableGeometry = transform.mapRect(m_availableGeometry);
}
}
+#endif
if (m_geometry != previousGeometry) {
QRectF physicalGeometry;
@@ -298,7 +308,7 @@ void QIOSScreen::updateProperties()
// before being output on the physical display. We have to take this into account when
// computing the physical size. Note that unlike the native bounds, the physical size
// follows the primary orientation of the screen.
- physicalGeometry = mapBetween(nativeOrientation(), primaryOrientation, fromCGRect(m_uiScreen.nativeBounds).toRect());
+ physicalGeometry = mapBetween(nativeOrientation(), primaryOrientation, QRectF::fromCGRect(m_uiScreen.nativeBounds).toRect());
} else {
physicalGeometry = QRectF(0, 0, m_geometry.width() * devicePixelRatio(), m_geometry.height() * devicePixelRatio());
}
@@ -393,7 +403,7 @@ qreal QIOSScreen::devicePixelRatio() const
Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
{
CGRect nativeBounds =
-#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
+#if !defined(Q_OS_TVOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0 ? m_uiScreen.nativeBounds :
#endif
m_uiScreen.bounds;
@@ -406,6 +416,9 @@ Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
Qt::ScreenOrientation QIOSScreen::orientation() const
{
+#ifdef Q_OS_TVOS
+ return Qt::PrimaryOrientation;
+#else
// Auxiliary screens are always the same orientation as their primary orientation
if (m_uiScreen != [UIScreen mainScreen])
return Qt::PrimaryOrientation;
@@ -430,6 +443,7 @@ Qt::ScreenOrientation QIOSScreen::orientation() const
}
return toQtScreenOrientation(deviceOrientation);
+#endif
}
void QIOSScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask)
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm
index 733367f3be..ff260d02dc 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.mm
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm
@@ -136,7 +136,7 @@ static void executeBlockWithoutAnimation(Block block)
// first responder, which is normally QIOSTextResponder.
QRectF cr = qApp->inputMethod()->cursorRectangle();
QRectF ar = qApp->inputMethod()->anchorRectangle();
- CGRect targetRect = toCGRect(cr.united(ar));
+ CGRect targetRect = cr.united(ar).toCGRect();
UIView *focusView = reinterpret_cast<UIView *>(qApp->focusWindow()->winId());
[[UIMenuController sharedMenuController] setTargetRect:targetRect inView:focusView];
[[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES];
@@ -496,12 +496,12 @@ static void executeBlockWithoutAnimation(Block block)
QGuiApplication::styleHints()->setCursorFlashTime(0);
if (!_loupeLayer)
[self createLoupe];
- [self updateFocalPoint:fromCGPoint(_lastTouchPoint)];
+ [self updateFocalPoint:QPointF::fromCGPoint(_lastTouchPoint)];
_loupeLayer.visible = YES;
break;
case UIGestureRecognizerStateChanged:
// Tell the sub class to move the loupe to the correct position
- [self updateFocalPoint:fromCGPoint(_lastTouchPoint)];
+ [self updateFocalPoint:QPointF::fromCGPoint(_lastTouchPoint)];
break;
case UIGestureRecognizerStateEnded:
// Restore cursor blinking, and hide the loupe
@@ -526,12 +526,12 @@ static void executeBlockWithoutAnimation(Block block)
- (QPointF)focalPoint
{
- return fromCGPoint([_loupeLayer.targetView convertPoint:_loupeLayer.focalPoint toView:_focusView]);
+ return QPointF::fromCGPoint([_loupeLayer.targetView convertPoint:_loupeLayer.focalPoint toView:_focusView]);
}
- (void)setFocalPoint:(QPointF)point
{
- _loupeLayer.focalPoint = [_loupeLayer.targetView convertPoint:toCGPoint(point) fromView:_focusView];
+ _loupeLayer.focalPoint = [_loupeLayer.targetView convertPoint:point.toCGPoint() fromView:_focusView];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
@@ -548,7 +548,7 @@ static void executeBlockWithoutAnimation(Block block)
// If the touch point is accepted by the sub class (e.g touch on cursor), we start a
// press'n'hold timer that eventually will move the state to UIGestureRecognizerStateBegan.
- if ([self acceptTouchesBegan:fromCGPoint(_firstTouchPoint)])
+ if ([self acceptTouchesBegan:QPointF::fromCGPoint(_firstTouchPoint)])
_triggerStateBeganTimer.start();
else
self.state = UIGestureRecognizerStateFailed;
@@ -856,8 +856,8 @@ static void executeBlockWithoutAnimation(Block block)
// Adjust handles and input rect to match the new selection
QRectF inputRect = QGuiApplication::inputMethod()->inputItemClipRectangle();
- CGRect cursorRect = toCGRect(QGuiApplication::inputMethod()->cursorRectangle());
- CGRect anchorRect = toCGRect(QGuiApplication::inputMethod()->anchorRectangle());
+ CGRect cursorRect = QGuiApplication::inputMethod()->cursorRectangle().toCGRect();
+ CGRect anchorRect = QGuiApplication::inputMethod()->anchorRectangle().toCGRect();
if (!_multiLine) {
// Resize the layer a bit bigger to ensure that the handles are
@@ -866,7 +866,7 @@ static void executeBlockWithoutAnimation(Block block)
inputRect.adjust(-margin / 2, -margin, margin / 2, margin);
}
- executeBlockWithoutAnimation(^{ _clipRectLayer.frame = toCGRect(inputRect); });
+ executeBlockWithoutAnimation(^{ _clipRectLayer.frame = inputRect.toCGRect(); });
_cursorLayer.cursorRectangle = [self.focusView.layer convertRect:cursorRect toLayer:_clipRectLayer];
_anchorLayer.cursorRectangle = [self.focusView.layer convertRect:anchorRect toLayer:_clipRectLayer];
_cursorLayer.visible = YES;
@@ -934,7 +934,7 @@ static void executeBlockWithoutAnimation(Block block)
}
QRectF inputRect = QGuiApplication::inputMethod()->inputItemClipRectangle();
- QPointF touchPos = fromCGPoint([static_cast<UITouch *>([touches anyObject]) locationInView:_focusView]);
+ QPointF touchPos = QPointF::fromCGPoint([static_cast<UITouch *>([touches anyObject]) locationInView:_focusView]);
if (!inputRect.contains(touchPos))
self.state = UIGestureRecognizerStateFailed;
@@ -943,7 +943,7 @@ static void executeBlockWithoutAnimation(Block block)
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
- QPointF touchPos = fromCGPoint([static_cast<UITouch *>([touches anyObject]) locationInView:_focusView]);
+ QPointF touchPos = QPointF::fromCGPoint([static_cast<UITouch *>([touches anyObject]) locationInView:_focusView]);
const QTransform mapToLocal = QGuiApplication::inputMethod()->inputItemTransform().inverted();
int cursorPosOnRelease = QInputMethod::queryFocusObject(Qt::ImCursorPosition, touchPos * mapToLocal).toInt();
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index 37d5557794..5ec05ec8ce 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -680,11 +680,7 @@
if (markedTextFormat.isEmpty()) {
// There seems to be no way to query how the preedit text
// should be drawn. So we need to hard-code the color.
- QSysInfo::MacVersion iosVersion = QSysInfo::MacintoshVersion;
- if (iosVersion < QSysInfo::MV_IOS_7_0)
- markedTextFormat.setBackground(QColor(235, 239, 247));
- else
- markedTextFormat.setBackground(QColor(206, 221, 238));
+ markedTextFormat.setBackground(QColor(206, 221, 238));
}
QList<QInputMethodEvent::Attribute> attrs;
@@ -812,7 +808,7 @@
[self sendEventToFocusObject:e];
}
- return toCGRect(startRect.united(endRect));
+ return startRect.united(endRect).toCGRect();
}
- (NSArray *)selectionRectsForRange:(UITextRange *)range
@@ -830,7 +826,7 @@
// Assume for now that position is always the same as
// cursor index until a better API is in place:
QRectF cursorRect = qApp->inputMethod()->cursorRectangle();
- return toCGRect(cursorRect);
+ return cursorRect.toCGRect();
}
- (void)replaceRange:(UITextRange *)range withText:(NSString *)text
@@ -897,6 +893,7 @@
// text instead of just guessing...
}
+#ifndef Q_OS_TVOS
- (NSDictionary *)textStylingAtPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
{
Q_UNUSED(position);
@@ -916,6 +913,7 @@
return [NSDictionary dictionary];
return [NSDictionary dictionaryWithObject:uifont forKey:UITextInputTextFontKey];
}
+#endif
- (NSDictionary *)markedTextStyle
{
diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm
index 486c146af9..83a8176478 100644
--- a/src/plugins/platforms/ios/qiostheme.mm
+++ b/src/plugins/platforms/ios/qiostheme.mm
@@ -51,9 +51,11 @@
#include <UIKit/UIFont.h>
#include <UIKit/UIInterface.h>
+#ifndef Q_OS_TVOS
#include "qiosmenu.h"
#include "qiosfiledialog.h"
#include "qiosmessagedialog.h"
+#endif
QT_BEGIN_NAMESPACE
@@ -80,12 +82,20 @@ const QPalette *QIOSTheme::palette(QPlatformTheme::Palette type) const
QPlatformMenuItem* QIOSTheme::createPlatformMenuItem() const
{
+#ifdef Q_OS_TVOS
+ return 0;
+#else
return new QIOSMenuItem();
+#endif
}
QPlatformMenu* QIOSTheme::createPlatformMenu() const
{
+#ifdef Q_OS_TVOS
+ return 0;
+#else
return new QIOSMenu();
+#endif
}
bool QIOSTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const
@@ -102,12 +112,14 @@ bool QIOSTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const
QPlatformDialogHelper *QIOSTheme::createPlatformDialogHelper(QPlatformTheme::DialogType type) const
{
switch (type) {
+#ifndef Q_OS_TVOS
case FileDialog:
return new QIOSFileDialog();
break;
case MessageDialog:
return new QIOSMessageDialog();
break;
+#endif
default:
return 0;
}
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h
index e97aeb32ed..92c4e59d1a 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.h
+++ b/src/plugins/platforms/ios/qiosviewcontroller.h
@@ -46,12 +46,16 @@ class QIOSScreen;
- (id)initWithQIOSScreen:(QIOSScreen *)screen;
- (void)updateProperties;
+#ifndef Q_OS_TVOS
@property (nonatomic, assign) UIInterfaceOrientation lockedOrientation;
+#endif
// UIViewController
@property (nonatomic, assign) BOOL prefersStatusBarHidden;
+#ifndef Q_OS_TVOS
@property (nonatomic, assign) UIStatusBarAnimation preferredStatusBarUpdateAnimation;
@property (nonatomic, assign) UIStatusBarStyle preferredStatusBarStyle;
+#endif
@end
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index 2acb247572..c8c07bd298 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -37,6 +37,7 @@
**
****************************************************************************/
+#include "qiosglobal.h"
#import "qiosviewcontroller.h"
#include <QtCore/qscopedvaluerollback.h>
@@ -233,33 +234,16 @@
if (self = [self init]) {
m_screen = screen;
-#if QT_IOS_DEPLOYMENT_TARGET_BELOW(__IPHONE_7_0)
- QSysInfo::MacVersion iosVersion = QSysInfo::MacintoshVersion;
-
- // We prefer to keep the root viewcontroller in fullscreen layout, so that
- // we don't have to compensate for the viewcontroller position. This also
- // gives us the same behavior on iOS 5/6 as on iOS 7, where full screen layout
- // is the only way.
- if (iosVersion < QSysInfo::MV_IOS_7_0)
- self.wantsFullScreenLayout = YES;
-
- // Use translucent statusbar by default on iOS6 iPhones (unless the user changed
- // the default in the Info.plist), so that windows placed under the stausbar are
- // still visible, just like on iOS7.
- if (screen->uiScreen() == [UIScreen mainScreen]
- && iosVersion >= QSysInfo::MV_IOS_6_0 && iosVersion < QSysInfo::MV_IOS_7_0
- && [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone
- && [UIApplication sharedApplication].statusBarStyle == UIStatusBarStyleDefault)
- [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent];
-#endif
- self.lockedOrientation = UIInterfaceOrientationUnknown;
self.changingOrientation = NO;
+#ifndef Q_OS_TVOS
+ self.lockedOrientation = UIInterfaceOrientationUnknown;
// Status bar may be initially hidden at startup through Info.plist
self.prefersStatusBarHidden = infoPlistValue(@"UIStatusBarHidden", false);
self.preferredStatusBarUpdateAnimation = UIStatusBarAnimationNone;
self.preferredStatusBarStyle = UIStatusBarStyle(infoPlistValue(@"UIStatusBarStyle", UIStatusBarStyleDefault));
+#endif
m_focusWindowChangeConnection = QObject::connect(qApp, &QGuiApplication::focusWindowChanged, [self]() {
[self updateProperties];
@@ -284,6 +268,7 @@
{
[super viewDidLoad];
+#ifndef Q_OS_TVOS
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(willChangeStatusBarFrame:)
name:UIApplicationWillChangeStatusBarFrameNotification
@@ -292,6 +277,7 @@
[center addObserver:self selector:@selector(didChangeStatusBarOrientation:)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:[UIApplication sharedApplication]];
+#endif
}
- (void)viewDidUnload
@@ -304,10 +290,13 @@
- (BOOL)shouldAutorotate
{
+#ifndef Q_OS_TVOS
return m_screen && m_screen->uiScreen() == [UIScreen mainScreen] && !self.lockedOrientation;
+#else
+ return NO;
+#endif
}
-#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_6_0)
- (NSUInteger)supportedInterfaceOrientations
{
// As documented by Apple in the iOS 6.0 release notes, setStatusBarOrientation:animated:
@@ -318,15 +307,6 @@
// supportedInterfaceOrientations says, which states that the method should not return 0.
return [self shouldAutorotate] ? UIInterfaceOrientationMaskAll : 0;
}
-#endif
-
-#if QT_IOS_DEPLOYMENT_TARGET_BELOW(__IPHONE_6_0)
-- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
-{
- Q_UNUSED(interfaceOrientation);
- return [self shouldAutorotate];
-}
-#endif
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration
{
@@ -435,6 +415,7 @@
// All decisions are based on the the top level window
focusWindow = qt_window_private(focusWindow)->topLevelWindow();
+#ifndef Q_OS_TVOS
UIApplication *uiApplication = [UIApplication sharedApplication];
// -------------- Status bar style and visbility ---------------
@@ -443,30 +424,16 @@
if (focusWindow->flags() & Qt::MaximizeUsingFullscreenGeometryHint)
self.preferredStatusBarStyle = UIStatusBarStyleDefault;
else
- self.preferredStatusBarStyle = QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0 ?
- UIStatusBarStyleLightContent : UIStatusBarStyleBlackTranslucent;
-
- if (self.preferredStatusBarStyle != oldStatusBarStyle) {
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0)
- [self setNeedsStatusBarAppearanceUpdate];
- else
- [uiApplication setStatusBarStyle:self.preferredStatusBarStyle];
- }
+ self.preferredStatusBarStyle = UIStatusBarStyleLightContent;
+
+ if (self.preferredStatusBarStyle != oldStatusBarStyle)
+ [self setNeedsStatusBarAppearanceUpdate];
bool currentStatusBarVisibility = self.prefersStatusBarHidden;
self.prefersStatusBarHidden = focusWindow->windowState() == Qt::WindowFullScreen;
if (self.prefersStatusBarHidden != currentStatusBarVisibility) {
-#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0) {
- [self setNeedsStatusBarAppearanceUpdate];
- } else
-#endif
- {
- [uiApplication setStatusBarHidden:self.prefersStatusBarHidden
- withAnimation:self.preferredStatusBarUpdateAnimation];
- }
-
+ [self setNeedsStatusBarAppearanceUpdate];
[self.view setNeedsLayout];
}
@@ -512,6 +479,7 @@
[UIViewController attemptRotationToDeviceOrientation];
}
}
+#endif
}
@end
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index ddf856d7a4..cddfbe6b06 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -211,7 +211,7 @@ void QIOSWindow::applyGeometry(const QRect &rect)
// The baseclass takes care of persisting this for us.
QPlatformWindow::setGeometry(rect);
- m_view.frame = toCGRect(rect);
+ m_view.frame = rect.toCGRect();
// iOS will automatically trigger -[layoutSubviews:] for resize,
// but not for move, so we force it just in case.
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index e38be68343..bf929667a6 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -44,7 +44,9 @@
#include "qiosviewcontroller.h"
#include "qiostextresponder.h"
#include "qioswindow.h"
+#ifndef Q_OS_TVOS
#include "qiosmenu.h"
+#endif
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qwindow_p.h>
@@ -58,7 +60,7 @@
- (id)initWithQIOSWindow:(QIOSWindow *)window
{
- if (self = [self initWithFrame:toCGRect(window->geometry())])
+ if (self = [self initWithFrame:window->geometry().toCGRect()])
m_qioswindow = window;
m_accessibleElements = [[NSMutableArray alloc] init];
@@ -78,7 +80,9 @@
if (isQtApplication())
self.hidden = YES;
+#ifndef Q_OS_TVOS
self.multipleTouchEnabled = YES;
+#endif
if (QIOSIntegration::instance()->debugWindowManagement()) {
static CGFloat hue = 0.0;
@@ -149,7 +153,7 @@
// from what we end up with after applying window constraints.
QRect requestedGeometry = m_qioswindow->geometry();
- QRect actualGeometry = fromCGRect(self.frame).toRect();
+ QRect actualGeometry = QRectF::fromCGRect(self.frame).toRect();
// Persist the actual/new geometry so that QWindow::geometry() can
// be queried on the resize event.
@@ -184,7 +188,7 @@
QRegion region;
if (m_qioswindow->isExposed()) {
- QSize bounds = fromCGRect(self.layer.bounds).toRect().size();
+ QSize bounds = QRectF::fromCGRect(self.layer.bounds).toRect().size();
Q_ASSERT(m_qioswindow->geometry().size() == bounds);
Q_ASSERT(self.hidden == !m_qioswindow->window()->isVisible());
@@ -324,7 +328,8 @@
// Touch positions are expected to be in QScreen global coordinates, and
// as we already have the QWindow positioned at the right place, we can
// just map from the local view position to global coordinates.
- QPoint localViewPosition = fromCGPoint([uiTouch locationInView:self]).toPoint();
+ // tvOS: all touches start at the center of the screen and move from there.
+ QPoint localViewPosition = QPointF::fromCGPoint([uiTouch locationInView:self]).toPoint();
QPoint globalScreenPosition = m_qioswindow->mapToGlobal(localViewPosition);
touchPoint.area = QRectF(globalScreenPosition, QSize(0, 0));
@@ -439,14 +444,24 @@
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
+#ifndef Q_OS_TVOS
// Check first if QIOSMenu should handle the action before continuing up the responder chain
return [QIOSMenu::menuActionTarget() targetForAction:action withSender:sender] != 0;
+#else
+ Q_UNUSED(action)
+ Q_UNUSED(sender)
+ return false;
+#endif
}
- (id)forwardingTargetForSelector:(SEL)selector
{
Q_UNUSED(selector)
+#ifndef Q_OS_TVOS
return QIOSMenu::menuActionTarget();
+#else
+ return nil;
+#endif
}
@end
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
index 1fd2b84e37..6ca651fdf7 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
@@ -412,11 +412,9 @@ QRegion QLinuxFbScreen::doRedraw()
if (!mBlitter)
mBlitter = new QPainter(&mFbScreenImage);
- const QVector<QRect> rects = touched.rects();
mBlitter->setCompositionMode(QPainter::CompositionMode_Source);
-
- for (int i = 0; i < rects.size(); ++i)
- mBlitter->drawImage(rects[i], *mScreenImage, rects[i]);
+ for (const QRect &rect : touched)
+ mBlitter->drawImage(rect, *mScreenImage, rect);
return touched;
}
diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp
index 465ad355b9..f80d85842a 100644
--- a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp
@@ -100,7 +100,7 @@ void QMirClientBackingStore::updateTexture()
QRegion fixed;
QRect imageRect = mImage.rect();
- Q_FOREACH (const QRect &rect, mDirty.rects()) {
+ for (const QRect &rect : mDirty) {
// intersect with image rect to be sure
QRect r = imageRect & rect;
@@ -113,7 +113,7 @@ void QMirClientBackingStore::updateTexture()
fixed |= r;
}
- Q_FOREACH (const QRect &rect, fixed.rects()) {
+ for (const QRect &rect : fixed) {
// if the sub-rect is full-width we can pass the image data directly to
// OpenGL instead of copying, since there is no gap between scanlines
if (rect.width() == imageRect.width()) {
diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.cpp b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
index ed1a81c2b3..a63aacdbfe 100644
--- a/src/plugins/platforms/offscreen/qoffscreencommon.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
@@ -179,9 +179,8 @@ bool QOffscreenBackingStore::scroll(const QRegion &area, int dx, int dy)
if (m_image.isNull())
return false;
- const QVector<QRect> rects = area.rects();
- for (int i = 0; i < rects.size(); ++i)
- qt_scrollRectInImage(m_image, rects.at(i), QPoint(dx, dy));
+ for (const QRect &rect : area)
+ qt_scrollRectInImage(m_image, rect, QPoint(dx, dy));
return true;
}
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
index a5b64636af..4bed5312ec 100644
--- a/src/plugins/platforms/platforms.pro
+++ b/src/plugins/platforms/platforms.pro
@@ -10,10 +10,8 @@ contains(QT_CONFIG, xcb) {
SUBDIRS += xcb
}
-mac {
- ios: SUBDIRS += ios
- else: SUBDIRS += cocoa
-}
+uikit: SUBDIRS += ios
+osx: SUBDIRS += cocoa
win32:!winrt: SUBDIRS += windows
winrt: SUBDIRS += winrt
@@ -37,6 +35,12 @@ contains(QT_CONFIG, directfb) {
contains(QT_CONFIG, linuxfb): SUBDIRS += linuxfb
+unix:!android:!darwin: SUBDIRS += vnc
+
+freebsd {
+ SUBDIRS += bsdfb
+}
+
haiku {
SUBDIRS += haiku
}
diff --git a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
index a08ac2b839..90a09d3087 100644
--- a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
+++ b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
@@ -97,7 +97,7 @@ void QQnxButtonEventNotifier::start()
m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read);
QObject::connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(updateButtonStates()));
- qButtonDebug() << "successfully connected to Navigator. fd =" << m_fd;
+ qButtonDebug("successfully connected to Navigator. fd = %d", m_fd);
}
void QQnxButtonEventNotifier::updateButtonStates()
@@ -121,7 +121,7 @@ void QQnxButtonEventNotifier::updateButtonStates()
// Ensure data is null terminated
buffer[bytes] = '\0';
- qButtonDebug() << "received PPS message:\n" << buffer;
+ qButtonDebug("received PPS message:\n%s", buffer);
// Process received message
QByteArray ppsData = QByteArray::fromRawData(buffer, bytes);
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
index 79ff74b113..ce3a445d7c 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
@@ -721,7 +721,7 @@ void QQnxInputContext::update(Qt::InputMethodQueries queries)
initEvent(&caretEvent.event, sInputSession, EVENT_CARET, CARET_POS_CHANGED, sizeof(caretEvent));
caretEvent.old_pos = lastCaret;
caretEvent.new_pos = m_caretPosition;
- qInputContextDebug() << "ictrl_dispatch_event caret changed" << lastCaret << m_caretPosition;
+ qInputContextDebug("ictrl_dispatch_event caret changed %d %d", lastCaret, m_caretPosition);
p_ictrl_dispatch_event(&caretEvent.event);
}
}
@@ -914,7 +914,7 @@ bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan
navigation_event_t navEvent;
initEvent(&navEvent.event, sInputSession, EVENT_NAVIGATION, key, sizeof(navEvent));
navEvent.magnitude = 1;
- qInputContextDebug() << "ictrl_dispatch_even navigation" << key;
+ qInputContextDebug("ictrl_dispatch_even navigation %d", key);
p_ictrl_dispatch_event(&navEvent.event);
}
} else {
@@ -927,7 +927,7 @@ bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan
keyEvent.sequence_id = sequenceId;
p_ictrl_dispatch_event(&keyEvent.event);
- qInputContextDebug() << "ictrl_dispatch_even key" << key;
+ qInputContextDebug("ictrl_dispatch_even key %d", key);
}
return true;
@@ -943,7 +943,7 @@ void QQnxInputContext::updateCursorPosition()
QCoreApplication::sendEvent(input, &query);
m_caretPosition = query.value(Qt::ImCursorPosition).toInt();
- qInputContextDebug() << m_caretPosition;
+ qInputContextDebug("%d", m_caretPosition);
}
void QQnxInputContext::endComposition()
@@ -1116,7 +1116,7 @@ int32_t QQnxInputContext::processEvent(event_t *event)
int flags = KEY_SYM_VALID | KEY_CAP_VALID;
if (event->event_id == IMF_KEY_DOWN)
flags |= KEY_DOWN;
- qInputContextDebug() << "EVENT_KEY" << flags << keySym;
+ qInputContextDebug("EVENT_KEY %d %d", flags, keySym);
QQnxScreenEventHandler::injectKeyboardEvent(flags, keySym, modifiers, 0, keyCap);
result = 0;
break;
@@ -1156,7 +1156,7 @@ int32_t QQnxInputContext::onCommitText(spannable_string_t *text, int32_t new_cur
int32_t QQnxInputContext::onDeleteSurroundingText(int32_t left_length, int32_t right_length)
{
- qInputContextDebug() << "L:" << left_length << " R:" << right_length;
+ qInputContextDebug("L: %d R: %d", int(left_length), int(right_length));
QObject *input = qGuiApp->focusObject();
if (!input)
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index 3a0e97af6e..9d38742d6f 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -453,11 +453,11 @@ void QQnxIntegration::createDisplays()
Q_SCREEN_CHECKERROR(result, "Failed to query display attachment");
if (!isAttached) {
- qIntegrationDebug() << "Skipping non-attached display" << i;
+ qIntegrationDebug("Skipping non-attached display %d", i);
continue;
}
- qIntegrationDebug() << "Creating screen for display" << i;
+ qIntegrationDebug("Creating screen for display %d", i);
createDisplay(displays[i], /*isPrimary=*/false);
} // of displays iteration
}
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
index 4955938a3a..0e16764b79 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
@@ -63,14 +63,14 @@ bool QQnxNavigatorEventHandler::handleOrientationCheck(int angle)
{
// reply to navigator that (any) orientation is acceptable
// TODO: check if top window flags prohibit orientation change
- qNavigatorEventHandlerDebug() << "angle=" << angle;
+ qNavigatorEventHandlerDebug("angle=%d", angle);
return true;
}
void QQnxNavigatorEventHandler::handleOrientationChange(int angle)
{
// update screen geometry and reply to navigator that we're ready
- qNavigatorEventHandlerDebug() << "angle=" << angle;
+ qNavigatorEventHandlerDebug("angle=%d", angle);
emit rotationChanged(angle);
}
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
index 9ccda2d94a..1f630863b7 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
@@ -91,8 +91,7 @@ void QQnxNavigatorEventNotifier::start()
errno = 0;
m_fd = open(navigatorControlPath, O_RDWR);
if (m_fd == -1) {
- qNavigatorEventNotifierDebug() << "failed to open navigator pps:"
- << strerror(errno);
+ qNavigatorEventNotifierDebug("failed to open navigator pps: %s", strerror(errno));
return;
}
diff --git a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
index fd1bbc4a85..d5234ca92f 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
@@ -79,7 +79,7 @@ bool QQnxNavigatorPps::openPpsConnection()
return false;
}
- qNavigatorDebug() << "successfully connected to Navigator. fd=" << m_fd;
+ qNavigatorDebug("successfully connected to Navigator. fd=%d", m_fd);
return true;
}
diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
index c9a89def41..a758bdf7f4 100644
--- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
@@ -139,7 +139,7 @@ void QQnxRasterBackingStore::beginPaint(const QRegion &region)
platformWindow()->adjustBufferSize();
if (window()->requestedFormat().alphaBufferSize() > 0) {
- foreach (const QRect &r, region.rects()) {
+ for (const QRect &r : region) {
// Clear transparent regions
const int bg[] = {
SCREEN_BLIT_COLOR, 0x00000000,
diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
index 0fe80d856d..b075690e3d 100644
--- a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
@@ -208,10 +208,9 @@ void QQnxRasterWindow::blitPreviousToCurrent(const QRegion &region, int dx, int
QQnxBuffer &previousBuffer = m_buffers[m_previousBufferIndex];
// Break down region into non-overlapping rectangles
- const QVector<QRect> rects = region.rects();
- for (int i = rects.size() - 1; i >= 0; i--) {
+ for (auto rit = region.rbegin(), rend = region.rend(); rit != rend; ++rit) {
// Clip rectangle to bounds of target
- const QRect rect = rects[i].intersected(currentBuffer.rect());
+ const QRect rect = rit->intersected(currentBuffer.rect());
if (rect.isEmpty())
continue;
diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp
index 16ddcd784b..678e83cd57 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreen.cpp
@@ -340,11 +340,12 @@ qreal QQnxScreen::refreshRate() const
qWarning("QQnxScreen: Failed to query screen mode. Using default value of 60Hz");
return 60.0;
}
- qScreenDebug() << "screen mode:" << endl
- << " width =" << displayMode.width << endl
- << " height =" << displayMode.height << endl
- << " refresh =" << displayMode.refresh << endl
- << " interlaced =" << displayMode.interlaced;
+ qScreenDebug("screen mode:\n"
+ " width = %u\n"
+ " height = %u\n"
+ " refresh = %u\n"
+ " interlaced = %u",
+ uint(displayMode.width), uint(displayMode.height), uint(displayMode.refresh), uint(displayMode.interlaced));
return static_cast<qreal>(displayMode.refresh);
}
@@ -404,7 +405,7 @@ static bool isOrthogonal(int angle1, int angle2)
void QQnxScreen::setRotation(int rotation)
{
- qScreenDebug() << "orientation =" << rotation;
+ qScreenDebug("orientation = %d", rotation);
// Check if rotation changed
// We only want to rotate if we are the primary screen
if (m_currentRotation != rotation && isPrimaryScreen()) {
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
index 599d43a8c8..42651732c2 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
@@ -147,7 +147,7 @@ bool QQnxScreenEventHandler::handleEvent(screen_event_t event, int qnxType)
default:
// event ignored
- qScreenEventDebug() << "unknown event" << qnxType;
+ qScreenEventDebug("unknown event %d", qnxType);
return false;
}
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
index 1174dc6ab3..025c03c058 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
@@ -164,7 +164,7 @@ void QQnxVirtualKeyboardPps::ppsDataReady()
{
ssize_t nread = qt_safe_read(m_fd, m_buffer, ms_bufferSize - 1);
- qVirtualKeyboardDebug() << "keyboardMessage size: " << nread;
+ qVirtualKeyboardDebug("keyboardMessage size: %zd", nread);
if (nread < 0){
connect(); // reconnect
return;
@@ -230,7 +230,7 @@ void QQnxVirtualKeyboardPps::handleKeyboardInfoMessage()
}
setHeight(newHeight);
- qVirtualKeyboardDebug() << "size=" << newHeight;
+ qVirtualKeyboardDebug("size=%d", newHeight);
}
bool QQnxVirtualKeyboardPps::showKeyboard()
diff --git a/src/plugins/platforms/vnc/main.cpp b/src/plugins/platforms/vnc/main.cpp
new file mode 100644
index 0000000000..6ee8bf1ec6
--- /dev/null
+++ b/src/plugins/platforms/vnc/main.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformintegrationplugin.h>
+#include "qvncintegration.h"
+#include "qvnc_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QVncIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "vnc.json")
+public:
+ QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE;
+};
+
+QPlatformIntegration* QVncIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ if (!system.compare(QLatin1String("vnc"), Qt::CaseInsensitive))
+ return new QVncIntegration(paramList);
+
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
+
diff --git a/src/plugins/platforms/vnc/qvnc.cpp b/src/plugins/platforms/vnc/qvnc.cpp
new file mode 100644
index 0000000000..b3613cf18f
--- /dev/null
+++ b/src/plugins/platforms/vnc/qvnc.cpp
@@ -0,0 +1,680 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qvnc_p.h"
+#include "qvncscreen.h"
+#include "qvncclient.h"
+#include "QtNetwork/qtcpserver.h"
+#include "QtNetwork/qtcpsocket.h"
+#include <qthread.h>
+
+#include <QtGui/qguiapplication.h>
+#include <QtGui/QWindow>
+
+#ifdef Q_OS_WIN
+#include <Winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcVnc, "qt.qpa.vnc");
+
+QVncDirtyMap::QVncDirtyMap(QVncScreen *screen)
+ : screen(screen), bytesPerPixel(0), numDirty(0)
+{
+ bytesPerPixel = (screen->depth() + 7) / 8;
+ bufferWidth = screen->geometry().width();
+ bufferHeight = screen->geometry().height();
+ bufferStride = bufferWidth * bytesPerPixel;
+ buffer = new uchar[bufferHeight * bufferStride];
+
+ mapWidth = (bufferWidth + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE;
+ mapHeight = (bufferHeight + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE;
+ numTiles = mapWidth * mapHeight;
+ map = new uchar[numTiles];
+}
+
+QVncDirtyMap::~QVncDirtyMap()
+{
+ delete[] map;
+ delete[] buffer;
+}
+
+void QVncDirtyMap::reset()
+{
+ memset(map, 1, numTiles);
+ memset(buffer, 0, bufferHeight * bufferStride);
+ numDirty = numTiles;
+}
+
+inline bool QVncDirtyMap::dirty(int x, int y) const
+{
+ return map[y * mapWidth + x];
+}
+
+inline void QVncDirtyMap::setClean(int x, int y)
+{
+ map[y * mapWidth + x] = 0;
+ --numDirty;
+}
+
+template <class T>
+void QVncDirtyMapOptimized<T>::setDirty(int tileX, int tileY, bool force)
+{
+ static bool alwaysForce = qEnvironmentVariableIsSet("QT_VNC_NO_COMPAREBUFFER");
+ if (alwaysForce)
+ force = true;
+
+ bool changed = false;
+
+ if (!force) {
+ const int lstep = bufferStride;
+ const int startX = tileX * MAP_TILE_SIZE;
+ const int startY = tileY * MAP_TILE_SIZE;
+ const uchar *scrn = screen->image()->constBits()
+ + startY * lstep + startX * bytesPerPixel;
+ uchar *old = buffer + startY * bufferStride + startX * sizeof(T);
+
+ const int tileHeight = (startY + MAP_TILE_SIZE > bufferHeight ?
+ bufferHeight - startY : MAP_TILE_SIZE);
+ const int tileWidth = (startX + MAP_TILE_SIZE > bufferWidth ?
+ bufferWidth - startX : MAP_TILE_SIZE);
+ const bool doInlines = (tileWidth == MAP_TILE_SIZE);
+
+ int y = tileHeight;
+
+ if (doInlines) { // hw: memcmp/memcpy is inlined when using constants
+ while (y) {
+ if (memcmp(old, scrn, sizeof(T) * MAP_TILE_SIZE)) {
+ changed = true;
+ break;
+ }
+ scrn += lstep;
+ old += bufferStride;
+ --y;
+ }
+
+ while (y) {
+ memcpy(old, scrn, sizeof(T) * MAP_TILE_SIZE);
+ scrn += lstep;
+ old += bufferStride;
+ --y;
+ }
+ } else {
+ while (y) {
+ if (memcmp(old, scrn, sizeof(T) * tileWidth)) {
+ changed = true;
+ break;
+ }
+ scrn += lstep;
+ old += bufferStride;
+ --y;
+ }
+
+ while (y) {
+ memcpy(old, scrn, sizeof(T) * tileWidth);
+ scrn += lstep;
+ old += bufferStride;
+ --y;
+ }
+ }
+ }
+
+ const int mapIndex = tileY * mapWidth + tileX;
+ if ((force || changed) && !map[mapIndex]) {
+ map[mapIndex] = 1;
+ ++numDirty;
+ }
+}
+
+template class QVncDirtyMapOptimized<unsigned char>;
+template class QVncDirtyMapOptimized<unsigned short>;
+template class QVncDirtyMapOptimized<unsigned int>;
+
+static const struct {
+ int keysym;
+ int keycode;
+} keyMap[] = {
+ { 0xff08, Qt::Key_Backspace },
+ { 0xff09, Qt::Key_Tab },
+ { 0xff0d, Qt::Key_Return },
+ { 0xff1b, Qt::Key_Escape },
+ { 0xff63, Qt::Key_Insert },
+ { 0xffff, Qt::Key_Delete },
+ { 0xff50, Qt::Key_Home },
+ { 0xff57, Qt::Key_End },
+ { 0xff55, Qt::Key_PageUp },
+ { 0xff56, Qt::Key_PageDown },
+ { 0xff51, Qt::Key_Left },
+ { 0xff52, Qt::Key_Up },
+ { 0xff53, Qt::Key_Right },
+ { 0xff54, Qt::Key_Down },
+ { 0xffbe, Qt::Key_F1 },
+ { 0xffbf, Qt::Key_F2 },
+ { 0xffc0, Qt::Key_F3 },
+ { 0xffc1, Qt::Key_F4 },
+ { 0xffc2, Qt::Key_F5 },
+ { 0xffc3, Qt::Key_F6 },
+ { 0xffc4, Qt::Key_F7 },
+ { 0xffc5, Qt::Key_F8 },
+ { 0xffc6, Qt::Key_F9 },
+ { 0xffc7, Qt::Key_F10 },
+ { 0xffc8, Qt::Key_F11 },
+ { 0xffc9, Qt::Key_F12 },
+ { 0xffe1, Qt::Key_Shift },
+ { 0xffe2, Qt::Key_Shift },
+ { 0xffe3, Qt::Key_Control },
+ { 0xffe4, Qt::Key_Control },
+ { 0xffe7, Qt::Key_Meta },
+ { 0xffe8, Qt::Key_Meta },
+ { 0xffe9, Qt::Key_Alt },
+ { 0xffea, Qt::Key_Alt },
+
+ { 0xffb0, Qt::Key_0 },
+ { 0xffb1, Qt::Key_1 },
+ { 0xffb2, Qt::Key_2 },
+ { 0xffb3, Qt::Key_3 },
+ { 0xffb4, Qt::Key_4 },
+ { 0xffb5, Qt::Key_5 },
+ { 0xffb6, Qt::Key_6 },
+ { 0xffb7, Qt::Key_7 },
+ { 0xffb8, Qt::Key_8 },
+ { 0xffb9, Qt::Key_9 },
+
+ { 0xff8d, Qt::Key_Return },
+ { 0xffaa, Qt::Key_Asterisk },
+ { 0xffab, Qt::Key_Plus },
+ { 0xffad, Qt::Key_Minus },
+ { 0xffae, Qt::Key_Period },
+ { 0xffaf, Qt::Key_Slash },
+
+ { 0xff95, Qt::Key_Home },
+ { 0xff96, Qt::Key_Left },
+ { 0xff97, Qt::Key_Up },
+ { 0xff98, Qt::Key_Right },
+ { 0xff99, Qt::Key_Down },
+ { 0xff9a, Qt::Key_PageUp },
+ { 0xff9b, Qt::Key_PageDown },
+ { 0xff9c, Qt::Key_End },
+ { 0xff9e, Qt::Key_Insert },
+ { 0xff9f, Qt::Key_Delete },
+
+ { 0, 0 }
+};
+
+void QRfbRect::read(QTcpSocket *s)
+{
+ quint16 buf[4];
+ s->read((char*)buf, 8);
+ x = ntohs(buf[0]);
+ y = ntohs(buf[1]);
+ w = ntohs(buf[2]);
+ h = ntohs(buf[3]);
+}
+
+void QRfbRect::write(QTcpSocket *s) const
+{
+ quint16 buf[4];
+ buf[0] = htons(x);
+ buf[1] = htons(y);
+ buf[2] = htons(w);
+ buf[3] = htons(h);
+ s->write((char*)buf, 8);
+}
+
+void QRfbPixelFormat::read(QTcpSocket *s)
+{
+ char buf[16];
+ s->read(buf, 16);
+ bitsPerPixel = buf[0];
+ depth = buf[1];
+ bigEndian = buf[2];
+ trueColor = buf[3];
+
+ quint16 a = ntohs(*(quint16 *)(buf + 4));
+ redBits = 0;
+ while (a) { a >>= 1; redBits++; }
+
+ a = ntohs(*(quint16 *)(buf + 6));
+ greenBits = 0;
+ while (a) { a >>= 1; greenBits++; }
+
+ a = ntohs(*(quint16 *)(buf + 8));
+ blueBits = 0;
+ while (a) { a >>= 1; blueBits++; }
+
+ redShift = buf[10];
+ greenShift = buf[11];
+ blueShift = buf[12];
+}
+
+void QRfbPixelFormat::write(QTcpSocket *s)
+{
+ char buf[16];
+ buf[0] = bitsPerPixel;
+ buf[1] = depth;
+ buf[2] = bigEndian;
+ buf[3] = trueColor;
+
+ quint16 a = 0;
+ for (int i = 0; i < redBits; i++) a = (a << 1) | 1;
+ *(quint16 *)(buf + 4) = htons(a);
+
+ a = 0;
+ for (int i = 0; i < greenBits; i++) a = (a << 1) | 1;
+ *(quint16 *)(buf + 6) = htons(a);
+
+ a = 0;
+ for (int i = 0; i < blueBits; i++) a = (a << 1) | 1;
+ *(quint16 *)(buf + 8) = htons(a);
+
+ buf[10] = redShift;
+ buf[11] = greenShift;
+ buf[12] = blueShift;
+ s->write(buf, 16);
+}
+
+
+void QRfbServerInit::setName(const char *n)
+{
+ delete[] name;
+ name = new char [strlen(n) + 1];
+ strcpy(name, n);
+}
+
+void QRfbServerInit::read(QTcpSocket *s)
+{
+ s->read((char *)&width, 2);
+ width = ntohs(width);
+ s->read((char *)&height, 2);
+ height = ntohs(height);
+ format.read(s);
+
+ quint32 len;
+ s->read((char *)&len, 4);
+ len = ntohl(len);
+
+ name = new char [len + 1];
+ s->read(name, len);
+ name[len] = '\0';
+}
+
+void QRfbServerInit::write(QTcpSocket *s)
+{
+ quint16 t = htons(width);
+ s->write((char *)&t, 2);
+ t = htons(height);
+ s->write((char *)&t, 2);
+ format.write(s);
+ quint32 len = strlen(name);
+ len = htonl(len);
+ s->write((char *)&len, 4);
+ s->write(name, strlen(name));
+}
+
+bool QRfbSetEncodings::read(QTcpSocket *s)
+{
+ if (s->bytesAvailable() < 3)
+ return false;
+
+ char tmp;
+ s->read(&tmp, 1); // padding
+ s->read((char *)&count, 2);
+ count = ntohs(count);
+
+ return true;
+}
+
+bool QRfbFrameBufferUpdateRequest::read(QTcpSocket *s)
+{
+ if (s->bytesAvailable() < 9)
+ return false;
+
+ s->read(&incremental, 1);
+ rect.read(s);
+
+ return true;
+}
+
+bool QRfbKeyEvent::read(QTcpSocket *s)
+{
+ if (s->bytesAvailable() < 7)
+ return false;
+
+ s->read(&down, 1);
+ quint16 tmp;
+ s->read((char *)&tmp, 2); // padding
+
+ quint32 key;
+ s->read((char *)&key, 4);
+ key = ntohl(key);
+
+ unicode = 0;
+ keycode = 0;
+ int i = 0;
+ while (keyMap[i].keysym && !keycode) {
+ if (keyMap[i].keysym == (int)key)
+ keycode = keyMap[i].keycode;
+ i++;
+ }
+
+ if (keycode >= ' ' && keycode <= '~')
+ unicode = keycode;
+
+ if (!keycode) {
+ if (key <= 0xff) {
+ unicode = key;
+ if (key >= 'a' && key <= 'z')
+ keycode = Qt::Key_A + key - 'a';
+ else if (key >= ' ' && key <= '~')
+ keycode = Qt::Key_Space + key - ' ';
+ }
+ }
+
+ return true;
+}
+
+bool QRfbPointerEvent::read(QTcpSocket *s)
+{
+ if (s->bytesAvailable() < 5)
+ return false;
+
+ char buttonMask;
+ s->read(&buttonMask, 1);
+ buttons = Qt::NoButton;
+ if (buttonMask & 1)
+ buttons |= Qt::LeftButton;
+ if (buttonMask & 2)
+ buttons |= Qt::MidButton;
+ if (buttonMask & 4)
+ buttons |= Qt::RightButton;
+
+ quint16 tmp;
+ s->read((char *)&tmp, 2);
+ x = ntohs(tmp);
+ s->read((char *)&tmp, 2);
+ y = ntohs(tmp);
+
+ return true;
+}
+
+bool QRfbClientCutText::read(QTcpSocket *s)
+{
+ if (s->bytesAvailable() < 7)
+ return false;
+
+ char tmp[3];
+ s->read(tmp, 3); // padding
+ s->read((char *)&length, 4);
+ length = ntohl(length);
+
+ return true;
+}
+
+void QRfbRawEncoder::write()
+{
+// QVncDirtyMap *map = server->dirtyMap();
+ QTcpSocket *socket = client->clientSocket();
+
+ const int bytesPerPixel = client->clientBytesPerPixel();
+
+ // create a region from the dirty rects and send the region's merged rects.
+ // ### use the tile map again
+ QRegion rgn = client->dirtyRegion();
+ qCDebug(lcVnc) << "QRfbRawEncoder::write()" << rgn;
+// if (map) {
+// for (int y = 0; y < map->mapHeight; ++y) {
+// for (int x = 0; x < map->mapWidth; ++x) {
+// if (!map->dirty(x, y))
+// continue;
+// rgn += QRect(x * MAP_TILE_SIZE, y * MAP_TILE_SIZE,
+// MAP_TILE_SIZE, MAP_TILE_SIZE);
+// map->setClean(x, y);
+// }
+// }
+
+// rgn &= QRect(0, 0, server->screen()->geometry().width(),
+// server->screen()->geometry().height());
+// }
+ const QVector<QRect> rects = rgn.rects();
+
+ {
+ const char tmp[2] = { 0, 0 }; // msg type, padding
+ socket->write(tmp, sizeof(tmp));
+ }
+
+ {
+ const quint16 count = htons(rects.size());
+ socket->write((char *)&count, sizeof(count));
+ }
+
+ if (rects.size() <= 0)
+ return;
+
+ const QImage screenImage = client->server()->screenImage();
+
+ for (const QRect &tileRect: rects) {
+ const QRfbRect rect(tileRect.x(), tileRect.y(),
+ tileRect.width(), tileRect.height());
+ rect.write(socket);
+
+ const quint32 encoding = htonl(0); // raw encoding
+ socket->write((char *)&encoding, sizeof(encoding));
+
+ int linestep = screenImage.bytesPerLine();
+ const uchar *screendata = screenImage.scanLine(rect.y)
+ + rect.x * screenImage.depth() / 8;
+
+ if (client->doPixelConversion()) {
+ const int bufferSize = rect.w * rect.h * bytesPerPixel;
+ if (bufferSize > buffer.size())
+ buffer.resize(bufferSize);
+
+ // convert pixels
+ char *b = buffer.data();
+ const int bstep = rect.w * bytesPerPixel;
+ for (int i = 0; i < rect.h; ++i) {
+ client->convertPixels(b, (const char*)screendata, rect.w);
+ screendata += linestep;
+ b += bstep;
+ }
+ socket->write(buffer.constData(), bufferSize);
+ } else {
+ for (int i = 0; i < rect.h; ++i) {
+ socket->write((const char*)screendata, rect.w * bytesPerPixel);
+ screendata += linestep;
+ }
+ }
+ if (socket->state() == QAbstractSocket::UnconnectedState)
+ break;
+ }
+ socket->flush();
+}
+
+QVncClientCursor::QVncClientCursor()
+{
+ QWindow *w = QGuiApplication::focusWindow();
+ QCursor c = w ? w->cursor() : QCursor(Qt::ArrowCursor);
+ changeCursor(&c, 0);
+}
+
+QVncClientCursor::~QVncClientCursor()
+{
+}
+
+void QVncClientCursor::write(QVncClient *client) const
+{
+ QTcpSocket *socket = client->clientSocket();
+
+ // FramebufferUpdate header
+ {
+ const quint16 tmp[6] = { htons(0),
+ htons(1),
+ htons(hotspot.x()), htons(hotspot.y()),
+ htons(cursor.width()),
+ htons(cursor.height()) };
+ socket->write((char*)tmp, sizeof(tmp));
+
+ const quint32 encoding = htonl(-239);
+ socket->write((char*)(&encoding), sizeof(encoding));
+ }
+
+ if (cursor.isNull())
+ return;
+
+ // write pixels
+ Q_ASSERT(cursor.hasAlphaChannel());
+ const QImage img = cursor.convertToFormat(client->server()->screen()->format());
+ const int n = client->clientBytesPerPixel() * img.width();
+ char *buffer = new char[n];
+ for (int i = 0; i < img.height(); ++i) {
+ client->convertPixels(buffer, (const char*)img.scanLine(i), img.width());
+ socket->write(buffer, n);
+ }
+ delete[] buffer;
+
+ // write mask
+ const QImage bitmap = cursor.createAlphaMask().convertToFormat(QImage::Format_Mono);
+ Q_ASSERT(bitmap.depth() == 1);
+ Q_ASSERT(bitmap.size() == img.size());
+ const int width = (bitmap.width() + 7) / 8;
+ for (int i = 0; i < bitmap.height(); ++i)
+ socket->write((const char*)bitmap.scanLine(i), width);
+}
+
+#ifndef QT_NO_CURSOR
+void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window)
+{
+ Q_UNUSED(window);
+ const Qt::CursorShape shape = widgetCursor ? widgetCursor->shape() : Qt::ArrowCursor;
+
+ if (shape == Qt::BitmapCursor) {
+ // application supplied cursor
+ hotspot = widgetCursor->hotSpot();
+ cursor = widgetCursor->pixmap().toImage();
+ } else {
+ // system cursor
+ QPlatformCursorImage platformImage(0, 0, 0, 0, 0, 0);
+ platformImage.set(shape);
+ cursor = *platformImage.image();
+ hotspot = platformImage.hotspot();
+ }
+ for (auto client : clients)
+ client->setDirtyCursor();
+}
+
+void QVncClientCursor::addClient(QVncClient *client)
+{
+ if (!clients.contains(client))
+ clients.append(client);
+}
+
+uint QVncClientCursor::removeClient(QVncClient *client)
+{
+ clients.removeOne(client);
+ return clients.count();
+}
+#endif
+
+QVncServer::QVncServer(QVncScreen *screen, quint16 port)
+ : qvnc_screen(screen)
+ , m_port(port)
+{
+ QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection);
+}
+
+void QVncServer::init()
+{
+ serverSocket = new QTcpServer(this);
+ if (!serverSocket->listen(QHostAddress::Any, m_port))
+ qWarning() << "QVncServer could not connect:" << serverSocket->errorString();
+ else
+ qWarning("QVncServer created on port %d", m_port);
+
+ connect(serverSocket, SIGNAL(newConnection()), this, SLOT(newConnection()));
+
+}
+
+QVncServer::~QVncServer()
+{
+ for (auto client : clients) {
+ delete client;
+ }
+}
+
+void QVncServer::setDirty()
+{
+ for (auto client : clients) {
+ client->setDirty(qvnc_screen->dirtyRegion);
+ }
+ qvnc_screen->clearDirty();
+}
+
+
+void QVncServer::newConnection()
+{
+ auto clientSocket = serverSocket->nextPendingConnection();
+ clients.append(new QVncClient(clientSocket, this));
+
+ dirtyMap()->reset();
+
+ qCDebug(lcVnc) << "new Connection from: " << clientSocket->localAddress();
+
+ qvnc_screen->setPowerState(QPlatformScreen::PowerStateOn);
+}
+
+void QVncServer::discardClient(QVncClient *client)
+{
+ clients.removeOne(client);
+ client->deleteLater();
+ if (clients.isEmpty()) {
+ qvnc_screen->disableClientCursor(client);
+ qvnc_screen->setPowerState(QPlatformScreen::PowerStateOff);
+ }
+}
+
+inline QImage QVncServer::screenImage() const
+{
+ return *qvnc_screen->image();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/vnc/qvnc_p.h b/src/plugins/platforms/vnc/qvnc_p.h
new file mode 100644
index 0000000000..1c44cd1569
--- /dev/null
+++ b/src/plugins/platforms/vnc/qvnc_p.h
@@ -0,0 +1,417 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVNC_P_H
+#define QVNC_P_H
+
+#include "qvncscreen.h"
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qvarlengtharray.h>
+#include <qpa/qplatformcursor.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcVnc)
+
+class QTcpSocket;
+class QTcpServer;
+
+class QVncScreen;
+class QVncServer;
+class QVncClientCursor;
+class QVncClient;
+
+// This fits with the VNC hextile messages
+#define MAP_TILE_SIZE 16
+
+class QVncDirtyMap
+{
+public:
+ QVncDirtyMap(QVncScreen *screen);
+ virtual ~QVncDirtyMap();
+
+ void reset();
+ bool dirty(int x, int y) const;
+ virtual void setDirty(int x, int y, bool force = false) = 0;
+ void setClean(int x, int y);
+
+ QVncScreen *screen;
+ int bytesPerPixel;
+ int numDirty;
+ int mapWidth;
+ int mapHeight;
+
+protected:
+ uchar *map;
+ uchar *buffer;
+ int bufferWidth;
+ int bufferHeight;
+ int bufferStride;
+ int numTiles;
+};
+
+template <class T>
+class QVncDirtyMapOptimized : public QVncDirtyMap
+{
+public:
+ QVncDirtyMapOptimized(QVncScreen *screen) : QVncDirtyMap(screen) {}
+ ~QVncDirtyMapOptimized() {}
+
+ void setDirty(int x, int y, bool force = false);
+};
+
+
+class QRfbRect
+{
+public:
+ QRfbRect() {}
+ QRfbRect(quint16 _x, quint16 _y, quint16 _w, quint16 _h) {
+ x = _x; y = _y; w = _w; h = _h;
+ }
+
+ void read(QTcpSocket *s);
+ void write(QTcpSocket *s) const;
+
+ quint16 x;
+ quint16 y;
+ quint16 w;
+ quint16 h;
+};
+
+class QRfbPixelFormat
+{
+public:
+ static int size() { return 16; }
+
+ void read(QTcpSocket *s);
+ void write(QTcpSocket *s);
+
+ int bitsPerPixel;
+ int depth;
+ bool bigEndian;
+ bool trueColor;
+ int redBits;
+ int greenBits;
+ int blueBits;
+ int redShift;
+ int greenShift;
+ int blueShift;
+};
+
+class QRfbServerInit
+{
+public:
+ QRfbServerInit() { name = 0; }
+ ~QRfbServerInit() { delete[] name; }
+
+ int size() const { return QRfbPixelFormat::size() + 8 + strlen(name); }
+ void setName(const char *n);
+
+ void read(QTcpSocket *s);
+ void write(QTcpSocket *s);
+
+ quint16 width;
+ quint16 height;
+ QRfbPixelFormat format;
+ char *name;
+};
+
+class QRfbSetEncodings
+{
+public:
+ bool read(QTcpSocket *s);
+
+ quint16 count;
+};
+
+class QRfbFrameBufferUpdateRequest
+{
+public:
+ bool read(QTcpSocket *s);
+
+ char incremental;
+ QRfbRect rect;
+};
+
+class QRfbKeyEvent
+{
+public:
+ bool read(QTcpSocket *s);
+
+ char down;
+ int keycode;
+ int unicode;
+};
+
+class QRfbPointerEvent
+{
+public:
+ bool read(QTcpSocket *s);
+
+ Qt::MouseButtons buttons;
+ quint16 x;
+ quint16 y;
+};
+
+class QRfbClientCutText
+{
+public:
+ bool read(QTcpSocket *s);
+
+ quint32 length;
+};
+
+class QRfbEncoder
+{
+public:
+ QRfbEncoder(QVncClient *s) : client(s) {}
+ virtual ~QRfbEncoder() {}
+
+ virtual void write() = 0;
+
+protected:
+ QVncClient *client;
+};
+
+class QRfbRawEncoder : public QRfbEncoder
+{
+public:
+ QRfbRawEncoder(QVncClient *s) : QRfbEncoder(s) {}
+
+ void write();
+
+private:
+ QByteArray buffer;
+};
+
+template <class SRC> class QRfbHextileEncoder;
+
+template <class SRC>
+class QRfbSingleColorHextile
+{
+public:
+ QRfbSingleColorHextile(QRfbHextileEncoder<SRC> *e) : encoder(e) {}
+ bool read(const uchar *data, int width, int height, int stride);
+ void write(QTcpSocket *socket) const;
+
+private:
+ QRfbHextileEncoder<SRC> *encoder;
+};
+
+template <class SRC>
+class QRfbDualColorHextile
+{
+public:
+ QRfbDualColorHextile(QRfbHextileEncoder<SRC> *e) : encoder(e) {}
+ bool read(const uchar *data, int width, int height, int stride);
+ void write(QTcpSocket *socket) const;
+
+private:
+ struct Rect {
+ quint8 xy;
+ quint8 wh;
+ } Q_PACKED rects[8 * 16];
+
+ quint8 numRects;
+ QRfbHextileEncoder<SRC> *encoder;
+
+private:
+ inline int lastx() const { return rectx(numRects); }
+ inline int lasty() const { return recty(numRects); }
+ inline int rectx(int r) const { return rects[r].xy >> 4; }
+ inline int recty(int r) const { return rects[r].xy & 0x0f; }
+ inline int width(int r) const { return (rects[r].wh >> 4) + 1; }
+ inline int height(int r) const { return (rects[r].wh & 0x0f) + 1; }
+
+ inline void setX(int r, int x) {
+ rects[r].xy = (x << 4) | (rects[r].xy & 0x0f);
+ }
+ inline void setY(int r, int y) {
+ rects[r].xy = (rects[r].xy & 0xf0) | y;
+ }
+ inline void setWidth(int r, int width) {
+ rects[r].wh = ((width - 1) << 4) | (rects[r].wh & 0x0f);
+ }
+ inline void setHeight(int r, int height) {
+ rects[r].wh = (rects[r].wh & 0xf0) | (height - 1);
+ }
+
+ inline void setWidth(int width) { setWidth(numRects, width); }
+ inline void setHeight(int height) { setHeight(numRects, height); }
+ inline void setX(int x) { setX(numRects, x); }
+ inline void setY(int y) { setY(numRects, y); }
+ void next();
+};
+
+template <class SRC>
+class QRfbMultiColorHextile
+{
+public:
+ QRfbMultiColorHextile(QRfbHextileEncoder<SRC> *e) : encoder(e) {}
+ bool read(const uchar *data, int width, int height, int stride);
+ void write(QTcpSocket *socket) const;
+
+private:
+ inline quint8* rect(int r) {
+ return rects.data() + r * (bpp + 2);
+ }
+ inline const quint8* rect(int r) const {
+ return rects.constData() + r * (bpp + 2);
+ }
+ inline void setX(int r, int x) {
+ quint8 *ptr = rect(r) + bpp;
+ *ptr = (x << 4) | (*ptr & 0x0f);
+ }
+ inline void setY(int r, int y) {
+ quint8 *ptr = rect(r) + bpp;
+ *ptr = (*ptr & 0xf0) | y;
+ }
+ void setColor(SRC color);
+ inline int rectx(int r) const {
+ const quint8 *ptr = rect(r) + bpp;
+ return *ptr >> 4;
+ }
+ inline int recty(int r) const {
+ const quint8 *ptr = rect(r) + bpp;
+ return *ptr & 0x0f;
+ }
+ inline void setWidth(int r, int width) {
+ quint8 *ptr = rect(r) + bpp + 1;
+ *ptr = ((width - 1) << 4) | (*ptr & 0x0f);
+ }
+ inline void setHeight(int r, int height) {
+ quint8 *ptr = rect(r) + bpp + 1;
+ *ptr = (*ptr & 0xf0) | (height - 1);
+ }
+
+ bool beginRect();
+ void endRect();
+
+ static const int maxRectsSize = 16 * 16;
+ QVarLengthArray<quint8, maxRectsSize> rects;
+
+ quint8 bpp;
+ quint8 numRects;
+ QRfbHextileEncoder<SRC> *encoder;
+};
+
+template <class SRC>
+class QRfbHextileEncoder : public QRfbEncoder
+{
+public:
+ QRfbHextileEncoder(QVncServer *s);
+ void write();
+
+private:
+ enum SubEncoding {
+ Raw = 1,
+ BackgroundSpecified = 2,
+ ForegroundSpecified = 4,
+ AnySubrects = 8,
+ SubrectsColoured = 16
+ };
+
+ QByteArray buffer;
+ QRfbSingleColorHextile<SRC> singleColorHextile;
+ QRfbDualColorHextile<SRC> dualColorHextile;
+ QRfbMultiColorHextile<SRC> multiColorHextile;
+
+ SRC bg;
+ SRC fg;
+ bool newBg;
+ bool newFg;
+
+ friend class QRfbSingleColorHextile<SRC>;
+ friend class QRfbDualColorHextile<SRC>;
+ friend class QRfbMultiColorHextile<SRC>;
+};
+
+class QVncClientCursor : public QPlatformCursor
+{
+public:
+ QVncClientCursor();
+ ~QVncClientCursor();
+
+ void write(QVncClient *client) const;
+
+ void changeCursor(QCursor *widgetCursor, QWindow *window);
+
+ void addClient(QVncClient *client);
+ uint removeClient(QVncClient *client);
+
+ QImage cursor;
+ QPoint hotspot;
+ QVector<QVncClient *> clients;
+};
+
+
+class QVncServer : public QObject
+{
+ Q_OBJECT
+public:
+ QVncServer(QVncScreen *screen, quint16 port = 5900);
+ ~QVncServer();
+
+ enum ServerMsg { FramebufferUpdate = 0,
+ SetColourMapEntries = 1 };
+
+ void setDirty();
+
+
+ inline QVncScreen* screen() const { return qvnc_screen; }
+ inline QVncDirtyMap* dirtyMap() const { return qvnc_screen->dirty; }
+ QImage screenImage() const;
+ void discardClient(QVncClient *client);
+
+private slots:
+ void newConnection();
+ void init();
+
+private:
+ QTcpServer *serverSocket;
+ QVector<QVncClient*> clients;
+ QVncScreen *qvnc_screen;
+ quint16 m_port;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/vnc/qvncclient.cpp b/src/plugins/platforms/vnc/qvncclient.cpp
new file mode 100644
index 0000000000..dae3e83f37
--- /dev/null
+++ b/src/plugins/platforms/vnc/qvncclient.cpp
@@ -0,0 +1,662 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvncclient.h"
+#include "qvnc_p.h"
+
+#include <QtNetwork/QTcpSocket>
+#include <QtCore/QCoreApplication>
+
+#include <qpa/qwindowsysteminterface.h>
+#include <QtGui/qguiapplication.h>
+
+#ifdef Q_OS_WIN
+#include <Winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QVncClient::QVncClient(QTcpSocket *clientSocket, QVncServer *server)
+ : QObject(server)
+ , m_server(server)
+ , m_clientSocket(clientSocket)
+ , m_encoder(nullptr)
+ , m_msgType(0)
+ , m_handleMsg(false)
+ , m_encodingsPending(0)
+ , m_cutTextPending(0)
+ , m_supportHextile(false)
+ , m_wantUpdate(false)
+ , m_keymod(0)
+ , m_dirtyCursor(false)
+ , m_updatePending(false)
+ , m_protocolVersion(V3_3)
+{
+ connect(m_clientSocket,SIGNAL(readyRead()),this,SLOT(readClient()));
+ connect(m_clientSocket,SIGNAL(disconnected()),this,SLOT(discardClient()));
+
+ // send protocol version
+ const char *proto = "RFB 003.003\n";
+ m_clientSocket->write(proto, 12);
+ m_state = Protocol;
+}
+
+QVncClient::~QVncClient()
+{
+ delete m_encoder;
+}
+
+QTcpSocket *QVncClient::clientSocket() const
+{
+ return m_clientSocket;
+}
+
+void QVncClient::setDirty(const QRegion &region)
+{
+ m_dirtyRegion += region;
+ if (m_state == Connected &&
+ ((m_server->dirtyMap()->numDirty > 0) || m_dirtyCursor)) {
+ scheduleUpdate();
+ }
+}
+
+void QVncClient::convertPixels(char *dst, const char *src, int count) const
+{
+ const int screendepth = m_server->screen()->depth();
+
+ // cutoffs
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ if (!m_swapBytes)
+#endif
+ if (m_sameEndian) {
+ if (screendepth == m_pixelFormat.bitsPerPixel) { // memcpy cutoffs
+
+ switch (screendepth) {
+ case 32:
+ memcpy(dst, src, count * sizeof(quint32));
+ return;
+ case 16:
+ if (m_pixelFormat.redBits == 5
+ && m_pixelFormat.greenBits == 6
+ && m_pixelFormat.blueBits == 5)
+ {
+ memcpy(dst, src, count * sizeof(quint16));
+ return;
+ }
+ }
+ }
+ }
+
+ const int bytesPerPixel = (m_pixelFormat.bitsPerPixel + 7) / 8;
+
+ for (int i = 0; i < count; ++i) {
+ int r, g, b;
+
+ switch (screendepth) {
+ case 8: {
+ QRgb rgb = m_server->screen()->image()->colorTable()[int(*src)];
+ r = qRed(rgb);
+ g = qGreen(rgb);
+ b = qBlue(rgb);
+ src++;
+ break;
+ }
+ case 16: {
+ quint16 p = *reinterpret_cast<const quint16*>(src);
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ if (swapBytes)
+ p = ((p & 0xff) << 8) | ((p & 0xff00) >> 8);
+#endif
+ r = (p >> 11) & 0x1f;
+ g = (p >> 5) & 0x3f;
+ b = p & 0x1f;
+ r <<= 3;
+ g <<= 2;
+ b <<= 3;
+ src += sizeof(quint16);
+ break;
+ }
+ case 32: {
+ quint32 p = *reinterpret_cast<const quint32*>(src);
+ r = (p >> 16) & 0xff;
+ g = (p >> 8) & 0xff;
+ b = p & 0xff;
+ src += sizeof(quint32);
+ break;
+ }
+ default: {
+ r = g = b = 0;
+ qWarning("QVNCServer: don't support %dbpp display", screendepth);
+ return;
+ }
+ }
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ if (m_swapBytes)
+ qSwap(r, b);
+#endif
+
+ r >>= (8 - m_pixelFormat.redBits);
+ g >>= (8 - m_pixelFormat.greenBits);
+ b >>= (8 - m_pixelFormat.blueBits);
+
+ int pixel = (r << m_pixelFormat.redShift) |
+ (g << m_pixelFormat.greenShift) |
+ (b << m_pixelFormat.blueShift);
+
+ if (m_sameEndian || m_pixelFormat.bitsPerPixel == 8) {
+ memcpy(dst, &pixel, bytesPerPixel);
+ dst += bytesPerPixel;
+ continue;
+ }
+
+
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ switch (m_pixelFormat.bitsPerPixel) {
+ case 16:
+ pixel = (((pixel & 0x0000ff00) << 8) |
+ ((pixel & 0x000000ff) << 24));
+ break;
+ case 32:
+ pixel = (((pixel & 0xff000000) >> 24) |
+ ((pixel & 0x00ff0000) >> 8) |
+ ((pixel & 0x0000ff00) << 8) |
+ ((pixel & 0x000000ff) << 24));
+ break;
+ default:
+ qWarning("Cannot handle %d bpp client", m_pixelFormat.bitsPerPixel);
+ }
+ } else { // QSysInfo::ByteOrder == QSysInfo::LittleEndian
+ switch (m_pixelFormat.bitsPerPixel) {
+ case 16:
+ pixel = (((pixel & 0xff000000) >> 8) |
+ ((pixel & 0x00ff0000) << 8));
+ break;
+ case 32:
+ pixel = (((pixel & 0xff000000) >> 24) |
+ ((pixel & 0x00ff0000) >> 8) |
+ ((pixel & 0x0000ff00) << 8) |
+ ((pixel & 0x000000ff) << 24));
+ break;
+ default:
+ qWarning("Cannot handle %d bpp client",
+ m_pixelFormat.bitsPerPixel);
+ break;
+ }
+ }
+ memcpy(dst, &pixel, bytesPerPixel);
+ dst += bytesPerPixel;
+ }
+}
+
+void QVncClient::readClient()
+{
+ qCDebug(lcVnc) << "readClient" << m_state;
+ switch (m_state) {
+ case Disconnected:
+
+ break;
+ case Protocol:
+ if (m_clientSocket->bytesAvailable() >= 12) {
+ char proto[13];
+ m_clientSocket->read(proto, 12);
+ proto[12] = '\0';
+ qCDebug(lcVnc, "Client protocol version %s", proto);
+ if (!strcmp(proto, "RFB 003.008\n")) {
+ m_protocolVersion = V3_8;
+ } else if (!strcmp(proto, "RFB 003.007\n")) {
+ m_protocolVersion = V3_7;
+ } else {
+ m_protocolVersion = V3_3;
+ }
+
+ if (m_protocolVersion == V3_3) {
+ // No authentication
+ quint32 auth = htonl(1);
+ m_clientSocket->write((char *) &auth, sizeof(auth));
+ m_state = Init;
+ }
+ }
+ break;
+ case Authentication:
+
+ break;
+ case Init:
+ if (m_clientSocket->bytesAvailable() >= 1) {
+ quint8 shared;
+ m_clientSocket->read((char *) &shared, 1);
+
+ // Server Init msg
+ QRfbServerInit sim;
+ QRfbPixelFormat &format = sim.format;
+ switch (m_server->screen()->depth()) {
+ case 32:
+ format.bitsPerPixel = 32;
+ format.depth = 32;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 8;
+ format.greenBits = 8;
+ format.blueBits = 8;
+ format.redShift = 16;
+ format.greenShift = 8;
+ format.blueShift = 0;
+ break;
+
+ case 24:
+ format.bitsPerPixel = 24;
+ format.depth = 24;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 8;
+ format.greenBits = 8;
+ format.blueBits = 8;
+ format.redShift = 16;
+ format.greenShift = 8;
+ format.blueShift = 0;
+ break;
+
+ case 18:
+ format.bitsPerPixel = 24;
+ format.depth = 18;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 6;
+ format.greenBits = 6;
+ format.blueBits = 6;
+ format.redShift = 12;
+ format.greenShift = 6;
+ format.blueShift = 0;
+ break;
+
+ case 16:
+ format.bitsPerPixel = 16;
+ format.depth = 16;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 5;
+ format.greenBits = 6;
+ format.blueBits = 5;
+ format.redShift = 11;
+ format.greenShift = 5;
+ format.blueShift = 0;
+ break;
+
+ case 15:
+ format.bitsPerPixel = 16;
+ format.depth = 15;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 5;
+ format.greenBits = 5;
+ format.blueBits = 5;
+ format.redShift = 10;
+ format.greenShift = 5;
+ format.blueShift = 0;
+ break;
+
+ case 12:
+ format.bitsPerPixel = 16;
+ format.depth = 12;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 4;
+ format.greenBits = 4;
+ format.blueBits = 4;
+ format.redShift = 8;
+ format.greenShift = 4;
+ format.blueShift = 0;
+ break;
+
+ case 8:
+ case 4:
+ format.bitsPerPixel = 8;
+ format.depth = 8;
+ format.bigEndian = 0;
+ format.trueColor = false;
+ format.redBits = 0;
+ format.greenBits = 0;
+ format.blueBits = 0;
+ format.redShift = 0;
+ format.greenShift = 0;
+ format.blueShift = 0;
+ break;
+
+ default:
+ qWarning("QVNC cannot drive depth %d", m_server->screen()->depth());
+ discardClient();
+ return;
+ }
+ sim.width = m_server->screen()->geometry().width();
+ sim.height = m_server->screen()->geometry().height();
+ sim.setName("Qt for Embedded Linux VNC Server");
+ sim.write(m_clientSocket);
+ m_state = Connected;
+ }
+ break;
+
+ case Connected:
+ do {
+ if (!m_handleMsg) {
+ m_clientSocket->read((char *)&m_msgType, 1);
+ m_handleMsg = true;
+ }
+ if (m_handleMsg) {
+ switch (m_msgType ) {
+ case SetPixelFormat:
+ setPixelFormat();
+ break;
+ case FixColourMapEntries:
+ qWarning("Not supported: FixColourMapEntries");
+ m_handleMsg = false;
+ break;
+ case SetEncodings:
+ setEncodings();
+ break;
+ case FramebufferUpdateRequest:
+ frameBufferUpdateRequest();
+ break;
+ case KeyEvent:
+ keyEvent();
+ break;
+ case PointerEvent:
+ pointerEvent();
+ break;
+ case ClientCutText:
+ clientCutText();
+ break;
+ default:
+ qWarning("Unknown message type: %d", (int)m_msgType);
+ m_handleMsg = false;
+ }
+ }
+ } while (!m_handleMsg && m_clientSocket->bytesAvailable());
+ break;
+ default:
+ break;
+ }
+}
+
+void QVncClient::discardClient()
+{
+ m_state = Disconnected;
+ m_server->discardClient(this);
+}
+
+void QVncClient::checkUpdate()
+{
+ if (!m_wantUpdate)
+ return;
+
+ if (m_dirtyCursor) {
+ m_server->screen()->clientCursor->write(this);
+ m_dirtyCursor = false;
+ m_wantUpdate = false;
+ return;
+ }
+
+ if (!m_dirtyRegion.isEmpty()) {
+ if (m_encoder)
+ m_encoder->write();
+ m_wantUpdate = false;
+ m_dirtyRegion = QRegion();
+ }
+}
+
+void QVncClient::scheduleUpdate()
+{
+ if (!m_updatePending) {
+ m_updatePending = true;
+ QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
+ }
+}
+
+bool QVncClient::event(QEvent *event)
+{
+ if (event->type() == QEvent::UpdateRequest) {
+ m_updatePending = false;
+ checkUpdate();
+ return true;
+ }
+ return QObject::event(event);
+}
+
+void QVncClient::setPixelFormat()
+{
+ if (m_clientSocket->bytesAvailable() >= 19) {
+ char buf[3];
+ m_clientSocket->read(buf, 3); // just padding
+ m_pixelFormat.read(m_clientSocket);
+ qCDebug(lcVnc, "Want format: %d %d %d %d %d %d %d %d %d %d",
+ int(m_pixelFormat.bitsPerPixel),
+ int(m_pixelFormat.depth),
+ int(m_pixelFormat.bigEndian),
+ int(m_pixelFormat.trueColor),
+ int(m_pixelFormat.redBits),
+ int(m_pixelFormat.greenBits),
+ int(m_pixelFormat.blueBits),
+ int(m_pixelFormat.redShift),
+ int(m_pixelFormat.greenShift),
+ int(m_pixelFormat.blueShift));
+ if (!m_pixelFormat.trueColor) {
+ qWarning("Can only handle true color clients");
+ discardClient();
+ }
+ m_handleMsg = false;
+ m_sameEndian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) == !!m_pixelFormat.bigEndian;
+ m_needConversion = pixelConversionNeeded();
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ m_swapBytes = qvnc_screen->swapBytes();
+#endif
+ }
+}
+
+void QVncClient::setEncodings()
+{
+ QRfbSetEncodings enc;
+
+ if (!m_encodingsPending && enc.read(m_clientSocket)) {
+ m_encodingsPending = enc.count;
+ if (!m_encodingsPending)
+ m_handleMsg = false;
+ }
+
+ if (m_encoder) {
+ delete m_encoder;
+ m_encoder = nullptr;
+ }
+
+ enum Encodings {
+ Raw = 0,
+ CopyRect = 1,
+ RRE = 2,
+ CoRRE = 4,
+ Hextile = 5,
+ ZRLE = 16,
+ Cursor = -239,
+ DesktopSize = -223
+ };
+
+ if (m_encodingsPending && (unsigned)m_clientSocket->bytesAvailable() >=
+ m_encodingsPending * sizeof(quint32)) {
+ for (int i = 0; i < m_encodingsPending; ++i) {
+ qint32 enc;
+ m_clientSocket->read((char *)&enc, sizeof(qint32));
+ enc = ntohl(enc);
+ qCDebug(lcVnc, "QVncServer::setEncodings: %d", enc);
+ switch (enc) {
+ case Raw:
+ if (!m_encoder) {
+ m_encoder = new QRfbRawEncoder(this);
+ qCDebug(lcVnc, "QVncServer::setEncodings: using raw");
+ }
+ break;
+ case CopyRect:
+ m_supportCopyRect = true;
+ break;
+ case RRE:
+ m_supportRRE = true;
+ break;
+ case CoRRE:
+ m_supportCoRRE = true;
+ break;
+ case Hextile:
+ m_supportHextile = true;
+ if (m_encoder)
+ break;
+ break;
+ case ZRLE:
+ m_supportZRLE = true;
+ break;
+ case Cursor:
+ m_supportCursor = true;
+ m_server->screen()->enableClientCursor(this);
+ break;
+ case DesktopSize:
+ m_supportDesktopSize = true;
+ break;
+ default:
+ break;
+ }
+ }
+ m_handleMsg = false;
+ m_encodingsPending = 0;
+ }
+
+ if (!m_encoder) {
+ m_encoder = new QRfbRawEncoder(this);
+ qCDebug(lcVnc, "QVncServer::setEncodings: fallback using raw");
+ }
+}
+
+void QVncClient::frameBufferUpdateRequest()
+{
+ qCDebug(lcVnc) << "FramebufferUpdateRequest";
+ QRfbFrameBufferUpdateRequest ev;
+
+ if (ev.read(m_clientSocket)) {
+ if (!ev.incremental) {
+ QRect r(ev.rect.x, ev.rect.y, ev.rect.w, ev.rect.h);
+ r.translate(m_server->screen()->geometry().topLeft());
+ setDirty(r);
+ }
+ m_wantUpdate = true;
+ checkUpdate();
+ m_handleMsg = false;
+ }
+}
+
+void QVncClient::pointerEvent()
+{
+ QRfbPointerEvent ev;
+ if (ev.read(m_clientSocket)) {
+ const QPoint pos = m_server->screen()->geometry().topLeft() + QPoint(ev.x, ev.y);
+ QWindowSystemInterface::handleMouseEvent(0, pos, pos, ev.buttons, QGuiApplication::keyboardModifiers());
+ m_handleMsg = false;
+ }
+}
+
+void QVncClient::keyEvent()
+{
+ QRfbKeyEvent ev;
+
+ if (ev.read(m_clientSocket)) {
+ if (ev.keycode == Qt::Key_Shift)
+ m_keymod = ev.down ? m_keymod | Qt::ShiftModifier :
+ m_keymod & ~Qt::ShiftModifier;
+ else if (ev.keycode == Qt::Key_Control)
+ m_keymod = ev.down ? m_keymod | Qt::ControlModifier :
+ m_keymod & ~Qt::ControlModifier;
+ else if (ev.keycode == Qt::Key_Alt)
+ m_keymod = ev.down ? m_keymod | Qt::AltModifier :
+ m_keymod & ~Qt::AltModifier;
+ if (ev.unicode || ev.keycode)
+ QWindowSystemInterface::handleKeyEvent(0, ev.down ? QEvent::KeyPress : QEvent::KeyRelease, ev.keycode, m_keymod, QString(ev.unicode));
+ m_handleMsg = false;
+ }
+}
+
+void QVncClient::clientCutText()
+{
+ QRfbClientCutText ev;
+
+ if (m_cutTextPending == 0 && ev.read(m_clientSocket)) {
+ m_cutTextPending = ev.length;
+ if (!m_cutTextPending)
+ m_handleMsg = false;
+ }
+
+ if (m_cutTextPending && m_clientSocket->bytesAvailable() >= m_cutTextPending) {
+ char *text = new char [m_cutTextPending+1];
+ m_clientSocket->read(text, m_cutTextPending);
+ delete [] text;
+ m_cutTextPending = 0;
+ m_handleMsg = false;
+ }
+}
+
+bool QVncClient::pixelConversionNeeded() const
+{
+ if (!m_sameEndian)
+ return true;
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ if (qvnc_screen->swapBytes())
+ return true;
+#endif
+
+ const int screendepth = m_server->screen()->depth();
+ if (screendepth != m_pixelFormat.bitsPerPixel)
+ return true;
+
+ switch (screendepth) {
+ case 32:
+ case 24:
+ return false;
+ case 16:
+ return (m_pixelFormat.redBits == 5
+ && m_pixelFormat.greenBits == 6
+ && m_pixelFormat.blueBits == 5);
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/vnc/qvncclient.h b/src/plugins/platforms/vnc/qvncclient.h
new file mode 100644
index 0000000000..a7a6b6b361
--- /dev/null
+++ b/src/plugins/platforms/vnc/qvncclient.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVNCCLIENT_H
+#define QVNCCLIENT_H
+
+#include <QObject>
+
+#include "qvnc_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QTcpSocket;
+class QVncServer;
+
+class QVncClient : public QObject
+{
+ Q_OBJECT
+public:
+ enum ClientMsg {
+ SetPixelFormat = 0,
+ FixColourMapEntries = 1,
+ SetEncodings = 2,
+ FramebufferUpdateRequest = 3,
+ KeyEvent = 4,
+ PointerEvent = 5,
+ ClientCutText = 6
+ };
+
+ explicit QVncClient(QTcpSocket *clientSocket, QVncServer *server);
+ ~QVncClient();
+ QTcpSocket *clientSocket() const;
+ QVncServer *server() const { return m_server; }
+
+ void setDirty(const QRegion &region);
+ void setDirtyCursor() { m_dirtyCursor = true; scheduleUpdate(); }
+ QRegion dirtyRegion() const { return m_dirtyRegion; }
+ inline bool isConnected() const { return m_state == Connected; }
+
+ inline int clientBytesPerPixel() const {
+ return m_pixelFormat.bitsPerPixel / 8;
+ }
+
+ void convertPixels(char *dst, const char *src, int count) const;
+ inline bool doPixelConversion() const { return m_needConversion; }
+
+signals:
+
+private slots:
+ void readClient();
+ void discardClient();
+ void checkUpdate();
+ void scheduleUpdate();
+
+protected:
+ bool event(QEvent *event) override;
+
+private:
+ enum ClientState {
+ Disconnected,
+ Protocol,
+ Authentication,
+ Init,
+ Connected
+ };
+ enum ProtocolVersion {
+ V3_3,
+ V3_7,
+ V3_8
+ };
+
+ void setPixelFormat();
+ void setEncodings();
+ void frameBufferUpdateRequest();
+ void pointerEvent();
+ void keyEvent();
+ void clientCutText();
+ bool pixelConversionNeeded() const;
+
+ QVncServer *m_server;
+ QTcpSocket *m_clientSocket;
+ QRfbEncoder *m_encoder;
+
+ // Client State
+ ClientState m_state;
+ quint8 m_msgType;
+ bool m_handleMsg;
+ QRfbPixelFormat m_pixelFormat;
+ bool m_sameEndian;
+ bool m_needConversion;
+ int m_encodingsPending;
+ int m_cutTextPending;
+ uint m_supportCopyRect : 1;
+ uint m_supportRRE : 1;
+ uint m_supportCoRRE : 1;
+ uint m_supportHextile : 1;
+ uint m_supportZRLE : 1;
+ uint m_supportCursor : 1;
+ uint m_supportDesktopSize : 1;
+ bool m_wantUpdate;
+ Qt::KeyboardModifiers m_keymod;
+ bool m_dirtyCursor;
+ bool m_updatePending;
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ bool m_swapBytes;
+#endif
+ QRegion m_dirtyRegion;
+ ProtocolVersion m_protocolVersion;
+};
+
+QT_END_NAMESPACE
+
+#endif // QVNCCLIENT_H
diff --git a/src/plugins/platforms/vnc/qvncintegration.cpp b/src/plugins/platforms/vnc/qvncintegration.cpp
new file mode 100644
index 0000000000..810c5d2a90
--- /dev/null
+++ b/src/plugins/platforms/vnc/qvncintegration.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the FOO module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvncintegration.h"
+#include "qvncscreen.h"
+#include "qvnc_p.h"
+
+#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
+#include <QtPlatformSupport/private/qgenericunixservices_p.h>
+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+
+#include <QtPlatformSupport/private/qfbbackingstore_p.h>
+#include <QtPlatformSupport/private/qfbwindow_p.h>
+#include <QtPlatformSupport/private/qfbcursor_p.h>
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatforminputcontextfactory_p.h>
+#include <private/qinputdevicemanager_p_p.h>
+#ifndef QT_NO_LIBINPUT
+#include <QtPlatformSupport/private/qlibinputhandler_p.h>
+#endif
+
+#include <QtCore/QRegularExpression>
+
+QT_BEGIN_NAMESPACE
+
+QVncIntegration::QVncIntegration(const QStringList &paramList)
+ : m_fontDb(new QGenericUnixFontDatabase),
+ m_services(new QGenericUnixServices)
+{
+ QRegularExpression portRx(QLatin1String("port=(\\d+)"));
+ quint16 port = 5900;
+ for (const QString &arg : paramList) {
+ QRegularExpressionMatch match;
+ if (arg.contains(portRx, &match))
+ port = match.captured(1).toInt();
+ }
+
+ m_primaryScreen = new QVncScreen(paramList);
+ m_server = new QVncServer(m_primaryScreen, port);
+ m_primaryScreen->vncServer = m_server;
+}
+
+QVncIntegration::~QVncIntegration()
+{
+ delete m_server;
+ destroyScreen(m_primaryScreen);
+}
+
+void QVncIntegration::initialize()
+{
+ if (m_primaryScreen->initialize())
+ screenAdded(m_primaryScreen);
+ else
+ qWarning("vnc: Failed to initialize screen");
+
+ m_inputContext = QPlatformInputContextFactory::create();
+
+ m_nativeInterface.reset(new QPlatformNativeInterface);
+
+ // we always have exactly one mouse and keyboard
+ QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount(
+ QInputDeviceManager::DeviceTypePointer, 1);
+ QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount(
+ QInputDeviceManager::DeviceTypeKeyboard, 1);
+
+}
+
+bool QVncIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+ case WindowManagement: return false;
+ default: return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+QPlatformBackingStore *QVncIntegration::createPlatformBackingStore(QWindow *window) const
+{
+ return new QFbBackingStore(window);
+}
+
+QPlatformWindow *QVncIntegration::createPlatformWindow(QWindow *window) const
+{
+ return new QFbWindow(window);
+}
+
+QAbstractEventDispatcher *QVncIntegration::createEventDispatcher() const
+{
+ return createUnixEventDispatcher();
+}
+
+QList<QPlatformScreen *> QVncIntegration::screens() const
+{
+ QList<QPlatformScreen *> list;
+ list.append(m_primaryScreen);
+ return list;
+}
+
+QPlatformFontDatabase *QVncIntegration::fontDatabase() const
+{
+ return m_fontDb.data();
+}
+
+QPlatformServices *QVncIntegration::services() const
+{
+ return m_services.data();
+}
+
+QPlatformNativeInterface *QVncIntegration::nativeInterface() const
+{
+ return m_nativeInterface.data();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/vnc/qvncintegration.h b/src/plugins/platforms/vnc/qvncintegration.h
new file mode 100644
index 0000000000..293ff54376
--- /dev/null
+++ b/src/plugins/platforms/vnc/qvncintegration.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVNCINTEGRATION_H
+#define QVNCINTEGRATION_H
+
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractEventDispatcher;
+class QVncScreen;
+class QVncServer;
+
+class QVncIntegration : public QPlatformIntegration, public QPlatformNativeInterface
+{
+public:
+ QVncIntegration(const QStringList &paramList);
+ ~QVncIntegration();
+
+ void initialize() Q_DECL_OVERRIDE;
+ bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
+
+ QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE;
+
+ QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE;
+
+ QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE;
+ QPlatformServices *services() const Q_DECL_OVERRIDE;
+ QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE { return m_inputContext; }
+
+ QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE;
+
+ QList<QPlatformScreen *> screens() const;
+
+private:
+ mutable QVncServer *m_server;
+ QVncScreen *m_primaryScreen;
+ QPlatformInputContext *m_inputContext;
+ QScopedPointer<QPlatformFontDatabase> m_fontDb;
+ QScopedPointer<QPlatformServices> m_services;
+ QScopedPointer<QPlatformNativeInterface> m_nativeInterface;
+};
+
+QT_END_NAMESPACE
+
+#endif // QVNCINTEGRATION_H
diff --git a/src/plugins/platforms/vnc/qvncscreen.cpp b/src/plugins/platforms/vnc/qvncscreen.cpp
new file mode 100644
index 0000000000..6d117c62bf
--- /dev/null
+++ b/src/plugins/platforms/vnc/qvncscreen.cpp
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvncscreen.h"
+#include "qvnc_p.h"
+#include <QtPlatformSupport/private/qfbwindow_p.h>
+#include <QtPlatformSupport/private/qfbcursor_p.h>
+
+#include <QtGui/QPainter>
+#include <QtCore/QRegularExpression>
+
+
+QT_BEGIN_NAMESPACE
+
+
+QVncScreen::QVncScreen(const QStringList &args)
+ : mArgs(args)
+{
+ initialize();
+}
+
+QVncScreen::~QVncScreen()
+{
+ if (clientCursor)
+ delete clientCursor;
+}
+
+bool QVncScreen::initialize()
+{
+ QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
+ QRegularExpression mmSizeRx(QLatin1String("mmsize=(?<width>(\\d*\\.)?\\d+)x(?<height>(\\d*\\.)?\\d+)"));
+ QRegularExpression depthRx(QLatin1String("depth=(\\d+)"));
+
+ mGeometry = QRect(0, 0, 1024, 768);
+ mFormat = QImage::Format_ARGB32_Premultiplied;
+ mDepth = 32;
+ mPhysicalSize = QSizeF(mGeometry.width()/96.*25.4, mGeometry.height()/96.*25.4);
+
+ for (const QString &arg : mArgs) {
+ QRegularExpressionMatch match;
+ if (arg.contains(mmSizeRx, &match)) {
+ mPhysicalSize = QSizeF(match.captured("width").toDouble(), match.captured("height").toDouble());
+ } else if (arg.contains(sizeRx, &match)) {
+ mGeometry.setSize(QSize(match.captured(1).toInt(), match.captured(2).toInt()));
+ } else if (arg.contains(depthRx, &match)) {
+ mDepth = match.captured(1).toInt();
+ }
+ }
+
+ QFbScreen::initializeCompositor();
+
+ switch (depth()) {
+ case 32:
+ dirty = new QVncDirtyMapOptimized<quint32>(this);
+ break;
+ case 16:
+ dirty = new QVncDirtyMapOptimized<quint16>(this);
+ break;
+ case 8:
+ dirty = new QVncDirtyMapOptimized<quint8>(this);
+ break;
+ default:
+ qWarning("QVNCScreen::initDevice: No support for screen depth %d",
+ depth());
+ dirty = 0;
+ return false;
+ }
+
+ setPowerState(PowerStateOff);
+
+ return true;
+}
+
+QRegion QVncScreen::doRedraw()
+{
+ QRegion touched = QFbScreen::doRedraw();
+
+ if (touched.isEmpty())
+ return touched;
+ dirtyRegion += touched;
+
+ vncServer->setDirty();
+ return touched;
+}
+
+void QVncScreen::enableClientCursor(QVncClient *client)
+{
+ delete mCursor;
+ mCursor = nullptr;
+ if (!clientCursor)
+ clientCursor = new QVncClientCursor();
+ clientCursor->addClient(client);
+}
+
+void QVncScreen::disableClientCursor(QVncClient *client)
+{
+ uint clientCount = clientCursor->removeClient(client);
+ if (clientCount == 0) {
+ delete clientCursor;
+ clientCursor = nullptr;
+ }
+
+ mCursor = new QFbCursor(this);
+}
+
+QPlatformCursor *QVncScreen::cursor() const
+{
+ return mCursor ? static_cast<QPlatformCursor *>(mCursor) : static_cast<QPlatformCursor *>(clientCursor);
+}
+
+// grabWindow() grabs "from the screen" not from the backingstores.
+// In linuxfb's case it will also include the mouse cursor.
+QPixmap QVncScreen::grabWindow(WId wid, int x, int y, int width, int height) const
+{
+ if (!wid) {
+ if (width < 0)
+ width = mScreenImage->width() - x;
+ if (height < 0)
+ height = mScreenImage->height() - y;
+ return QPixmap::fromImage(*mScreenImage).copy(x, y, width, height);
+ }
+
+ QFbWindow *window = windowForId(wid);
+ if (window) {
+ const QRect geom = window->geometry();
+ if (width < 0)
+ width = geom.width() - x;
+ if (height < 0)
+ height = geom.height() - y;
+ QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height));
+ rect &= window->geometry();
+ return QPixmap::fromImage(*mScreenImage).copy(rect);
+ }
+
+ return QPixmap();
+}
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+bool QVNCScreen::swapBytes() const
+{
+ if (depth() != 16)
+ return false;
+
+ if (screen())
+ return screen()->frameBufferLittleEndian();
+ return frameBufferLittleEndian();
+}
+#endif
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platforms/vnc/qvncscreen.h b/src/plugins/platforms/vnc/qvncscreen.h
new file mode 100644
index 0000000000..e3c6651781
--- /dev/null
+++ b/src/plugins/platforms/vnc/qvncscreen.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVncScreen_H
+#define QVncScreen_H
+
+#include <QtPlatformSupport/private/qfbscreen_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPainter;
+class QFbCursor;
+class QTcpSocket;
+class QVncServer;
+class QVncDirtyMap;
+class QVncClientCursor;
+class QVncClient;
+
+class QVncScreen : public QFbScreen
+{
+ Q_OBJECT
+public:
+ QVncScreen(const QStringList &args);
+ ~QVncScreen();
+
+ bool initialize();
+
+ QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE;
+
+ QRegion doRedraw() Q_DECL_OVERRIDE;
+ QImage *image() const { return mScreenImage; }
+
+ void enableClientCursor(QVncClient *client);
+ void disableClientCursor(QVncClient *client);
+ QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
+
+ void clearDirty() { dirtyRegion = QRegion(); }
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ bool swapBytes() const
+#endif
+
+ QStringList mArgs;
+
+ qreal dpiX = 96;
+ qreal dpiY = 96;
+ QVncDirtyMap *dirty = 0;
+ QRegion dirtyRegion;
+ int refreshRate = 30;
+ QVncServer *vncServer = 0;
+ QVncClientCursor *clientCursor = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QVncScreen_H
+
diff --git a/src/plugins/platforms/vnc/vnc.json b/src/plugins/platforms/vnc/vnc.json
new file mode 100644
index 0000000000..6a16b08ca8
--- /dev/null
+++ b/src/plugins/platforms/vnc/vnc.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "vnc" ]
+}
diff --git a/src/plugins/platforms/vnc/vnc.pro b/src/plugins/platforms/vnc/vnc.pro
new file mode 100644
index 0000000000..9a1428ac39
--- /dev/null
+++ b/src/plugins/platforms/vnc/vnc.pro
@@ -0,0 +1,25 @@
+TARGET = qvnc
+
+PLUGIN_TYPE = platforms
+PLUGIN_CLASS_NAME = QVncIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private network
+
+SOURCES = \
+ main.cpp \
+ qvncintegration.cpp \
+ qvncscreen.cpp \
+ qvnc.cpp \
+ qvncclient.cpp
+
+HEADERS = \
+ qvncintegration.h \
+ qvncscreen.h \
+ qvnc_p.h \
+ qvncclient.h
+
+CONFIG += qpa/genericunixfontdatabase
+
+OTHER_FILES += vnc.json
diff --git a/src/plugins/platforms/windows/accessible/accessible.pri b/src/plugins/platforms/windows/accessible/accessible.pri
index 0774d907f2..0e3aacc558 100644
--- a/src/plugins/platforms/windows/accessible/accessible.pri
+++ b/src/plugins/platforms/windows/accessible/accessible.pri
@@ -6,15 +6,13 @@ HEADERS += \
$$PWD/qwindowsaccessibility.h \
$$PWD/comutils.h
-!wince: {
- SOURCES += $$PWD/qwindowsmsaaaccessible.cpp
- HEADERS += $$PWD/qwindowsmsaaaccessible.h
+SOURCES += $$PWD/qwindowsmsaaaccessible.cpp
+HEADERS += $$PWD/qwindowsmsaaaccessible.h
- !mingw: {
- SOURCES += $$PWD/iaccessible2.cpp
- HEADERS += $$PWD/iaccessible2.h
- include(../../../../3rdparty/iaccessible2/iaccessible2.pri)
- }
+!mingw: {
+ SOURCES += $$PWD/iaccessible2.cpp
+ HEADERS += $$PWD/iaccessible2.h
+ include(../../../../3rdparty/iaccessible2/iaccessible2.pri)
}
mingw: LIBS *= -luuid
diff --git a/src/plugins/platforms/windows/accessible/comutils.cpp b/src/plugins/platforms/windows/accessible/comutils.cpp
index 7655bdf622..1c072c5e2c 100644
--- a/src/plugins/platforms/windows/accessible/comutils.cpp
+++ b/src/plugins/platforms/windows/accessible/comutils.cpp
@@ -170,7 +170,6 @@ bool QVariant2VARIANT(const QVariant &var, VARIANT &arg, const QByteArray &typeN
case QVariant::LongLong:
if (out && arg.vt == (VT_CY|VT_BYREF)) {
arg.pcyVal->int64 = qvar.toLongLong();
-#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400
} else if (out && arg.vt == (VT_I8|VT_BYREF)) {
*arg.pllVal = qvar.toLongLong();
} else {
@@ -181,22 +180,11 @@ bool QVariant2VARIANT(const QVariant &var, VARIANT &arg, const QByteArray &typeN
arg.vt |= VT_BYREF;
}
}
-#else
- } else {
- arg.vt = VT_CY;
- arg.cyVal.int64 = qvar.toLongLong();
- if (out) {
- arg.pcyVal = new CY(arg.cyVal);
- arg.vt |= VT_BYREF;
- }
- }
-#endif
break;
case QVariant::ULongLong:
if (out && arg.vt == (VT_CY|VT_BYREF)) {
arg.pcyVal->int64 = qvar.toULongLong();
-#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400
} else if (out && arg.vt == (VT_UI8|VT_BYREF)) {
*arg.pullVal = qvar.toULongLong();
} else {
@@ -207,18 +195,6 @@ bool QVariant2VARIANT(const QVariant &var, VARIANT &arg, const QByteArray &typeN
arg.vt |= VT_BYREF;
}
}
-#else
- } else {
- arg.vt = VT_CY;
- arg.cyVal.int64 = qvar.toULongLong();
- if (out) {
- arg.pcyVal = new CY(arg.cyVal);
- arg.vt |= VT_BYREF;
- }
- }
-
-#endif
-
break;
case QVariant::Bool:
diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
index 4a3f0ccb2b..7cf24421f8 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
@@ -56,12 +56,10 @@
#include <QtGui/qguiapplication.h>
#include "qwindowsaccessibility.h"
-#if !defined(Q_OS_WINCE)
-# ifdef Q_CC_MINGW
-# include "qwindowsmsaaaccessible.h"
-# else
-# include "iaccessible2.h"
-# endif
+#ifdef Q_CC_MINGW
+# include "qwindowsmsaaaccessible.h"
+#else
+# include "iaccessible2.h"
#endif
#include "comutils.h"
@@ -74,11 +72,7 @@
#include <winuser.h>
#if !defined(WINABLEAPI)
-# if defined(Q_OS_WINCE)
-# include <bldver.h>
-# else
-# include <winable.h>
-# endif
+# include <winable.h>
#endif
#include <servprov.h>
@@ -86,7 +80,7 @@
#include <comdef.h>
#endif
-#include "../qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
QT_BEGIN_NAMESPACE
@@ -153,10 +147,6 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
}
}
-#if defined(Q_OS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
- // There is no user32.lib nor NotifyWinEvent for CE
- return;
-#else
// An event has to be associated with a window,
// so find the first parent that is a widget and that has a WId
QAccessibleInterface *iface = event->accessibleInterface();
@@ -179,7 +169,6 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
event->type() != QAccessible::ObjectDestroyed) {
::NotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, QAccessible::uniqueId(iface));
}
-#endif // Q_OS_WINCE
}
QWindow *QWindowsAccessibility::windowHelper(const QAccessibleInterface *iface)
@@ -202,11 +191,6 @@ QWindow *QWindowsAccessibility::windowHelper(const QAccessibleInterface *iface)
*/
IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc)
{
-#if defined(Q_OS_WINCE)
- Q_UNUSED(acc);
-
- return 0;
-#else
if (!acc)
return 0;
@@ -222,12 +206,10 @@ IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc)
IAccessible *iacc = 0;
wacc->QueryInterface(IID_IAccessible, reinterpret_cast<void **>(&iacc));
return iacc;
-#endif // defined(Q_OS_WINCE)
}
bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
{
-#if !defined(Q_OS_WINCE)
if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) {
/* For UI Automation */
} else if (DWORD(lParam) == DWORD(OBJID_CLIENT)) {
@@ -263,12 +245,6 @@ bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, W
}
}
}
-#else
- Q_UNUSED(hwnd);
- Q_UNUSED(wParam);
- Q_UNUSED(lParam);
- Q_UNUSED(lResult);
-#endif // !defined(Q_OS_WINCE)
return false;
}
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
index 0e2165cdcb..ff115a2249 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
@@ -67,7 +67,7 @@
#endif
-#include "../qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
index 2f8602e320..fd00f8ac8b 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
@@ -43,7 +43,7 @@
#ifndef QT_NO_ACCESSIBILITY
#include <QtCore/qglobal.h>
-#include "../qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtCore/qsharedpointer.h>
#include <QtGui/qaccessible.h>
#ifndef Q_CC_MINGW
diff --git a/src/plugins/platforms/windows/qplatformfunctions_wince.h b/src/plugins/platforms/windows/qplatformfunctions_wince.h
deleted file mode 100644
index 309191537a..0000000000
--- a/src/plugins/platforms/windows/qplatformfunctions_wince.h
+++ /dev/null
@@ -1,371 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QPLATFORMFUNCTIONS_WCE_H
-#define QPLATFORMFUNCTIONS_WCE_H
-//
-// W A R N I N G
-// -------------
-//
-// This file is part of the QPA API and is not meant to be used
-// in applications. Usage of this API may make your code
-// source and binary incompatible with future versions of Qt.
-//
-
-#ifdef Q_OS_WINCE
-#include <QtCore/qfunctions_wince.h>
-#define UNDER_NT
-#include <wingdi.h>
-#include <objidl.h>
-
-#ifndef WM_MOUSELEAVE
-# define WM_MOUSELEAVE 0x02A3
-#endif
-
-#ifndef WM_TOUCH
-# define WM_TOUCH 0x0240
-#endif
-
-#ifndef WM_GETOBJECT
-#define WM_GETOBJECT 0x003D
-#endif
-
-#define GetWindowLongPtr GetWindowLong
-#define SetWindowLongPtr SetWindowLong
-#define GWLP_USERDATA GWL_USERDATA
-
-#ifndef CWP_SKIPINVISIBLE
-#define CWP_SKIPINVISIBLE 0x0001
-#define CWP_SKIPTRANSPARENT 0x0004
-#endif
-
-#ifndef CS_OWNDC
-#define CS_OWNDC 0x0020
-#endif
-
-#ifndef HWND_MESSAGE
-#define HWND_MESSAGE 0
-#endif
-
-// Real Value would be 0x40000000, but if we pass this to Windows Embedded Compact
-// he blits it wrongly, so lets not do any harm and define it to 0
-#ifndef CAPTUREBLT
-#define CAPTUREBLT (DWORD)0x0
-#endif
-
-#define SW_SHOWMINIMIZED SW_MINIMIZE
-#define SW_SHOWMINNOACTIVE SW_MINIMIZE
-
-#ifndef CF_DIBV5
-#define CF_DIBV5 17
-#endif
-
-#ifndef WM_MOUSEACTIVATE
-#define WM_MOUSEACTIVATE 0x0021
-#endif
-
-#ifndef WM_CHILDACTIVATE
-#define WM_CHILDACTIVATE 0x0022
-#endif
-
-#ifndef WM_PARENTNOTIFY
-#define WM_PARENTNOTIFY 0x0210
-#endif
-
-#ifndef WM_ENTERIDLE
-#define WM_ENTERIDLE 0x0121
-#endif
-
-#ifndef WM_GETMINMAXINFO
-#define WM_GETMINMAXINFO 0x0024
-#endif
-
-#ifndef WM_WINDOWPOSCHANGING
-#define WM_WINDOWPOSCHANGING 0x0046
-#endif
-
-#ifndef WM_NCMOUSEMOVE
-#define WM_NCMOUSEMOVE 0x00A0
-#endif
-
-#ifndef WM_NCMBUTTONDBLCLK
-#define WM_NCMBUTTONDBLCLK 0x00A
-#endif
-
-#ifndef WM_NCCREATE
-#define WM_NCCREATE 0x0081
-#endif
-
-#ifndef WM_NCCALCSIZE
-#define WM_NCCALCSIZE 0x0083
-#endif
-
-#ifndef WM_NCACTIVATE
-#define WM_NCACTIVATE 0x0086
-#endif
-
-#ifndef WM_NCMOUSELEAVE
-#define WM_NCMOUSELEAVE 0x02A2
-#endif
-
-#ifndef WM_NCLBUTTONDOWN
-#define WM_NCLBUTTONDOWN 0x00A1
-#endif
-
-#ifndef WM_NCLBUTTONUP
-#define WM_NCLBUTTONUP 0x00A2
-#endif
-
-#ifndef WM_NCPAINT
-#define WM_NCPAINT 0x0085
-#endif
-
-#ifndef WM_NCHITTEST
-#define WM_NCHITTEST 0x0084
-#endif
-
-#ifndef WM_THEMECHANGED
-#define WM_THEMECHANGED 0x031A
-#endif
-
-#ifndef WM_DISPLAYCHANGE
-#define WM_DISPLAYCHANGE 0x007E
-#endif
-
-#ifndef VREFRESH
-#define VREFRESH 116
-#endif
-
-#ifndef SM_SWAPBUTTON
-#define SM_SWAPBUTTON 23
-#endif
-
-// application defines
-#define SPI_SETNONCLIENTMETRICS 72
-#define SPI_SETICONTITLELOGFONT 0x0022
-#define WM_ACTIVATEAPP 0x001c
-#define SW_PARENTCLOSING 1
-#define SW_OTHERMAXIMIZED 2
-#define SW_PARENTOPENING 3
-#define SW_OTHERRESTORED 4
-#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
-
-// drag n drop
-#ifndef CFSTR_PERFORMEDDROPEFFECT
-#define CFSTR_PERFORMEDDROPEFFECT TEXT("Performed DropEffect")
-#endif
-
-// QWidget
-#define SW_SHOWMINIMIZED SW_MINIMIZE
-
-// QRegion
-#define ALTERNATE 0
-#define WINDING 1
-
-// QFontEngine
-typedef struct _FIXED {
- WORD fract;
- short value;
-} FIXED;
-
-typedef struct tagPOINTFX {
- FIXED x;
- FIXED y;
-} POINTFX;
-
-typedef struct _MAT2 {
- FIXED eM11;
- FIXED eM12;
- FIXED eM21;
- FIXED eM22;
-} MAT2;
-
-typedef struct _GLYPHMETRICS {
- UINT gmBlackBoxX;
- UINT gmBlackBoxY;
- POINT gmptGlyphOrigin;
- short gmCellIncX;
- short gmCellIncY;
-} GLYPHMETRICS;
-
-typedef struct tagTTPOLYGONHEADER
-{
- DWORD cb;
- DWORD dwType;
- POINTFX pfxStart;
-} TTPOLYGONHEADER;
-
-typedef struct tagTTPOLYCURVE
-{
- WORD wType;
- WORD cpfx;
- POINTFX apfx[1];
-} TTPOLYCURVE;
-
-#define GGO_NATIVE 2
-#define GGO_GLYPH_INDEX 0x0080
-#define TT_PRIM_LINE 1
-#define TT_PRIM_QSPLINE 2
-#define TT_PRIM_CSPLINE 3
-#define ANSI_VAR_FONT 12
-
-#ifndef OleInitialize
-#define OleInitialize(a) 0
-#endif
-
-#ifndef SPI_GETSNAPTODEFBUTTON
-#define SPI_GETSNAPTODEFBUTTON 95
-#endif
-
-#ifndef WS_EX_LAYERED
-#define WS_EX_LAYERED 0x00080000
-#endif
-
-// Clipboard --------------------------------------------------------
-#ifndef WM_CHANGECBCHAIN
-#define WM_CHANGECBCHAIN 0x030D
-#endif
-
-#ifndef WM_DRAWCLIPBOARD
-#define WM_DRAWCLIPBOARD 0x0308
-#endif
-
-#include <QFileInfo>
-
-inline bool IsIconic( HWND /*hWnd*/ )
-{
- return false;
-}
-
-inline int AddFontResourceExW( LPCWSTR name, DWORD /*fl*/, PVOID /*res*/)
-{
- QString fName = QString::fromWCharArray(name);
- QFileInfo fileinfo(fName);
- fName = fileinfo.absoluteFilePath();
- return AddFontResource((LPCWSTR)fName.utf16());
-}
-
-inline bool RemoveFontResourceExW( LPCWSTR /*name*/, DWORD /*fl*/, PVOID /*pdv*/)
-{
- return 0;
-}
-
-inline void OleUninitialize()
-{
-}
-
-inline DWORD GetGlyphOutline( HDC /*hdc*/, UINT /*uChar*/, INT /*fuFormat*/, GLYPHMETRICS * /*lpgm*/,
- DWORD /*cjBuffer*/, LPVOID /*pvBuffer*/, CONST MAT2 * /*lpmat2*/ )
-{
- qFatal("GetGlyphOutline() not supported under Windows CE. Please try using freetype font-rendering, by "
- "passing the command line argument -platform windows:fontengine=freetype to the application.");
- return GDI_ERROR;
-}
-
-inline HWND GetAncestor(HWND hWnd, UINT /*gaFlags*/)
-{
- return GetParent(hWnd);
-}
-
-#ifndef GA_PARENT
-# define GA_PARENT 1
-#endif
-
-#ifndef SPI_SETFONTSMOOTHINGTYPE
-# define SPI_SETFONTSMOOTHINGTYPE 0x200B
-#endif
-#ifndef SPI_GETFONTSMOOTHINGTYPE
-# define SPI_GETFONTSMOOTHINGTYPE 0x200A
-#endif
-#ifndef FE_FONTSMOOTHINGCLEARTYPE
-# define FE_FONTSMOOTHINGCLEARTYPE 0x0002
-#endif
-
-#ifndef DEVICE_FONTTYPE
-#define DEVICE_FONTTYPE 0x0002
-#endif
-
-#ifndef RASTER_FONTTYPE
-#define RASTER_FONTTYPE 0x0001
-#endif
-
-#ifndef WM_DISPLAYCHANGE
-#define WM_DISPLAYCHANGE 0x007E
-#endif
-
-BOOL qt_wince_ChangeClipboardChain(
- HWND hWndRemove, // handle to window to remove
- HWND hWndNewNext // handle to next window
-);
-#define ChangeClipboardChain(a,b) qt_wince_ChangeClipboardChain(a,b);
-
-HWND qt_wince_SetClipboardViewer(
- HWND hWndNewViewer // handle to clipboard viewer window
-);
-#define SetClipboardViewer(a) qt_wince_SetClipboardViewer(a)
-
-/* Shell stock icon IDs
- SHGetStockIconInfo() is not available on CE, but we're using these
- constants in code that is built on CE as well */
- enum
- {
- SIID_INVALID = -1,
- SIID_DOCNOASSOC = 0,
- SIID_FOLDER = 3,
- SIID_FOLDEROPEN = 4,
- SIID_DRIVE35 = 6,
- SIID_DRIVEFIXED = 8,
- SIID_DRIVENET = 9,
- SIID_DRIVECD = 11,
- SIID_HELP = 23,
- SIID_RECYCLER = 31,
- SIID_DRIVEDVD = 59,
- SIID_SHIELD = 77,
- SIID_WARNING = 78,
- SIID_INFO = 79,
- SIID_ERROR = 80
-};
-
-#ifndef SHGSI_LINKOVERLAY
-// Value is wrong, but doesn't matter, not used at runtime
-#define SHGSI_LINKOVERLAY 0
-#endif
-
-#endif // Q_OS_WINCE
-#endif // QPLATFORMFUNCTIONS_WCE_H
diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h
deleted file mode 100644
index 898a09fba7..0000000000
--- a/src/plugins/platforms/windows/qtwindows_additional.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QTWINDOWS_ADDITIONAL_H
-#define QTWINDOWS_ADDITIONAL_H
-
-#include <QtCore/QtGlobal> // get compiler define
-#include <QtCore/qt_windows.h>
-
-#ifndef WM_THEMECHANGED
-# define WM_THEMECHANGED 0x031A
-#endif
-
-#ifndef WM_DWMCOMPOSITIONCHANGED
-# define WM_DWMCOMPOSITIONCHANGED 0x31E
-#endif
-
-#ifndef GWL_HWNDPARENT
-# define GWL_HWNDPARENT (-8)
-#endif
-
-/* Complement the definitions and declarations missing
- * when using MinGW or older Windows SDKs. */
-
-#if defined(Q_CC_MINGW)
-# if !defined(ULW_ALPHA)
-# define ULW_ALPHA 0x00000002
-# define LWA_ALPHA 0x00000002
-# endif // !defined(ULW_ALPHA)
-# define SPI_GETFONTSMOOTHINGTYPE 0x200A
-# define FE_FONTSMOOTHINGCLEARTYPE 0x0002
-# define CLEARTYPE_QUALITY 5
-# define SPI_GETDROPSHADOW 0x1024
-# define COLOR_MENUHILIGHT 29
-# define COLOR_MENUBAR 30
-# define CF_DIBV5 17
-
-#if !defined(CO_E_NOT_SUPPORTED)
-#define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L)
-#endif
-
-#define IFMETHOD HRESULT STDMETHODCALLTYPE
-#define IFACEMETHODIMP STDMETHODIMP
-#define IFACEMETHODIMP_(type) STDMETHODIMP_(type)
-
-// For accessibility:
-#ifdef __cplusplus
- #define EXTERN_C extern "C"
-#else
- #define EXTERN_C extern
-#endif
-
-#define CHILDID_SELF 0
-#define WM_GETOBJECT 0x003D
-
-#ifndef SHGFI_ADDOVERLAYS // Shell structures for icons.
-typedef struct _SHSTOCKICONINFO
-{
- DWORD cbSize;
- HICON hIcon;
- int iSysImageIndex;
- int iIcon;
- WCHAR szPath[MAX_PATH];
-} SHSTOCKICONINFO;
-
-# define SIID_SHIELD 77
-# define SHGFI_ADDOVERLAYS 0x20
-# define SHGFI_OVERLAYINDEX 0x40
-#endif // SIID_SHIELD
-
-#if !defined(__MINGW64_VERSION_MAJOR)
-
-#define STATE_SYSTEM_HASPOPUP 0x40000000
-#define STATE_SYSTEM_PROTECTED 0x20000000
-
-typedef struct tagUPDATELAYEREDWINDOWINFO {
- DWORD cbSize;
- HDC hdcDst;
- const POINT *pptDst;
- const SIZE *psize;
- HDC hdcSrc;
- const POINT *pptSrc;
- COLORREF crKey;
- const BLENDFUNCTION *pblend;
- DWORD dwFlags;
- const RECT *prcDirty;
-} UPDATELAYEREDWINDOWINFO, *PUPDATELAYEREDWINDOWINFO;
-
-#endif // if !defined(__MINGW64_VERSION_MAJOR)
-
-// OpenGL Pixelformat flags.
-#define PFD_SUPPORT_DIRECTDRAW 0x00002000
-#define PFD_DIRECT3D_ACCELERATED 0x00004000
-#define PFD_SUPPORT_COMPOSITION 0x00008000
-
-// IME.
-#define IMR_CONFIRMRECONVERTSTRING 0x0005
-
-#ifndef MAPVK_VK_TO_CHAR
-# define MAPVK_VK_TO_CHAR 2
-#endif
-
-#endif // if defined(Q_CC_MINGW)
-
-/* Touch is supported from Windows 7 onwards and data structures
- * are present in the Windows SDK's, but not in older MSVC Express
- * versions. */
-
-#if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE)
-
-#define WM_TOUCH 0x0240
-
-typedef struct tagTOUCHINPUT {
- LONG x;
- LONG y;
- HANDLE hSource;
- DWORD dwID;
- DWORD dwFlags;
- DWORD dwMask;
- DWORD dwTime;
- ULONG_PTR dwExtraInfo;
- DWORD cxContact;
- DWORD cyContact;
-} TOUCHINPUT, *PTOUCHINPUT;
-typedef TOUCHINPUT const * PCTOUCHINPUT;
-
-# define TOUCHEVENTF_MOVE 0x0001
-# define TOUCHEVENTF_DOWN 0x0002
-# define TOUCHEVENTF_UP 0x0004
-# define TOUCHEVENTF_INRANGE 0x0008
-# define TOUCHEVENTF_PRIMARY 0x0010
-# define TOUCHEVENTF_NOCOALESCE 0x0020
-# define TOUCHEVENTF_PALM 0x0080
-# define TOUCHINPUTMASKF_CONTACTAREA 0x0004
-# define TOUCHINPUTMASKF_EXTRAINFO 0x0002
-
-#endif // if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE)
-
-#ifndef WM_GESTURE
-# define WM_GESTURE 0x0119
-#endif
-
-#endif // QTWINDOWS_ADDITIONAL_H
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index 90008663e7..ec6a8f62ae 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -41,10 +41,19 @@
#ifndef QTWINDOWSGLOBAL_H
#define QTWINDOWSGLOBAL_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtCore/qnamespace.h>
-#ifdef Q_OS_WINCE
-# include "qplatformfunctions_wince.h"
+
+#ifndef WM_DWMCOMPOSITIONCHANGED // MinGW.
+# define WM_DWMCOMPOSITIONCHANGED 0x31E
+#endif
+
+#ifndef WM_TOUCH
+# define WM_TOUCH 0x0240
+#endif
+
+#ifndef WM_GESTURE
+# define WM_GESTURE 0x0119
#endif
QT_BEGIN_NAMESPACE
@@ -158,10 +167,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
return QtWindows::MouseWheelEvent;
-#ifndef Q_OS_WINCE
case WM_WINDOWPOSCHANGING:
return QtWindows::GeometryChangingEvent;
-#endif
case WM_MOVE:
return QtWindows::MoveEvent;
case WM_SHOWWINDOW:
@@ -172,10 +179,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
return QtWindows::ResizeEvent;
case WM_NCCALCSIZE:
return QtWindows::CalculateSize;
-#ifndef Q_OS_WINCE
case WM_NCHITTEST:
return QtWindows::NonClientHitTest;
-#endif // !Q_OS_WINCE
case WM_GETMINMAXINFO:
return QtWindows::QuerySizeHints;
case WM_KEYDOWN: // keyboard event
@@ -243,12 +248,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
return QtWindows::ContextMenu;
#endif
case WM_SYSCOMMAND:
-#ifndef Q_OS_WINCE
if ((wParamIn & 0xfff0) == SC_CONTEXTHELP)
return QtWindows::WhatsThisEvent;
-#endif
break;
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
case WM_QUERYENDSESSION:
return QtWindows::QueryEndSessionApplicationEvent;
case WM_ENDSESSION:
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
index 7123ed826d..3b7374dc92 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
@@ -87,7 +87,6 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
QWindowsWindow *rw = QWindowsWindow::windowsWindowOf(window);
Q_ASSERT(rw);
-#ifndef Q_OS_WINCE
const bool hasAlpha = rw->format().hasAlpha();
const Qt::WindowFlags flags = window->flags();
if ((flags & Qt::FramelessWindowHint) && QWindowsWindow::setWindowLayered(rw->handle(), flags, hasAlpha, rw->opacity()) && hasAlpha) {
@@ -101,21 +100,16 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
POINT ptDst = {r.x(), r.y()};
POINT ptSrc = {0, 0};
BLENDFUNCTION blend = {AC_SRC_OVER, 0, BYTE(qRound(255.0 * rw->opacity())), AC_SRC_ALPHA};
- if (QWindowsContext::user32dll.updateLayeredWindowIndirect) {
- RECT dirty = {dirtyRect.x(), dirtyRect.y(),
- dirtyRect.x() + dirtyRect.width(), dirtyRect.y() + dirtyRect.height()};
- UPDATELAYEREDWINDOWINFO info = {sizeof(info), NULL, &ptDst, &size, m_image->hdc(), &ptSrc, 0, &blend, ULW_ALPHA, &dirty};
- const BOOL result = QWindowsContext::user32dll.updateLayeredWindowIndirect(rw->handle(), &info);
- if (!result)
- qErrnoWarning("UpdateLayeredWindowIndirect failed for ptDst=(%d, %d),"
- " size=(%dx%d), dirty=(%dx%d %d, %d)", r.x(), r.y(),
- r.width(), r.height(), dirtyRect.width(), dirtyRect.height(),
- dirtyRect.x(), dirtyRect.y());
- } else {
- QWindowsContext::user32dll.updateLayeredWindow(rw->handle(), NULL, &ptDst, &size, m_image->hdc(), &ptSrc, 0, &blend, ULW_ALPHA);
- }
+ RECT dirty = {dirtyRect.x(), dirtyRect.y(),
+ dirtyRect.x() + dirtyRect.width(), dirtyRect.y() + dirtyRect.height()};
+ UPDATELAYEREDWINDOWINFO info = {sizeof(info), NULL, &ptDst, &size, m_image->hdc(), &ptSrc, 0, &blend, ULW_ALPHA, &dirty};
+ const BOOL result = UpdateLayeredWindowIndirect(rw->handle(), &info);
+ if (!result)
+ qErrnoWarning("UpdateLayeredWindowIndirect failed for ptDst=(%d, %d),"
+ " size=(%dx%d), dirty=(%dx%d %d, %d)", r.x(), r.y(),
+ r.width(), r.height(), dirtyRect.width(), dirtyRect.height(),
+ dirtyRect.x(), dirtyRect.y());
} else {
-#endif
const HDC dc = rw->getDC();
if (!dc) {
qErrnoWarning("%s: GetDC failed", __FUNCTION__);
@@ -129,9 +123,7 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
qErrnoWarning(int(lastError), "%s: BitBlt failed", __FUNCTION__);
}
rw->releaseDC();
-#ifndef Q_OS_WINCE
}
-#endif
// Write image for debug purposes.
if (QWindowsContext::verbose > 2 && lcQpaBackingStore().isDebugEnabled()) {
@@ -175,7 +167,7 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion &region)
staticRegion &= QRect(0, 0, newimg.width(), newimg.height());
QPainter painter(&newimg);
painter.setCompositionMode(QPainter::CompositionMode_Source);
- foreach (const QRect &rect, staticRegion.rects())
+ for (const QRect &rect : staticRegion)
painter.drawImage(rect, oldimg, rect);
}
@@ -190,10 +182,9 @@ bool QWindowsBackingStore::scroll(const QRegion &area, int dx, int dy)
if (m_image.isNull() || m_image->image().isNull())
return false;
- const QVector<QRect> rects = area.rects();
const QPoint offset(dx, dy);
- for (int i = 0; i < rects.size(); ++i)
- qt_scrollRectInImage(m_image->image(), rects.at(i), offset);
+ for (const QRect &rect : area)
+ qt_scrollRectInImage(m_image->image(), rect, offset);
return true;
}
@@ -207,7 +198,7 @@ void QWindowsBackingStore::beginPaint(const QRegion &region)
QPainter p(&m_image->image());
p.setCompositionMode(QPainter::CompositionMode_Source);
const QColor blank = Qt::transparent;
- foreach (const QRect &r, region.rects())
+ for (const QRect &r : region)
p.fillRect(r, blank);
}
}
@@ -219,8 +210,6 @@ HDC QWindowsBackingStore::getDC() const
return 0;
}
-#ifndef QT_NO_OPENGL
-
QImage QWindowsBackingStore::toImage() const
{
if (m_image.isNull()) {
@@ -230,6 +219,4 @@ QImage QWindowsBackingStore::toImage() const
return m_image.data()->image();
}
-#endif // !QT_NO_OPENGL
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h
index 26c79348a9..46a7fcc676 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.h
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSBACKINGSTORE_H
#define QWINDOWSBACKINGSTORE_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <qpa/qplatformbackingstore.h>
#include <QtCore/QScopedPointer>
@@ -65,9 +65,7 @@ public:
HDC getDC() const;
-#ifndef QT_NO_OPENGL
QImage toImage() const Q_DECL_OVERRIDE;
-#endif
private:
QScopedPointer<QWindowsNativeImage> m_image;
diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp
index d527e07308..21bc9d7377 100644
--- a/src/plugins/platforms/windows/qwindowsclipboard.cpp
+++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp
@@ -237,8 +237,7 @@ void QWindowsClipboard::propagateClipboardMessage(UINT message, WPARAM wParam, L
return;
// In rare cases, a clipboard viewer can hang (application crashed,
// suspended by a shell prompt 'Select' or debugger).
- if (QWindowsContext::user32dll.isHungAppWindow
- && QWindowsContext::user32dll.isHungAppWindow(m_nextClipboardViewer)) {
+ if (IsHungAppWindow(m_nextClipboardViewer)) {
qWarning("Cowardly refusing to send clipboard message to hung application...");
return;
}
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index efeb1f5f05..ef0962c2ff 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -51,7 +51,7 @@
#ifndef QT_NO_ACCESSIBILITY
# include "accessible/qwindowsaccessibility.h"
#endif
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
# include <private/qsessionmanager_p.h>
# include "qwindowssessionmanager.h"
#endif
@@ -76,9 +76,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <windowsx.h>
-#ifndef Q_OS_WINCE
-# include <comdef.h>
-#endif
+#include <comdef.h>
QT_BEGIN_NAMESPACE
@@ -99,45 +97,29 @@ int QWindowsContext::verbose = 0;
# define LANG_SYRIAC 0x5a
#endif
-static inline bool useRTL_Extensions(QSysInfo::WinVersion ver)
+static inline bool useRTL_Extensions()
{
- // This is SDK dependent on CE so out of scope for now
- if (QSysInfo::windowsVersion() & QSysInfo::WV_CE_based)
- return false;
- if ((ver & QSysInfo::WV_NT_based) && (ver >= QSysInfo::WV_VISTA)) {
- // Since the IsValidLanguageGroup/IsValidLocale functions always return true on
- // Vista, check the Keyboard Layouts for enabling RTL.
- if (const int nLayouts = GetKeyboardLayoutList(0, 0)) {
- QScopedArrayPointer<HKL> lpList(new HKL[nLayouts]);
- GetKeyboardLayoutList(nLayouts, lpList.data());
- for (int i = 0; i < nLayouts; ++i) {
- switch (PRIMARYLANGID((quintptr)lpList[i])) {
- case LANG_ARABIC:
- case LANG_HEBREW:
- case LANG_FARSI:
- case LANG_SYRIAC:
- return true;
- default:
- break;
- }
+ // Since the IsValidLanguageGroup/IsValidLocale functions always return true on
+ // Vista, check the Keyboard Layouts for enabling RTL.
+ if (const int nLayouts = GetKeyboardLayoutList(0, 0)) {
+ QScopedArrayPointer<HKL> lpList(new HKL[nLayouts]);
+ GetKeyboardLayoutList(nLayouts, lpList.data());
+ for (int i = 0; i < nLayouts; ++i) {
+ switch (PRIMARYLANGID((quintptr)lpList[i])) {
+ case LANG_ARABIC:
+ case LANG_HEBREW:
+ case LANG_FARSI:
+ case LANG_SYRIAC:
+ return true;
+ default:
+ break;
}
}
- return false;
- } // NT/Vista
-#ifndef Q_OS_WINCE
- // Pre-NT: figure out whether a RTL language is installed
- return IsValidLanguageGroup(LGRPID_ARABIC, LGRPID_INSTALLED)
- || IsValidLanguageGroup(LGRPID_HEBREW, LGRPID_INSTALLED)
- || IsValidLocale(MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
- || IsValidLocale(MAKELCID(MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
- || IsValidLocale(MAKELCID(MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
- || IsValidLocale(MAKELCID(MAKELANGID(LANG_FARSI, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED);
-#else
+ }
return false;
-#endif
}
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
static inline QWindowsSessionManager *platformSessionManager() {
QGuiApplicationPrivate *guiPrivate = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp));
QSessionManagerPrivate *managerPrivate = static_cast<QSessionManagerPrivate*>(QObjectPrivate::get(guiPrivate->session_manager));
@@ -160,13 +142,8 @@ static inline QWindowsSessionManager *platformSessionManager() {
\internal
\ingroup qt-lighthouse-win
*/
-
-#ifndef Q_OS_WINCE
-
QWindowsUser32DLL::QWindowsUser32DLL() :
- setLayeredWindowAttributes(0), updateLayeredWindow(0),
- updateLayeredWindowIndirect(0),
- isHungAppWindow(0), isTouchWindow(0),
+ isTouchWindow(0),
registerTouchWindow(0), unregisterTouchWindow(0),
getTouchInputInfo(0), closeTouchInputHandle(0), setProcessDPIAware(0),
addClipboardFormatListener(0), removeClipboardFormatListener(0),
@@ -177,20 +154,11 @@ QWindowsUser32DLL::QWindowsUser32DLL() :
void QWindowsUser32DLL::init()
{
QSystemLibrary library(QStringLiteral("user32"));
- // MinGW (g++ 3.4.5) accepts only C casts.
- setLayeredWindowAttributes = (SetLayeredWindowAttributes)(library.resolve("SetLayeredWindowAttributes"));
- updateLayeredWindow = (UpdateLayeredWindow)(library.resolve("UpdateLayeredWindow"));
- if (Q_UNLIKELY(!setLayeredWindowAttributes || !updateLayeredWindow))
- qFatal("This version of Windows is not supported (User32.dll is missing the symbols 'SetLayeredWindowAttributes', 'UpdateLayeredWindow').");
-
- updateLayeredWindowIndirect = (UpdateLayeredWindowIndirect)(library.resolve("UpdateLayeredWindowIndirect"));
- isHungAppWindow = (IsHungAppWindow)library.resolve("IsHungAppWindow");
setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware");
- if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) {
- addClipboardFormatListener = (AddClipboardFormatListener)library.resolve("AddClipboardFormatListener");
- removeClipboardFormatListener = (RemoveClipboardFormatListener)library.resolve("RemoveClipboardFormatListener");
- }
+ addClipboardFormatListener = (AddClipboardFormatListener)library.resolve("AddClipboardFormatListener");
+ removeClipboardFormatListener = (RemoveClipboardFormatListener)library.resolve("RemoveClipboardFormatListener");
+
getDisplayAutoRotationPreferences = (GetDisplayAutoRotationPreferences)library.resolve("GetDisplayAutoRotationPreferences");
setDisplayAutoRotationPreferences = (SetDisplayAutoRotationPreferences)library.resolve("SetDisplayAutoRotationPreferences");
}
@@ -208,38 +176,6 @@ bool QWindowsUser32DLL::initTouch()
return isTouchWindow && registerTouchWindow && unregisterTouchWindow && getTouchInputInfo && closeTouchInputHandle;
}
-/*!
- \class QWindowsShell32DLL
- \brief Struct that contains dynamically resolved symbols of Shell32.dll.
-
- The stub libraries shipped with the MinGW compiler miss some of the
- functions. They need to be retrieved dynamically.
-
- \sa QWindowsUser32DLL
-
- \internal
- \ingroup qt-lighthouse-win
-*/
-
-QWindowsShell32DLL::QWindowsShell32DLL()
- : sHCreateItemFromParsingName(0)
- , sHGetKnownFolderIDList(0)
- , sHGetStockIconInfo(0)
- , sHGetImageList(0)
- , sHCreateItemFromIDList(0)
-{
-}
-
-void QWindowsShell32DLL::init()
-{
- QSystemLibrary library(QStringLiteral("shell32"));
- sHCreateItemFromParsingName = (SHCreateItemFromParsingName)(library.resolve("SHCreateItemFromParsingName"));
- sHGetKnownFolderIDList = (SHGetKnownFolderIDList)(library.resolve("SHGetKnownFolderIDList"));
- sHGetStockIconInfo = (SHGetStockIconInfo)library.resolve("SHGetStockIconInfo");
- sHGetImageList = (SHGetImageList)library.resolve("SHGetImageList");
- sHCreateItemFromIDList = (SHCreateItemFromIDList)library.resolve("SHCreateItemFromIDList");
-}
-
QWindowsShcoreDLL::QWindowsShcoreDLL()
: getProcessDpiAwareness(0)
, setProcessDpiAwareness(0)
@@ -258,11 +194,8 @@ void QWindowsShcoreDLL::init()
}
QWindowsUser32DLL QWindowsContext::user32dll;
-QWindowsShell32DLL QWindowsContext::shell32dll;
QWindowsShcoreDLL QWindowsContext::shcoredll;
-#endif // !Q_OS_WINCE
-
QWindowsContext *QWindowsContext::m_instance = 0;
/*!
@@ -291,7 +224,7 @@ struct QWindowsContextPrivate {
QWindowsMimeConverter m_mimeConverter;
QWindowsScreenManager m_screenManager;
QSharedPointer<QWindowCreationContext> m_creationContext;
-#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE)
+#if !defined(QT_NO_TABLETEVENT)
QScopedPointer<QWindowsTabletSupport> m_tabletSupport;
#endif
const HRESULT m_oleInitializeResult;
@@ -306,18 +239,14 @@ QWindowsContextPrivate::QWindowsContextPrivate()
, m_eventType(QByteArrayLiteral("windows_generic_MSG"))
, m_lastActiveWindow(0), m_asyncExpose(0)
{
- const QSysInfo::WinVersion ver = QSysInfo::windowsVersion();
-#ifndef Q_OS_WINCE
QWindowsContext::user32dll.init();
- QWindowsContext::shell32dll.init();
QWindowsContext::shcoredll.init();
if (m_mouseHandler.touchDevice() && QWindowsContext::user32dll.initTouch())
m_systemInfo |= QWindowsContext::SI_SupportsTouch;
-#endif // !Q_OS_WINCE
m_displayContext = GetDC(0);
m_defaultDPI = GetDeviceCaps(m_displayContext, LOGPIXELSY);
- if (useRTL_Extensions(ver)) {
+ if (useRTL_Extensions()) {
m_systemInfo |= QWindowsContext::SI_RTL_Extensions;
m_keyMapper.setUseRTLExtensions(true);
}
@@ -338,7 +267,7 @@ QWindowsContext::QWindowsContext() :
const QByteArray bv = qgetenv("QT_QPA_VERBOSE");
if (!bv.isEmpty())
QLoggingCategory::setFilterRules(QString::fromLocal8Bit(bv));
-#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE)
+#if !defined(QT_NO_TABLETEVENT)
d->m_tabletSupport.reset(QWindowsTabletSupport::create());
qCDebug(lcQpaTablet) << "Tablet support: " << (d->m_tabletSupport.isNull() ? QStringLiteral("None") : d->m_tabletSupport->description());
#endif
@@ -346,7 +275,7 @@ QWindowsContext::QWindowsContext() :
QWindowsContext::~QWindowsContext()
{
-#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE)
+#if !defined(QT_NO_TABLETEVENT)
d->m_tabletSupport.reset(); // Destroy internal window before unregistering classes.
#endif
unregisterWindowClasses();
@@ -371,12 +300,10 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
if (!touchDevice)
return false;
-#ifndef Q_OS_WINCE
if (!QWindowsContext::user32dll.initTouch()) {
delete touchDevice;
return false;
}
-#endif // !Q_OS_WINCE
if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
@@ -389,7 +316,7 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
void QWindowsContext::setTabletAbsoluteRange(int a)
{
-#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE)
+#if !defined(QT_NO_TABLETEVENT)
if (!d->m_tabletSupport.isNull())
d->m_tabletSupport->setAbsoluteRange(a);
#else
@@ -399,19 +326,16 @@ void QWindowsContext::setTabletAbsoluteRange(int a)
int QWindowsContext::processDpiAwareness()
{
-#ifndef Q_OS_WINCE
int result;
if (QWindowsContext::shcoredll.getProcessDpiAwareness
&& SUCCEEDED(QWindowsContext::shcoredll.getProcessDpiAwareness(NULL, &result))) {
return result;
}
-#endif // !Q_OS_WINCE
return -1;
}
void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness)
{
-#ifndef Q_OS_WINCE
qCDebug(lcQpaWindows) << __FUNCTION__ << dpiAwareness;
if (QWindowsContext::shcoredll.isValid()) {
const HRESULT hr = QWindowsContext::shcoredll.setProcessDpiAwareness(dpiAwareness);
@@ -426,9 +350,6 @@ void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiA
qErrnoWarning("SetProcessDPIAware() failed");
}
}
-#else // !Q_OS_WINCE
- Q_UNUSED(dpiAwareness)
-#endif
}
QWindowsContext *QWindowsContext::instance()
@@ -559,19 +480,14 @@ QString QWindowsContext::registerWindowClass(QString cname,
if (d->m_registeredWindowClassNames.contains(cname)) // already registered in our list
return cname;
-#ifndef Q_OS_WINCE
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
-#else
- WNDCLASS wc;
-#endif
wc.style = style;
wc.lpfnWndProc = proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = appInstance;
wc.hCursor = 0;
-#ifndef Q_OS_WINCE
wc.hbrBackground = brush;
if (icon) {
wc.hIcon = static_cast<HICON>(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));
@@ -587,22 +503,10 @@ QString QWindowsContext::registerWindowClass(QString cname,
wc.hIcon = 0;
wc.hIconSm = 0;
}
-#else
- if (icon) {
- wc.hIcon = (HICON)LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
- } else {
- wc.hIcon = 0;
- }
-#endif
wc.lpszMenuName = 0;
wc.lpszClassName = reinterpret_cast<LPCWSTR>(cname.utf16());
-#ifndef Q_OS_WINCE
ATOM atom = RegisterClassEx(&wc);
-#else
- ATOM atom = RegisterClass(&wc);
-#endif
-
if (!atom)
qErrnoWarning("QApplication::regClass: Registering window class '%s' failed.",
qPrintable(cname));
@@ -720,28 +624,14 @@ static inline bool findPlatformWindowHelper(const POINT &screenPoint, unsigned c
POINT point = screenPoint;
ScreenToClient(*hwnd, &point);
// Returns parent if inside & none matched.
-#ifndef Q_OS_WINCE
const HWND child = ChildWindowFromPointEx(*hwnd, point, cwexFlags);
-#else
-// Under Windows CE we don't use ChildWindowFromPointEx as it's not available
-// and ChildWindowFromPoint does not work properly.
- Q_UNUSED(cwexFlags)
- const HWND child = WindowFromPoint(point);
-#endif
if (!child || child == *hwnd)
return false;
if (QWindowsWindow *window = context->findPlatformWindow(child)) {
*result = window;
*hwnd = child;
-#ifndef Q_OS_WINCE
return true;
-#else
-// WindowFromPoint does not return same handle in two sequential calls, which leads
-// to an endless loop, but calling WindowFromPoint once is good enough.
- return false;
-#endif
}
-#ifndef Q_OS_WINCE // Does not have WS_EX_TRANSPARENT .
// QTBUG-40555: despite CWP_SKIPINVISIBLE, it is possible to hit on invisible
// full screen windows of other applications that have WS_EX_TRANSPARENT set
// (for example created by screen sharing applications). In that case, try to
@@ -757,7 +647,6 @@ static inline bool findPlatformWindowHelper(const POINT &screenPoint, unsigned c
return true;
}
}
-#endif // !Q_OS_WINCE
*hwnd = child;
return true;
}
@@ -784,7 +673,7 @@ QWindowsScreenManager &QWindowsContext::screenManager()
QWindowsTabletSupport *QWindowsContext::tabletSupport() const
{
-#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE)
+#if !defined(QT_NO_TABLETEVENT)
return d->m_tabletSupport.data();
#else
return 0;
@@ -810,7 +699,6 @@ HWND QWindowsContext::createDummyWindow(const QString &classNameIn,
HWND_MESSAGE, NULL, static_cast<HINSTANCE>(GetModuleHandle(0)), NULL);
}
-#ifndef Q_OS_WINCE
// Re-engineered from the inline function _com_error::ErrorMessage().
// We cannot use it directly since it uses swprintf_s(), which is not
// present in the MSVCRT.DLL found on Windows XP (QTBUG-35617).
@@ -829,7 +717,6 @@ static inline QString errorMessageFromComError(const _com_error &comError)
return QStringLiteral("IDispatch error #") + QString::number(wCode);
return QStringLiteral("Unknown error 0x0") + QString::number(comError.Error(), 16);
}
-#endif // !Q_OS_WINCE
/*!
\brief Common COM error strings.
@@ -894,12 +781,10 @@ QByteArray QWindowsContext::comErrorString(HRESULT hr)
default:
break;
}
-#ifndef Q_OS_WINCE
_com_error error(hr);
result += QByteArrayLiteral(" (");
result += errorMessageFromComError(error);
result += ')';
-#endif // !Q_OS_WINCE
return result;
}
@@ -935,9 +820,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
ClientToScreen(msg.hwnd, &msg.pt);
}
} else {
-#ifndef Q_OS_WINCE
GetCursorPos(&msg.pt);
-#endif
}
// Run the native event filters.
@@ -980,7 +863,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
switch (et) {
case QtWindows::GestureEvent:
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
#else
return d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
@@ -1019,11 +902,9 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
// Pass on to current creation context
if (!platformWindow && !d->m_creationContext.isNull()) {
switch (et) {
-#ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
case QtWindows::QuerySizeHints:
d->m_creationContext->applyToMinMaxInfo(reinterpret_cast<MINMAXINFO *>(lParam));
return true;
-#endif
case QtWindows::ResizeEvent:
d->m_creationContext->obtainedGeometry.setSize(QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
return true;
@@ -1061,7 +942,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::InputMethodKeyEvent:
case QtWindows::InputMethodKeyDownEvent:
case QtWindows::AppCommandEvent:
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
return platformSessionManager()->isInteractionBlocked() ? true : d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
#else
return d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
@@ -1072,7 +953,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::ResizeEvent:
platformWindow->handleResized(static_cast<int>(wParam));
return true;
-#ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
case QtWindows::QuerySizeHints:
platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam));
return true;// maybe available on some SDKs revisit WM_NCCALCSIZE
@@ -1082,30 +962,18 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return platformWindow->handleNonClientHitTest(QPoint(msg.pt.x, msg.pt.y), result);
case QtWindows::GeometryChangingEvent:
return platformWindow->QWindowsWindow::handleGeometryChanging(&msg);
-#endif // !Q_OS_WINCE
case QtWindows::ExposeEvent:
return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
case QtWindows::NonClientMouseEvent:
if (platformWindow->frameStrutEventsEnabled())
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
#else
return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
#endif
break;
-/* the mouse tracking on windows already handles the reset of the cursor
- * and does not like somebody else handling it.
- * on WINCE its necessary to handle this event to get the correct cursor
- */
-#ifdef Q_OS_WINCE
- case QtWindows::CursorEvent:
- {
- QWindowsWindow::baseWindowOf(platformWindow->window())->applyCursor();
- return true;
- }
-#endif
case QtWindows::ScrollEvent:
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
#else
return d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
@@ -1113,13 +981,13 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::MouseWheelEvent:
case QtWindows::MouseEvent:
case QtWindows::LeaveEvent:
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
#else
return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
#endif
case QtWindows::TouchEvent:
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
#else
return d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
@@ -1152,7 +1020,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::CompositionSettingsChanged:
platformWindow->handleCompositionSettingsChanged();
return true;
-#ifndef Q_OS_WINCE
case QtWindows::ActivateWindowEvent:
if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) {
*result = LRESULT(MA_NOACTIVATE);
@@ -1175,7 +1042,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return true;
}
break;
-#endif
#ifndef QT_NO_CONTEXTMENU
case QtWindows::ContextMenu:
return handleContextMenuEvent(platformWindow->window(), msg);
@@ -1186,7 +1052,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return true;
#endif
} break;
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
case QtWindows::QueryEndSessionApplicationEvent: {
QWindowsSessionManager *sessionManager = platformSessionManager();
if (sessionManager->isActive()) { // bogus message from windows
@@ -1226,7 +1092,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
}
return true;
}
-#endif // !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#endif // !defined(QT_NO_SESSIONMANAGER)
default:
break;
}
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 3559335747..843f7e2ad6 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -41,7 +41,7 @@
#define QWINDOWSCONTEXT_H
#include "qtwindowsglobal.h"
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtCore/QScopedPointer>
#include <QtCore/QSharedPointer>
@@ -79,38 +79,23 @@ class QPoint;
class QKeyEvent;
class QTouchDevice;
-#ifndef Q_OS_WINCE
struct QWindowsUser32DLL
{
QWindowsUser32DLL();
inline void init();
inline bool initTouch();
- typedef BOOL (WINAPI *IsTouchWindow)(HWND, PULONG);
+ typedef BOOL (WINAPI *IsTouchWindow)(HWND, PULONG); // Windows 7
typedef BOOL (WINAPI *RegisterTouchWindow)(HWND, ULONG);
typedef BOOL (WINAPI *UnregisterTouchWindow)(HWND);
typedef BOOL (WINAPI *GetTouchInputInfo)(HANDLE, UINT, PVOID, int);
typedef BOOL (WINAPI *CloseTouchInputHandle)(HANDLE);
- typedef BOOL (WINAPI *SetLayeredWindowAttributes)(HWND, COLORREF, BYTE, DWORD);
- typedef BOOL (WINAPI *UpdateLayeredWindow)(HWND, HDC , const POINT *,
- const SIZE *, HDC, const POINT *, COLORREF,
- const BLENDFUNCTION *, DWORD);
- typedef BOOL (WINAPI *UpdateLayeredWindowIndirect)(HWND, const UPDATELAYEREDWINDOWINFO *);
- typedef BOOL (WINAPI *IsHungAppWindow)(HWND);
typedef BOOL (WINAPI *SetProcessDPIAware)();
typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND);
typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND);
typedef BOOL (WINAPI *GetDisplayAutoRotationPreferences)(DWORD *);
typedef BOOL (WINAPI *SetDisplayAutoRotationPreferences)(DWORD);
- // Functions missing in Q_CC_GNU stub libraries.
- SetLayeredWindowAttributes setLayeredWindowAttributes;
- UpdateLayeredWindow updateLayeredWindow;
-
- // Functions missing in older versions of Windows
- UpdateLayeredWindowIndirect updateLayeredWindowIndirect;
- IsHungAppWindow isHungAppWindow;
-
// Touch functions from Windows 7 onwards (also for use with Q_CC_MSVC).
IsTouchWindow isTouchWindow;
RegisterTouchWindow registerTouchWindow;
@@ -121,7 +106,8 @@ struct QWindowsUser32DLL
// Windows Vista onwards
SetProcessDPIAware setProcessDPIAware;
- // Clipboard listeners, Windows Vista onwards
+ // Clipboard listeners are present on Windows Vista onwards
+ // but missing in MinGW 4.9 stub libs. Can be removed in MinGW 5.
AddClipboardFormatListener addClipboardFormatListener;
RemoveClipboardFormatListener removeClipboardFormatListener;
@@ -130,24 +116,6 @@ struct QWindowsUser32DLL
SetDisplayAutoRotationPreferences setDisplayAutoRotationPreferences;
};
-struct QWindowsShell32DLL
-{
- QWindowsShell32DLL();
- inline void init();
-
- typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **);
- typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, PIDLIST_ABSOLUTE *);
- typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *);
- typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **);
- typedef HRESULT (WINAPI *SHCreateItemFromIDList)(PCIDLIST_ABSOLUTE, REFIID, void **);
-
- SHCreateItemFromParsingName sHCreateItemFromParsingName;
- SHGetKnownFolderIDList sHGetKnownFolderIDList;
- SHGetStockIconInfo sHGetStockIconInfo;
- SHGetImageList sHGetImageList;
- SHCreateItemFromIDList sHCreateItemFromIDList;
-};
-
// Shell scaling library (Windows 8.1 onwards)
struct QWindowsShcoreDLL {
QWindowsShcoreDLL();
@@ -163,8 +131,6 @@ struct QWindowsShcoreDLL {
GetDpiForMonitor getDpiForMonitor;
};
-#endif // Q_OS_WINCE
-
class QWindowsContext
{
Q_DISABLE_COPY(QWindowsContext)
@@ -236,11 +202,9 @@ public:
QWindowsMimeConverter &mimeConverter() const;
QWindowsScreenManager &screenManager();
QWindowsTabletSupport *tabletSupport() const;
-#ifndef Q_OS_WINCE
+
static QWindowsUser32DLL user32dll;
- static QWindowsShell32DLL shell32dll;
static QWindowsShcoreDLL shcoredll;
-#endif
static QByteArray comErrorString(HRESULT hr);
bool asyncExpose() const;
diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp
index d02648fade..1bebe88df7 100644
--- a/src/plugins/platforms/windows/qwindowscursor.cpp
+++ b/src/plugins/platforms/windows/qwindowscursor.cpp
@@ -56,7 +56,7 @@
static bool initResources()
{
-#if !defined (Q_OS_WINCE) && !defined (QT_NO_IMAGEFORMAT_PNG)
+#if !defined (QT_NO_IMAGEFORMAT_PNG)
Q_INIT_RESOURCE(cursors);
#endif
return true;
@@ -143,7 +143,6 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits,
if (hotSpot.y() < 0)
hotSpot.setY(height / 2);
const int n = qMax(1, width / 8);
-#if !defined(Q_OS_WINCE)
QScopedArrayPointer<uchar> xBits(new uchar[height * n]);
QScopedArrayPointer<uchar> xMask(new uchar[height * n]);
int x = 0;
@@ -164,54 +163,6 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits,
}
return CreateCursor(GetModuleHandle(0), hotSpot.x(), hotSpot.y(), width, height,
xBits.data(), xMask.data());
-#elif defined(GWES_ICONCURS) // Q_OS_WINCE
- // Windows CE only supports fixed cursor size.
- int sysW = GetSystemMetrics(SM_CXCURSOR);
- int sysH = GetSystemMetrics(SM_CYCURSOR);
- int sysN = qMax(1, sysW / 8);
- uchar* xBits = new uchar[sysH * sysN];
- uchar* xMask = new uchar[sysH * sysN];
- int x = 0;
- for (int i = 0; i < sysH; ++i) {
- if (i >= height) {
- memset(&xBits[x] , 255, sysN);
- memset(&xMask[x] , 0, sysN);
- x += sysN;
- } else {
- int fillWidth = n > sysN ? sysN : n;
- const uchar *bits = bbits.constScanLine(i);
- const uchar *mask = mbits.constScanLine(i);
- for (int j = 0; j < fillWidth; ++j) {
- uchar b = bits[j];
- uchar m = mask[j];
- if (invb)
- b ^= 0xFF;
- if (invm)
- m ^= 0xFF;
- xBits[x] = ~m;
- xMask[x] = b ^ m;
- ++x;
- }
- for (int j = fillWidth; j < sysN; ++j ) {
- xBits[x] = 255;
- xMask[x] = 0;
- ++x;
- }
- }
- }
-
- HCURSOR hcurs = CreateCursor(qWinAppInst(), hotSpot.x(), hotSpot.y(), sysW, sysH,
- xBits, xMask);
- delete [] xBits;
- delete [] xMask;
- return hcurs;
-#else
- Q_UNUSED(n);
- Q_UNUSED(invm);
- Q_UNUSED(invb);
- Q_UNUSED(mbits);
- return 0;
-#endif
}
// Create a cursor from image and mask of the format QImage::Format_Mono.
@@ -252,7 +203,7 @@ static QSize systemCursorSize(const QPlatformScreen *screen = Q_NULLPTR)
return primaryScreenCursorSize;
}
-#if defined (Q_OS_WINCE) || defined (QT_NO_IMAGEFORMAT_PNG)
+#if defined (QT_NO_IMAGEFORMAT_PNG)
static inline QSize standardCursorSize() { return QSize(32, 32); }
@@ -468,7 +419,7 @@ QWindowsCursor::PixmapCursor QWindowsCursor::customCursor(Qt::CursorShape cursor
return QWindowsCursor::PixmapCursor();
}
-#else // Q_OS_WINCE || QT_NO_IMAGEFORMAT_PNG
+#else // QT_NO_IMAGEFORMAT_PNG
struct QWindowsCustomPngCursor {
Qt::CursorShape shape;
int size;
@@ -526,7 +477,7 @@ QWindowsCursor::PixmapCursor QWindowsCursor::customCursor(Qt::CursorShape cursor
QString::fromLatin1(bestFit->fileName));
return PixmapCursor(rawImage, QPoint(bestFit->hotSpotX, bestFit->hotSpotY));
}
-#endif // Q_OS_WINCE || QT_NO_IMAGEFORMAT_PNG
+#endif // !QT_NO_IMAGEFORMAT_PNG
struct QWindowsStandardCursorMapping {
Qt::CursorShape shape;
@@ -575,13 +526,8 @@ HCURSOR QWindowsCursor::createCursorFromShape(Qt::CursorShape cursorShape, const
// Load available standard cursors from resources
const QWindowsStandardCursorMapping *sEnd = standardCursors + sizeof(standardCursors) / sizeof(standardCursors[0]);
for (const QWindowsStandardCursorMapping *s = standardCursors; s < sEnd; ++s) {
- if (s->shape == cursorShape) {
-#ifndef Q_OS_WINCE
+ if (s->shape == cursorShape)
return static_cast<HCURSOR>(LoadImage(0, s->resource, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED));
-#else
- return LoadCursor(0, s->resource);
-#endif
- }
}
qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cursorShape);
@@ -677,7 +623,6 @@ QPoint QWindowsCursor::mousePosition()
QWindowsCursor::CursorState QWindowsCursor::cursorState()
{
-#ifndef Q_OS_WINCE
enum { cursorShowing = 0x1, cursorSuppressed = 0x2 }; // Windows 8: CURSOR_SUPPRESSED
CURSORINFO cursorInfo;
cursorInfo.cbSize = sizeof(CURSORINFO);
@@ -687,7 +632,6 @@ QWindowsCursor::CursorState QWindowsCursor::cursorState()
if (cursorInfo.flags & cursorSuppressed)
return CursorSuppressed;
}
-#endif // !Q_OS_WINCE
return CursorHidden;
}
@@ -758,7 +702,6 @@ QPixmap QWindowsCursor::dragDefaultCursor(Qt::DropAction action) const
"...............XXXX....."};
if (m_ignoreDragCursor.isNull()) {
-#if !defined (Q_OS_WINCE)
HCURSOR cursor = LoadCursor(NULL, IDC_NO);
ICONINFO iconInfo = {0, 0, 0, 0, 0};
GetIconInfo(cursor, &iconInfo);
@@ -782,9 +725,6 @@ QPixmap QWindowsCursor::dragDefaultCursor(Qt::DropAction action) const
DeleteObject(iconInfo.hbmMask);
DeleteObject(iconInfo.hbmColor);
DestroyCursor(cursor);
-#else // !Q_OS_WINCE
- m_ignoreDragCursor = QPixmap(ignoreDragCursorXpmC);
-#endif // !Q_OS_WINCE
}
return m_ignoreDragCursor;
}
diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h
index c0f9235c30..6fff5f9ab1 100644
--- a/src/plugins/platforms/windows/qwindowscursor.h
+++ b/src/plugins/platforms/windows/qwindowscursor.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSCURSOR_H
#define QWINDOWSCURSOR_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <qpa/qplatformcursor.h>
#include <QtCore/QSharedPointer>
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index d5e5f87e5c..a7106c972b 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -70,300 +70,10 @@
#include <algorithm>
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
// #define USE_NATIVE_COLOR_DIALOG /* Testing purposes only */
-#ifdef Q_CC_MINGW /* Add missing declarations for MinGW */
-
-#ifndef __IShellLibrary_FWD_DEFINED__
-
-/* Constants obtained by running the below stream operator for
- * CLSID, IID on the constants in the Windows SDK libraries. */
-
-static const IID IID_IFileOpenDialog = {0xd57c7288, 0xd4ad, 0x4768, {0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60}};
-static const IID IID_IFileSaveDialog = {0x84bccd23, 0x5fde, 0x4cdb,{0xae, 0xa4, 0xaf, 0x64, 0xb8, 0x3d, 0x78, 0xab}};
-#ifdef __MINGW64_VERSION_MAJOR
-static const IID q_IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe}};
-#define IID_IShellItem q_IID_IShellItem
-#else
-static const IID IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe}};
-static const IID IID_IShellItemArray = {0xb63ea76d, 0x1f85, 0x456f, {0xa1, 0x9c, 0x48, 0x15, 0x9e, 0xfa, 0x85, 0x8b}};
-# define LFF_FORCEFILESYSTEM 1
-#endif
-static const IID IID_IFileDialogEvents = {0x973510db, 0x7d7f, 0x452b,{0x89, 0x75, 0x74, 0xa8, 0x58, 0x28, 0xd3, 0x54}};
-static const CLSID CLSID_FileOpenDialog = {0xdc1c5a9c, 0xe88a, 0x4dde, {0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7}};
-static const CLSID CLSID_FileSaveDialog = {0xc0b4e2f3, 0xba21, 0x4773,{0x8d, 0xba, 0x33, 0x5e, 0xc9, 0x46, 0xeb, 0x8b}};
-
-typedef struct _COMDLG_FILTERSPEC
-{
- LPCWSTR pszName;
- LPCWSTR pszSpec;
-} COMDLG_FILTERSPEC;
-
-
-#define FOS_OVERWRITEPROMPT 0x2
-#define FOS_STRICTFILETYPES 0x4
-#define FOS_NOCHANGEDIR 0x8
-#define FOS_PICKFOLDERS 0x20
-#define FOS_FORCEFILESYSTEM 0x40
-#define FOS_ALLNONSTORAGEITEMS 0x80
-#define FOS_NOVALIDATE 0x100
-#define FOS_ALLOWMULTISELECT 0x200
-#define FOS_PATHMUSTEXIST 0x800
-#define FOS_FILEMUSTEXIST 0x1000
-#define FOS_CREATEPROMPT 0x2000
-#define FOS_SHAREAWARE 0x4000
-#define FOS_NOREADONLYRETURN 0x8000
-#define FOS_NOTESTFILECREATE 0x10000
-#define FOS_HIDEMRUPLACES 0x20000
-#define FOS_HIDEPINNEDPLACES 0x40000
-#define FOS_NODEREFERENCELINKS 0x100000
-#define FOS_DONTADDTORECENT 0x2000000
-#define FOS_FORCESHOWHIDDEN 0x10000000
-#define FOS_DEFAULTNOMINIMODE 0x20000000
-#define FOS_FORCEPREVIEWPANEON 0x40000000
-
-#if __MINGW64_VERSION_MAJOR < 2
-typedef int GETPROPERTYSTOREFLAGS;
-#define GPS_DEFAULT 0x00000000
-#define GPS_HANDLERPROPERTIESONLY 0x00000001
-#define GPS_READWRITE 0x00000002
-#define GPS_TEMPORARY 0x00000004
-#define GPS_FASTPROPERTIESONLY 0x00000008
-#define GPS_OPENSLOWITEM 0x00000010
-#define GPS_DELAYCREATION 0x00000020
-#define GPS_BESTEFFORT 0x00000040
-#define GPS_MASK_VALID 0x0000007F
-#endif
-
-typedef int (QT_WIN_CALLBACK* BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
-// message from browser
-#define BFFM_INITIALIZED 1
-#define BFFM_SELCHANGED 2
-#define BFFM_ENABLEOK (WM_USER + 101)
-// Browsing for directory.
-#define BIF_NONEWFOLDERBUTTON 0x0200
-#define BIF_NOTRANSLATETARGETS 0x0400
-#define BIF_BROWSEFORCOMPUTER 0x1000
-#define BIF_BROWSEFORPRINTER 0x2000
-#define BIF_BROWSEINCLUDEFILES 0x4000
-#define BIF_SHAREABLE 0x8000
-
-//the enums
-typedef enum {
- SIATTRIBFLAGS_AND = 0x1,
- SIATTRIBFLAGS_OR = 0x2,
- SIATTRIBFLAGS_APPCOMPAT = 0x3,
- SIATTRIBFLAGS_MASK = 0x3
-} SIATTRIBFLAGS;
-#ifndef __MINGW64_VERSION_MAJOR
-typedef enum {
- SIGDN_NORMALDISPLAY = 0x00000000,
- SIGDN_PARENTRELATIVEPARSING = 0x80018001,
- SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
- SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,
- SIGDN_PARENTRELATIVEEDITING = 0x80031001,
- SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,
- SIGDN_FILESYSPATH = 0x80058000,
- SIGDN_URL = 0x80068000
-} SIGDN;
-#endif
-typedef enum {
- FDAP_BOTTOM = 0x00000000,
- FDAP_TOP = 0x00000001
-} FDAP;
-typedef enum {
- FDESVR_DEFAULT = 0x00000000,
- FDESVR_ACCEPT = 0x00000001,
- FDESVR_REFUSE = 0x00000002
-} FDE_SHAREVIOLATION_RESPONSE;
-typedef FDE_SHAREVIOLATION_RESPONSE FDE_OVERWRITE_RESPONSE;
-
-//the structs
-typedef struct {
- LPCWSTR pszName;
- LPCWSTR pszSpec;
-} qt_COMDLG_FILTERSPEC;
-typedef struct {
- GUID fmtid;
- DWORD pid;
-} qt_PROPERTYKEY;
-
-typedef struct {
- USHORT cb;
- BYTE abID[1];
-} qt_SHITEMID, *qt_LPSHITEMID;
-typedef struct {
- qt_SHITEMID mkid;
-} qt_ITEMIDLIST, *qt_LPITEMIDLIST;
-typedef const qt_ITEMIDLIST *qt_LPCITEMIDLIST;
-typedef struct {
- HWND hwndOwner;
- qt_LPCITEMIDLIST pidlRoot;
- LPWSTR pszDisplayName;
- LPCWSTR lpszTitle;
- UINT ulFlags;
- BFFCALLBACK lpfn;
- LPARAM lParam;
- int iImage;
-} qt_BROWSEINFO;
-
-#endif // __IShellLibrary_FWD_DEFINED__
-
-#ifndef __IFileDialogEvents_FWD_DEFINED__
-DECLARE_INTERFACE(IFileDialogEvents);
-#endif
-
-#ifndef __IShellItem_INTERFACE_DEFINED__
-DECLARE_INTERFACE_(IShellItem, IUnknown)
-{
- STDMETHOD(BindToHandler)(THIS_ IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppv) PURE;
- STDMETHOD(GetParent)(THIS_ IShellItem **ppsi) PURE;
- STDMETHOD(GetDisplayName)(THIS_ SIGDN sigdnName, LPWSTR *ppszName) PURE;
- STDMETHOD(GetAttributes)(THIS_ ULONG sfgaoMask, ULONG *psfgaoAttribs) PURE;
- STDMETHOD(Compare)(THIS_ IShellItem *psi, DWORD hint, int *piOrder) PURE;
-};
-#endif
-
-#ifndef __IShellItemFilter_INTERFACE_DEFINED__
-DECLARE_INTERFACE_(IShellItemFilter, IUnknown)
-{
- STDMETHOD(IncludeItem)(THIS_ IShellItem *psi) PURE;
- STDMETHOD(GetEnumFlagsForItem)(THIS_ IShellItem *psi, DWORD *pgrfFlags) PURE;
-};
-#endif
-
-#ifndef __IEnumShellItems_INTERFACE_DEFINED__
-DECLARE_INTERFACE_(IEnumShellItems, IUnknown)
-{
- STDMETHOD(Next)(THIS_ ULONG celt, IShellItem **rgelt, ULONG *pceltFetched) PURE;
- STDMETHOD(Skip)(THIS_ ULONG celt) PURE;
- STDMETHOD(Reset)(THIS_) PURE;
- STDMETHOD(Clone)(THIS_ IEnumShellItems **ppenum) PURE;
-};
-#endif
-
-#ifndef __IShellItemArray_INTERFACE_DEFINED__
-DECLARE_INTERFACE_(IShellItemArray, IUnknown)
-{
- STDMETHOD(BindToHandler)(THIS_ IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut) PURE;
- STDMETHOD(GetPropertyStore)(THIS_ GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) PURE;
- STDMETHOD(GetPropertyDescriptionList)(THIS_ const qt_PROPERTYKEY *keyType, REFIID riid, void **ppv) PURE;
- STDMETHOD(GetAttributes)(THIS_ SIATTRIBFLAGS dwAttribFlags, ULONG sfgaoMask, ULONG *psfgaoAttribs) PURE;
- STDMETHOD(GetCount)(THIS_ DWORD *pdwNumItems) PURE;
- STDMETHOD(GetItemAt)(THIS_ DWORD dwIndex, IShellItem **ppsi) PURE;
- STDMETHOD(EnumItems)(THIS_ IEnumShellItems **ppenumShellItems) PURE;
-};
-#endif
-
-#ifndef __IShellLibrary_INTERFACE_DEFINED__
-
-enum LIBRARYOPTIONFLAGS {};
-enum DEFAULTSAVEFOLDERTYPE { DSFT_DETECT = 1 };
-enum LIBRARYSAVEFLAGS {};
-
-DECLARE_INTERFACE_(IShellLibrary, IUnknown)
-{
- STDMETHOD(LoadLibraryFromItem)(THIS_ IShellItem *psiLibrary, DWORD grfMode) PURE;
- STDMETHOD(LoadLibraryFromKnownFolder)(THIS_ const GUID &kfidLibrary, DWORD grfMode) PURE;
- STDMETHOD(AddFolder)(THIS_ IShellItem *psiLocation) PURE;
- STDMETHOD(RemoveFolder)(THIS_ IShellItem *psiLocation) PURE;
- STDMETHOD(GetFolders)(THIS_ int lff, REFIID riid, void **ppv) PURE;
- STDMETHOD(ResolveFolder)(THIS_ IShellItem *psiFolderToResolve, DWORD dwTimeout, REFIID riid, void **ppv) PURE;
- STDMETHOD(GetDefaultSaveFolder)(THIS_ DEFAULTSAVEFOLDERTYPE dsft, REFIID riid, void **ppv) PURE;
- STDMETHOD(SetDefaultSaveFolder)(THIS_ DEFAULTSAVEFOLDERTYPE dsft, IShellItem *psi) PURE;
- STDMETHOD(GetOptions)(THIS_ LIBRARYOPTIONFLAGS *plofOptions) PURE;
- STDMETHOD(SetOptions)(THIS_ LIBRARYOPTIONFLAGS lofMask, LIBRARYOPTIONFLAGS lofOptions) PURE;
- STDMETHOD(GetFolderType)(THIS_ GUID *pftid) PURE;
- STDMETHOD(SetFolderType)(THIS_ const GUID &ftid) PURE;
- STDMETHOD(GetIcon)(THIS_ LPWSTR *ppszIcon) PURE;
- STDMETHOD(SetIcon)(THIS_ LPCWSTR pszIcon) PURE;
- STDMETHOD(Commit)(THIS_) PURE;
- STDMETHOD(Save)(THIS_ IShellItem *psiFolderToSaveIn, LPCWSTR pszLibraryName, LIBRARYSAVEFLAGS lsf, IShellItem **ppsiSavedTo) PURE;
- STDMETHOD(SaveInKnownFolder)(THIS_ const GUID &kfidToSaveIn, LPCWSTR pszLibraryName, LIBRARYSAVEFLAGS lsf,IShellItem **ppsiSavedTo) PURE;
-};
-#endif
-
-#ifndef __IModalWindow_INTERFACE_DEFINED__
-DECLARE_INTERFACE_(IModalWindow, IUnknown)
-{
- STDMETHOD(Show)(THIS_ HWND hwndParent) PURE;
-};
-#endif
-
-#ifndef __IFileDialog_INTERFACE_DEFINED__
-DECLARE_INTERFACE_(IFileDialog, IModalWindow)
-{
- STDMETHOD(SetFileTypes)(THIS_ UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec) PURE;
- STDMETHOD(SetFileTypeIndex)(THIS_ UINT iFileType) PURE;
- STDMETHOD(GetFileTypeIndex)(THIS_ UINT *piFileType) PURE;
- STDMETHOD(Advise)(THIS_ IFileDialogEvents *pfde, DWORD *pdwCookie) PURE;
- STDMETHOD(Unadvise)(THIS_ DWORD dwCookie) PURE;
- STDMETHOD(SetOptions)(THIS_ DWORD fos) PURE;
- STDMETHOD(GetOptions)(THIS_ DWORD *pfos) PURE;
- STDMETHOD(SetDefaultFolder)(THIS_ IShellItem *psi) PURE;
- STDMETHOD(SetFolder)(THIS_ IShellItem *psi) PURE;
- STDMETHOD(GetFolder)(THIS_ IShellItem **ppsi) PURE;
- STDMETHOD(GetCurrentSelection)(THIS_ IShellItem **ppsi) PURE;
- STDMETHOD(SetFileName)(THIS_ LPCWSTR pszName) PURE;
- STDMETHOD(GetFileName)(THIS_ LPWSTR *pszName) PURE;
- STDMETHOD(SetTitle)(THIS_ LPCWSTR pszTitle) PURE;
- STDMETHOD(SetOkButtonLabel)(THIS_ LPCWSTR pszText) PURE;
- STDMETHOD(SetFileNameLabel)(THIS_ LPCWSTR pszLabel) PURE;
- STDMETHOD(GetResult)(THIS_ IShellItem **ppsi) PURE;
- STDMETHOD(AddPlace)(THIS_ IShellItem *psi, FDAP fdap) PURE;
- STDMETHOD(SetDefaultExtension)(THIS_ LPCWSTR pszDefaultExtension) PURE;
- STDMETHOD(Close)(THIS_ HRESULT hr) PURE;
- STDMETHOD(SetClientGuid)(THIS_ REFGUID guid) PURE;
- STDMETHOD(ClearClientData)(THIS_) PURE;
- STDMETHOD(SetFilter)(THIS_ IShellItemFilter *pFilter) PURE;
-};
-#endif
-
-#ifndef __IFileDialogEvents_INTERFACE_DEFINED__
-DECLARE_INTERFACE_(IFileDialogEvents, IUnknown)
-{
- STDMETHOD(OnFileOk)(THIS_ IFileDialog *pfd) PURE;
- STDMETHOD(OnFolderChanging)(THIS_ IFileDialog *pfd, IShellItem *psiFolder) PURE;
- STDMETHOD(OnFolderChange)(THIS_ IFileDialog *pfd) PURE;
- STDMETHOD(OnSelectionChange)(THIS_ IFileDialog *pfd) PURE;
- STDMETHOD(OnShareViolation)(THIS_ IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse) PURE;
- STDMETHOD(OnTypeChange)(THIS_ IFileDialog *pfd) PURE;
- STDMETHOD(OnOverwrite)(THIS_ IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse) PURE;
-};
-#endif
-
-#ifndef __IFileOpenDialog_INTERFACE_DEFINED__
-DECLARE_INTERFACE_(IFileOpenDialog, IFileDialog)
-{
- STDMETHOD(GetResults)(THIS_ IShellItemArray **ppenum) PURE;
- STDMETHOD(GetSelectedItems)(THIS_ IShellItemArray **ppsai) PURE;
-};
-#endif
-
-#ifndef __IPropertyStore_FWD_DEFINED__
-typedef IUnknown IPropertyStore;
-#endif
-
-#ifndef __IFileOperationProgressSink_FWD_DEFINED__
-typedef IUnknown IFileOperationProgressSink;
-#endif
-
-#ifndef __IFileSaveDialog_INTERFACE_DEFINED__
-DECLARE_INTERFACE_(IFileSaveDialog, IFileDialog)
-{
-public:
- STDMETHOD(SetSaveAsItem)(THIS_ IShellItem *psi) PURE;
- STDMETHOD(SetProperties)(THIS_ IPropertyStore *pStore) PURE;
- STDMETHOD(SetCollectedProperties)(THIS_ IPropertyStore *pStore) PURE;
- STDMETHOD(GetProperties)(THIS_ IPropertyStore **ppStore) PURE;
- STDMETHOD(ApplyProperties)(THIS_ IShellItem *psi, IPropertyStore *pStore, HWND hwnd, IFileOperationProgressSink *pSink) PURE;
-};
-#endif
-
-#endif // Q_CC_MINGW
-
QT_BEGIN_NAMESPACE
#ifndef QT_NO_DEBUG_STREAM
@@ -637,7 +347,6 @@ void QWindowsDialogHelperBase<BaseClass>::stopTimer()
}
}
-#ifndef Q_OS_WINCE
// Find a file dialog window created by IFileDialog by process id, window
// title and class, which starts with a hash '#'.
@@ -673,7 +382,6 @@ static inline HWND findDialogWindow(const QString &title)
EnumWindows(findDialogEnumWindowsProc, reinterpret_cast<LPARAM>(&context));
return context.hwnd;
}
-#endif // !Q_OS_WINCE
template <class BaseClass>
void QWindowsDialogHelperBase<BaseClass>::hide()
@@ -989,24 +697,19 @@ void QWindowsNativeFileDialogBase::setWindowTitle(const QString &title)
IShellItem *QWindowsNativeFileDialogBase::shellItem(const QUrl &url)
{
-#ifndef Q_OS_WINCE
if (url.isLocalFile()) {
- if (!QWindowsContext::shell32dll.sHCreateItemFromParsingName)
- return Q_NULLPTR;
IShellItem *result = Q_NULLPTR;
const QString native = QDir::toNativeSeparators(url.toLocalFile());
const HRESULT hr =
- QWindowsContext::shell32dll.sHCreateItemFromParsingName(reinterpret_cast<const wchar_t *>(native.utf16()),
- NULL, IID_IShellItem,
- reinterpret_cast<void **>(&result));
+ SHCreateItemFromParsingName(reinterpret_cast<const wchar_t *>(native.utf16()),
+ NULL, IID_IShellItem,
+ reinterpret_cast<void **>(&result));
if (FAILED(hr)) {
qErrnoWarning("%s: SHCreateItemFromParsingName(%s)) failed", __FUNCTION__, qPrintable(url.toString()));
return Q_NULLPTR;
}
return result;
} else if (url.scheme() == QLatin1String("clsid")) {
- if (!QWindowsContext::shell32dll.sHGetKnownFolderIDList || !QWindowsContext::shell32dll.sHCreateItemFromIDList)
- return Q_NULLPTR;
// Support for virtual folders via GUID
// (see https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx)
// specified as "clsid:<GUID>" (without '{', '}').
@@ -1017,12 +720,12 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QUrl &url)
return Q_NULLPTR;
}
PIDLIST_ABSOLUTE idList;
- HRESULT hr = QWindowsContext::shell32dll.sHGetKnownFolderIDList(uuid, 0, 0, &idList);
+ HRESULT hr = SHGetKnownFolderIDList(uuid, 0, 0, &idList);
if (FAILED(hr)) {
qErrnoWarning("%s: SHGetKnownFolderIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString()));
return Q_NULLPTR;
}
- hr = QWindowsContext::shell32dll.sHCreateItemFromIDList(idList, IID_IShellItem, reinterpret_cast<void **>(&result));
+ hr = SHCreateItemFromIDList(idList, IID_IShellItem, reinterpret_cast<void **>(&result));
CoTaskMemFree(idList);
if (FAILED(hr)) {
qErrnoWarning("%s: SHCreateItemFromIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString()));
@@ -1032,9 +735,6 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QUrl &url)
} else {
qWarning() << __FUNCTION__ << ": Unhandled scheme: " << url.scheme();
}
-#else // !Q_OS_WINCE
- Q_UNUSED(url)
-#endif
return 0;
}
@@ -1050,11 +750,9 @@ void QWindowsNativeFileDialogBase::setDirectory(const QUrl &directory)
QString QWindowsNativeFileDialogBase::directory() const
{
-#ifndef Q_OS_WINCE
IShellItem *item = 0;
if (m_fileDialog && SUCCEEDED(m_fileDialog->GetFolder(&item)) && item)
return QWindowsNativeFileDialogBase::itemPath(item);
-#endif
return QString();
}
@@ -1106,7 +804,7 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode,
qErrnoWarning("%s: SetOptions() failed", __FUNCTION__);
}
-#if !defined(Q_OS_WINCE) && defined(__IShellLibrary_INTERFACE_DEFINED__) // Windows SDK 7
+#if defined(__IShellLibrary_INTERFACE_DEFINED__) // Windows SDK 7
// Helper for "Libraries": collections of folders appearing from Windows 7
// on, visible in the file dialogs.
@@ -1159,7 +857,7 @@ QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *i
return result;
}
-#else // !Q_OS_WINCE && __IShellLibrary_INTERFACE_DEFINED__
+#else // __IShellLibrary_INTERFACE_DEFINED__
QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *)
{
@@ -1171,7 +869,7 @@ QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *)
return QString();
}
-#endif // Q_OS_WINCE || !__IShellLibrary_INTERFACE_DEFINED__
+#endif // !__IShellLibrary_INTERFACE_DEFINED__
QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item)
{
@@ -1417,14 +1115,12 @@ bool QWindowsNativeFileDialogBase::onFileOk()
void QWindowsNativeFileDialogBase::close()
{
m_fileDialog->Close(S_OK);
-#ifndef Q_OS_WINCE
// IFileDialog::Close() does not work unless invoked from a callback.
// Try to find the window and send it a WM_CLOSE in addition.
const HWND hwnd = findDialogWindow(m_title);
qCDebug(lcQpaDialogs) << __FUNCTION__ << "closing" << hwnd;
if (hwnd && IsWindowVisible(hwnd))
PostMessageW(hwnd, WM_CLOSE, 0, 0);
-#endif // !Q_OS_WINCE
}
HRESULT QWindowsNativeFileDialogEventHandler::OnFolderChanging(IFileDialog *, IShellItem *item)
@@ -1725,8 +1421,6 @@ QString QWindowsFileDialogHelper::selectedNameFilter() const
return m_data.selectedNameFilter();
}
-#ifndef Q_OS_WINCE
-
/*!
\class QWindowsXpNativeFileDialog
\brief Native Windows directory dialog for Windows XP using SHlib-functions.
@@ -2050,8 +1744,6 @@ QString QWindowsXpFileDialogHelper::selectedNameFilter() const
return m_data.selectedNameFilter();
}
-#endif // Q_OS_WINCE
-
/*!
\class QWindowsNativeColorDialog
\brief Native Windows color dialog.
@@ -2179,7 +1871,6 @@ namespace QWindowsDialogs {
// QWindowsDialogHelperBase creation functions
bool useHelper(QPlatformTheme::DialogType type)
{
-#if !defined(_WIN32_WCE) || _WIN32_WCE < 0x800
if (QWindowsIntegration::instance()->options() & QWindowsIntegration::NoNativeDialogs)
return false;
switch (type) {
@@ -2198,28 +1889,20 @@ bool useHelper(QPlatformTheme::DialogType type)
break;
}
return false;
-#else
- return false;
-#endif // !defined(_WIN32_WCE) || _WIN32_WCE < 0x800
}
QPlatformDialogHelper *createHelper(QPlatformTheme::DialogType type)
{
-#if !defined(_WIN32_WCE) || _WIN32_WCE < 0x800
if (QWindowsIntegration::instance()->options() & QWindowsIntegration::NoNativeDialogs)
return 0;
switch (type) {
- case QPlatformTheme::FileDialog:
-#ifndef Q_OS_WINCE // Note: "Windows XP Professional x64 Edition has version number WV_5_2 (WV_2003).
+ case QPlatformTheme::FileDialog: // Note: "Windows XP Professional x64 Edition has version number WV_5_2 (WV_2003).
if (QWindowsIntegration::instance()->options() & QWindowsIntegration::XpNativeDialogs
|| QSysInfo::windowsVersion() <= QSysInfo::WV_2003) {
return new QWindowsXpFileDialogHelper();
}
if (QSysInfo::windowsVersion() > QSysInfo::WV_2003)
return new QWindowsFileDialogHelper();
-#else
- return new QWindowsFileDialogHelper();
-#endif // Q_OS_WINCE
case QPlatformTheme::ColorDialog:
#ifdef USE_NATIVE_COLOR_DIALOG
return new QWindowsColorDialogHelper();
@@ -2233,9 +1916,6 @@ QPlatformDialogHelper *createHelper(QPlatformTheme::DialogType type)
break;
}
return 0;
-#else
- return 0;
-#endif // !defined(_WIN32_WCE) || _WIN32_WCE < 0x800
}
} // namespace QWindowsDialogs
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
index b643d9a920..b3101a1419 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSDIALOGHELPER_H
#define QWINDOWSDIALOGHELPER_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <qpa/qplatformdialoghelper.h>
#include <qpa/qplatformtheme.h>
#include <QtCore/QStringList>
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 246f53ef2f..26a5131927 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -45,7 +45,7 @@
#endif
#include "qwindowsintegration.h"
#include "qwindowsole.h"
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include "qwindowswindow.h"
#include "qwindowsmousehandler.h"
#include "qwindowscursor.h"
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp
index 0ce4e87e52..6124b004b6 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp
@@ -95,13 +95,9 @@ static void *resolveFunc(HMODULE lib, const char *name)
return proc;
}
#else
-static void *resolveFunc(HMODULE lib, const char *name)
+static inline void *resolveFunc(HMODULE lib, const char *name)
{
-# ifndef Q_OS_WINCE
- return (void *) ::GetProcAddress(lib, name);
-# else
- return (void *) ::GetProcAddress(lib, (const wchar_t *) QString::fromLatin1(name).utf16());
-# endif // Q_OS_WINCE
+ return ::GetProcAddress(lib, name);
}
#endif // Q_CC_MINGW
@@ -121,7 +117,7 @@ void *QWindowsLibEGL::resolve(const char *name)
bool QWindowsLibEGL::init()
{
const char dllName[] = QT_STRINGIFY(LIBEGL_NAME)
-#if defined(QT_DEBUG) && !defined(Q_OS_WINCE)
+#if defined(QT_DEBUG)
"d"
#endif
"";
@@ -178,7 +174,7 @@ bool QWindowsLibGLESv2::init()
{
const char dllName[] = QT_STRINGIFY(LIBGLESV2_NAME)
-#if defined(QT_DEBUG) && !defined(Q_OS_WINCE)
+#if defined(QT_DEBUG)
"d"
#endif
"";
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
index 68a8fc5390..0e00ee6910 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
@@ -42,7 +42,7 @@
#include "qwindowscontext.h"
#include "qwindowsfontengine.h"
#include "qwindowsfontenginedirectwrite.h"
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtGui/QFont>
#include <QtGui/QGuiApplication>
@@ -57,10 +57,6 @@
#include <wchar.h>
-#ifdef Q_OS_WINCE
-# include "qplatformfunctions_wince.h"
-#endif
-
#if !defined(QT_NO_DIRECTWRITE)
# if defined(QT_USE_DIRECTWRITE2)
# include <dwrite_2.h>
@@ -947,17 +943,6 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet,
quint32 codePageRange[2] = {
signature->fsCsb[0], signature->fsCsb[1]
};
-#ifdef Q_OS_WINCE
- if (signature->fsUsb[0] == 0) {
- // If the unicode ranges bit mask is zero then
- // EnumFontFamiliesEx failed to determine it properly.
- // In this case we just pretend that the font supports all languages.
- unicodeRange[0] = 0xbfffffff; // second most significant bit must be zero
- unicodeRange[1] = 0xffffffff;
- unicodeRange[2] = 0xffffffff;
- unicodeRange[3] = 0xffffffff;
- }
-#endif
writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
// ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
// the symbol for Baht, and Windows thus reports that it supports the Thai script.
@@ -1117,9 +1102,8 @@ QWindowsFontEngineDataPtr sharedFontData()
}
#endif // QT_NO_THREAD
-#ifndef Q_OS_WINCE
extern Q_GUI_EXPORT bool qt_needs_a8_gamma_correction;
-#endif
+
QWindowsFontDatabase::QWindowsFontDatabase()
{
// Properties accessed by QWin32PrintEngine (Qt Print Support)
@@ -1133,9 +1117,7 @@ QWindowsFontDatabase::QWindowsFontDatabase()
qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: "
<< data->clearTypeEnabled << "gamma: " << data->fontSmoothingGamma;
}
-#ifndef Q_OS_WINCE
qt_needs_a8_gamma_correction = true;
-#endif
}
QWindowsFontDatabase::~QWindowsFontDatabase()
@@ -1586,14 +1568,12 @@ LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request)
int strat = OUT_DEFAULT_PRECIS;
if (request.styleStrategy & QFont::PreferBitmap) {
strat = OUT_RASTER_PRECIS;
-#ifndef Q_OS_WINCE
} else if (request.styleStrategy & QFont::PreferDevice) {
strat = OUT_DEVICE_PRECIS;
} else if (request.styleStrategy & QFont::PreferOutline) {
strat = OUT_OUTLINE_PRECIS;
} else if (request.styleStrategy & QFont::ForceOutline) {
strat = OUT_TT_ONLY_PRECIS;
-#endif
}
lf.lfOutPrecision = strat;
@@ -1602,10 +1582,8 @@ LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request)
if (request.styleStrategy & QFont::PreferMatch)
qual = DRAFT_QUALITY;
-#ifndef Q_OS_WINCE
else if (request.styleStrategy & QFont::PreferQuality)
qual = PROOF_QUALITY;
-#endif
if (request.styleStrategy & QFont::PreferAntialias) {
if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && !(request.styleStrategy & QFont::NoSubpixelAntialias)) {
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h
index 574e20ef30..8b8c9c15f4 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase.h
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h
@@ -42,7 +42,7 @@
#include <qpa/qplatformfontdatabase.h>
#include <QtCore/QSharedPointer>
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#if !defined(QT_NO_DIRECTWRITE)
struct IDWriteFactory;
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
index fb75e75dcd..d782519c68 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
@@ -53,10 +53,6 @@
#include <QtGui/QFontDatabase>
#include <wchar.h>
-#ifdef Q_OS_WINCE
-#include <QtCore/QFile>
-#include <QtEndian>
-#endif
QT_BEGIN_NAMESPACE
@@ -108,8 +104,6 @@ static FontFile * createFontFile(const QString &fileName, int index)
extern bool localizedName(const QString &name);
extern QString getEnglishName(const QString &familyName);
-#ifndef Q_OS_WINCE
-
namespace {
struct FontKey
{
@@ -165,223 +159,6 @@ static const FontKey *findFontKey(const QString &name, int *indexIn = Q_NULLPTR)
return Q_NULLPTR;
}
-#else // Q_OS_WINCE
-
-typedef struct {
- quint16 majorVersion;
- quint16 minorVersion;
- quint16 numTables;
- quint16 searchRange;
- quint16 entrySelector;
- quint16 rangeShift;
-} OFFSET_TABLE;
-
-typedef struct {
- quint32 tag;
- quint32 checkSum;
- quint32 offset;
- quint32 length;
-} TABLE_DIRECTORY;
-
-typedef struct {
- quint16 fontSelector;
- quint16 nrCount;
- quint16 storageOffset;
-} NAME_TABLE_HEADER;
-
-typedef struct {
- quint16 platformID;
- quint16 encodingID;
- quint16 languageID;
- quint16 nameID;
- quint16 stringLength;
- quint16 stringOffset;
-} NAME_RECORD;
-
-typedef struct {
- quint32 tag;
- quint16 majorVersion;
- quint16 minorVersion;
- quint32 numFonts;
-} TTC_TABLE_HEADER;
-
-static QString fontNameFromTTFile(const QString &filename, int startPos = 0)
-{
- QFile f(filename);
- QString retVal;
- qint64 bytesRead;
- qint64 bytesToRead;
-
- if (f.open(QIODevice::ReadOnly)) {
- f.seek(startPos);
- OFFSET_TABLE ttOffsetTable;
- bytesToRead = sizeof(OFFSET_TABLE);
- bytesRead = f.read((char*)&ttOffsetTable, bytesToRead);
- if (bytesToRead != bytesRead)
- return retVal;
- ttOffsetTable.numTables = qFromBigEndian(ttOffsetTable.numTables);
- ttOffsetTable.majorVersion = qFromBigEndian(ttOffsetTable.majorVersion);
- ttOffsetTable.minorVersion = qFromBigEndian(ttOffsetTable.minorVersion);
-
- if (ttOffsetTable.majorVersion != 1 || ttOffsetTable.minorVersion != 0)
- return retVal;
-
- TABLE_DIRECTORY tblDir;
- bool found = false;
-
- for (int i = 0; i < ttOffsetTable.numTables; i++) {
- bytesToRead = sizeof(TABLE_DIRECTORY);
- bytesRead = f.read((char*)&tblDir, bytesToRead);
- if (bytesToRead != bytesRead)
- return retVal;
- if (qFromBigEndian(tblDir.tag) == MAKE_TAG('n', 'a', 'm', 'e')) {
- found = true;
- tblDir.length = qFromBigEndian(tblDir.length);
- tblDir.offset = qFromBigEndian(tblDir.offset);
- break;
- }
- }
-
- if (found) {
- f.seek(tblDir.offset);
- NAME_TABLE_HEADER ttNTHeader;
- bytesToRead = sizeof(NAME_TABLE_HEADER);
- bytesRead = f.read((char*)&ttNTHeader, bytesToRead);
- if (bytesToRead != bytesRead)
- return retVal;
- ttNTHeader.nrCount = qFromBigEndian(ttNTHeader.nrCount);
- ttNTHeader.storageOffset = qFromBigEndian(ttNTHeader.storageOffset);
- NAME_RECORD ttRecord;
- found = false;
-
- for (int i = 0; i < ttNTHeader.nrCount; i++) {
- bytesToRead = sizeof(NAME_RECORD);
- bytesRead = f.read((char*)&ttRecord, bytesToRead);
- if (bytesToRead != bytesRead)
- return retVal;
- ttRecord.nameID = qFromBigEndian(ttRecord.nameID);
- if (ttRecord.nameID == 1) {
- ttRecord.stringLength = qFromBigEndian(ttRecord.stringLength);
- ttRecord.stringOffset = qFromBigEndian(ttRecord.stringOffset);
- int nPos = f.pos();
- f.seek(tblDir.offset + ttRecord.stringOffset + ttNTHeader.storageOffset);
-
- QByteArray nameByteArray = f.read(ttRecord.stringLength);
- if (!nameByteArray.isEmpty()) {
- if (ttRecord.encodingID == 256 || ttRecord.encodingID == 768) {
- //This is UTF-16 in big endian
- int stringLength = ttRecord.stringLength / 2;
- retVal.resize(stringLength);
- QChar *data = retVal.data();
- const ushort *srcData = (const ushort *)nameByteArray.data();
- for (int i = 0; i < stringLength; ++i)
- data[i] = qFromBigEndian(srcData[i]);
- return retVal;
- } else if (ttRecord.encodingID == 0) {
- //This is Latin1
- retVal = QString::fromLatin1(nameByteArray);
- } else {
- qWarning("Could not retrieve Font name from file: %s", qPrintable(QDir::toNativeSeparators(filename)));
- }
- break;
- }
- f.seek(nPos);
- }
- }
- }
- f.close();
- }
- return retVal;
-}
-
-static QStringList fontNamesFromTTCFile(const QString &filename)
-{
- QFile f(filename);
- QStringList retVal;
- qint64 bytesRead;
- qint64 bytesToRead;
-
- if (f.open(QIODevice::ReadOnly)) {
- TTC_TABLE_HEADER ttcTableHeader;
- bytesToRead = sizeof(TTC_TABLE_HEADER);
- bytesRead = f.read((char*)&ttcTableHeader, bytesToRead);
- if (bytesToRead != bytesRead)
- return retVal;
- ttcTableHeader.majorVersion = qFromBigEndian(ttcTableHeader.majorVersion);
- ttcTableHeader.minorVersion = qFromBigEndian(ttcTableHeader.minorVersion);
- ttcTableHeader.numFonts = qFromBigEndian(ttcTableHeader.numFonts);
-
- if (ttcTableHeader.majorVersion < 1 || ttcTableHeader.majorVersion > 2)
- return retVal;
- QVarLengthArray<quint32> offsetTable(ttcTableHeader.numFonts);
- bytesToRead = sizeof(quint32) * ttcTableHeader.numFonts;
- bytesRead = f.read((char*)offsetTable.data(), bytesToRead);
- if (bytesToRead != bytesRead)
- return retVal;
- f.close();
- for (int i = 0; i < (int)ttcTableHeader.numFonts; ++i)
- retVal << fontNameFromTTFile(filename, qFromBigEndian(offsetTable[i]));
- }
- return retVal;
-}
-
-static inline QString fontSettingsOrganization() { return QStringLiteral("Qt-Project"); }
-static inline QString fontSettingsApplication() { return QStringLiteral("Qtbase"); }
-static inline QString fontSettingsGroup() { return QStringLiteral("CEFontCache"); }
-
-static QString findFontFile(const QString &faceName)
-{
- static QHash<QString, QString> fontCache;
-
- if (fontCache.isEmpty()) {
- QSettings settings(QSettings::SystemScope, fontSettingsOrganization(), fontSettingsApplication());
- settings.beginGroup(fontSettingsGroup());
- foreach (const QString &fontName, settings.allKeys())
- fontCache.insert(fontName, settings.value(fontName).toString());
- settings.endGroup();
- }
-
- QString value = fontCache.value(faceName);
-
- //Fallback if we haven't cached the font yet or the font got removed/renamed iterate again over all fonts
- if (value.isEmpty() || !QFile::exists(value)) {
- QSettings settings(QSettings::SystemScope, fontSettingsOrganization(), fontSettingsApplication());
- settings.beginGroup(fontSettingsGroup());
-
- //empty the cache first, as it seems that it is dirty
- settings.remove(QString());
-
- QDirIterator it(QStringLiteral("/Windows"), QStringList() << QStringLiteral("*.ttf") << QStringLiteral("*.ttc"), QDir::Files | QDir::Hidden | QDir::System);
- const QLatin1Char lowerF('f');
- const QLatin1Char upperF('F');
- while (it.hasNext()) {
- const QString fontFile = it.next();
- QStringList fontNames;
- const QChar c = fontFile[fontFile.size() - 1];
- if (c == lowerF || c == upperF)
- fontNames << fontNameFromTTFile(fontFile);
- else
- fontNames << fontNamesFromTTCFile(fontFile);
- foreach (const QString fontName, fontNames) {
- if (fontName.isEmpty())
- continue;
- fontCache.insert(fontName, fontFile);
- settings.setValue(fontName, fontFile);
-
- if (localizedName(fontName)) {
- QString englishFontName = getEnglishName(fontName);
- fontCache.insert(englishFontName, fontFile);
- settings.setValue(englishFontName, fontFile);
- }
- }
- }
- settings.endGroup();
- value = fontCache.value(faceName);
- }
- return value;
-}
-#endif // Q_OS_WINCE
-
static bool addFontToDatabase(const QString &faceName,
const QString &fullName,
uchar charSet,
@@ -453,7 +230,6 @@ static bool addFontToDatabase(const QString &faceName,
}
int index = 0;
-#ifndef Q_OS_WINCE
const FontKey *key = findFontKey(faceName, &index);
if (!key) {
key = findFontKey(fullName, &index);
@@ -465,19 +241,11 @@ static bool addFontToDatabase(const QString &faceName,
return false;
}
QString value = key->fileName;
-#else
- QString value = findFontFile(faceName);
-#endif
-
if (value.isEmpty())
return false;
if (!QDir::isAbsolutePath(value))
-#ifndef Q_OS_WINCE
value.prepend(QFile::decodeName(qgetenv("windir") + "\\Fonts\\"));
-#else
- value.prepend(QFile::decodeName("/Windows/"));
-#endif
QPlatformFontDatabase::registerFont(faceName, QString(), foundryName, weight, style, stretch,
antialias, scalable, size, fixed, writingSystems, createFontFile(value, index));
@@ -501,24 +269,6 @@ static bool addFontToDatabase(const QString &faceName,
return true;
}
-#ifdef Q_OS_WINCE
-static QByteArray getFntTable(HFONT hfont, uint tag)
-{
- HDC hdc = GetDC(0);
- HGDIOBJ oldFont = SelectObject(hdc, hfont);
- quint32 t = qFromBigEndian<quint32>(tag);
- QByteArray buffer;
-
- DWORD length = GetFontData(hdc, t, 0, NULL, 0);
- if (length != GDI_ERROR) {
- buffer.resize(length);
- GetFontData(hdc, t, 0, reinterpret_cast<uchar *>(buffer.data()), length);
- }
- SelectObject(hdc, oldFont);
- return buffer;
-}
-#endif
-
static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric,
DWORD type, LPARAM)
{
@@ -576,8 +326,6 @@ struct PopulateFamiliesContext
};
} // namespace
-#ifndef Q_OS_WINCE
-
// Delayed population of font families
static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric,
@@ -633,74 +381,6 @@ void QWindowsFontDatabaseFT::populateFontDatabase()
QPlatformFontDatabase::registerFontFamily(context.systemDefaultFont);
}
-#else // !Q_OS_WINCE
-
-// Non-delayed population of fonts (Windows CE).
-
-static int QT_WIN_CALLBACK populateFontCe(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric,
- int type, LPARAM lparam)
-{
- // the "@family" fonts are just the same as "family". Ignore them.
- const wchar_t *faceNameW = f->elfLogFont.lfFaceName;
- if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) {
- const uchar charSet = f->elfLogFont.lfCharSet;
-
- FONTSIGNATURE signature;
- QByteArray table;
-
- if (type & TRUETYPE_FONTTYPE) {
- HFONT hfont = CreateFontIndirect(&f->elfLogFont);
- table = getFntTable(hfont, MAKE_TAG('O', 'S', '/', '2'));
- DeleteObject((HGDIOBJ)hfont);
- }
-
- if (table.length() >= 86) {
- // See also qfontdatabase_mac.cpp, offsets taken from OS/2 table in the TrueType spec
- uchar *tableData = reinterpret_cast<uchar *>(table.data());
-
- signature.fsUsb[0] = qFromBigEndian<quint32>(tableData + 42);
- signature.fsUsb[1] = qFromBigEndian<quint32>(tableData + 46);
- signature.fsUsb[2] = qFromBigEndian<quint32>(tableData + 50);
- signature.fsUsb[3] = qFromBigEndian<quint32>(tableData + 54);
-
- signature.fsCsb[0] = qFromBigEndian<quint32>(tableData + 78);
- signature.fsCsb[1] = qFromBigEndian<quint32>(tableData + 82);
- } else {
- memset(&signature, 0, sizeof(signature));
- }
-
- // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
- // identical to a TEXTMETRIC except for the last four members, which we don't use
- // anyway
- const QString faceName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
- if (addFontToDatabase(faceName, QString::fromWCharArray(f->elfFullName),
- charSet, (TEXTMETRIC *)textmetric, &signature, type, true)) {
- PopulateFamiliesContext *context = reinterpret_cast<PopulateFamiliesContext *>(lparam);
- if (!context->seenSystemDefaultFont && faceName == context->systemDefaultFont)
- context->seenSystemDefaultFont = true;
- }
- }
-
- // keep on enumerating
- return 1;
-}
-
-void QWindowsFontDatabaseFT::populateFontDatabase()
-{
- LOGFONT lf;
- lf.lfCharSet = DEFAULT_CHARSET;
- HDC dummy = GetDC(0);
- lf.lfFaceName[0] = 0;
- lf.lfPitchAndFamily = 0;
- PopulateFamiliesContext context(QWindowsFontDatabase::systemDefaultFont().family());
- EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)populateFontCe, reinterpret_cast<LPARAM>(&context), 0);
- ReleaseDC(0, dummy);
- // Work around EnumFontFamiliesEx() not listing the system font, see below.
- if (!context.seenSystemDefaultFont)
- populateFamily(context.systemDefaultFont);
-}
-#endif // Q_OS_WINCE
-
QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, void *handle)
{
QFontEngine *fe = QBasicFontDatabase::fontEngine(fontDef, handle);
@@ -718,21 +398,8 @@ QFontEngine *QWindowsFontDatabaseFT::fontEngine(const QByteArray &fontData, qrea
QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
{
QStringList result;
-
result.append(QWindowsFontDatabase::familyForStyleHint(styleHint));
-
-#ifdef Q_OS_WINCE
- QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\FontLink\\SystemLink"), QSettings::NativeFormat);
- const QStringList fontList = settings.value(family).toStringList();
- foreach (const QString &fallback, fontList) {
- const int sep = fallback.indexOf(QLatin1Char(','));
- if (sep > 0)
- result << fallback.mid(sep + 1);
- }
-#endif
-
result.append(QWindowsFontDatabase::extraTryFontsForFamily(family));
-
result.append(QBasicFontDatabase::fallbacksForFamily(family, style, styleHint, script));
qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h
index 988b0012f7..fa8f777133 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h
@@ -42,7 +42,7 @@
#include <QtPlatformSupport/private/qbasicfontdatabase_p.h>
#include <QtCore/QSharedPointer>
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index 4f3df32f16..744d882bb2 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -42,7 +42,7 @@
#include "qwindowsnativeimage.h"
#include "qwindowscontext.h"
#include "qwindowsfontdatabase.h"
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include "qwindowsfontenginedirectwrite.h"
#include <QtGui/private/qtextengine_p.h> // glyph_metrics_t
@@ -65,10 +65,6 @@
#include <limits.h>
-#ifdef Q_OS_WINCE
-# include "qplatformfunctions_wince.h"
-#endif
-
#if !defined(QT_NO_DIRECTWRITE)
# include <dwrite.h>
#endif
@@ -205,9 +201,6 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
{
int glyph_pos = 0;
{
-#if defined(Q_OS_WINCE)
- {
-#else
if (symbol) {
QStringIterator it(str, str + numChars);
while (it.hasNext()) {
@@ -225,7 +218,6 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
++glyph_pos;
}
} else {
-#endif
QStringIterator it(str, str + numChars);
while (it.hasNext()) {
const uint uc = it.next();
@@ -329,21 +321,16 @@ QWindowsFontEngine::~QWindowsFontEngine()
glyph_t QWindowsFontEngine::glyphIndex(uint ucs4) const
{
- glyph_t glyph;
+ glyph_t glyph = 0;
-#if !defined(Q_OS_WINCE)
if (symbol) {
glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
if (glyph == 0 && ucs4 < 0x100)
glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
} else if (ttf) {
glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
- } else
-#endif
- if (ucs4 >= tm.tmFirstChar && ucs4 <= tm.tmLastChar) {
+ } else if (ucs4 >= tm.tmFirstChar && ucs4 <= tm.tmLastChar) {
glyph = ucs4;
- } else {
- glyph = 0;
}
return glyph;
@@ -377,12 +364,8 @@ bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *g
inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
{
-#if defined(Q_OS_WINCE)
- GetCharWidth32(hdc, glyph, glyph, &width);
-#else
if (ptrGetCharWidthI)
ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
-#endif
}
void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
@@ -467,7 +450,7 @@ glyph_metrics_t QWindowsFontEngine::boundingBox(const QGlyphLayout &glyphs)
return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0);
}
-#ifndef Q_OS_WINCE
+
bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const
{
Q_ASSERT(metrics != 0);
@@ -520,11 +503,9 @@ bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph, const QTransform &t, g
return false;
}
}
-#endif
glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph, const QTransform &t)
{
-#ifndef Q_OS_WINCE
HDC hdc = m_fontEngineData->hdc;
SelectObject(hdc, hfont);
@@ -542,34 +523,6 @@ glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph, const QTransform
}
return glyphMetrics;
-#else
- HDC hdc = m_fontEngineData->hdc;
- HGDIOBJ oldFont = SelectObject(hdc, hfont);
-
- ABC abc;
- int width;
- int advance;
-#ifdef GWES_MGTT // true type fonts
- if (GetCharABCWidths(hdc, glyph, glyph, &abc)) {
- width = qAbs(abc.abcA) + abc.abcB + qAbs(abc.abcC);
- advance = abc.abcA + abc.abcB + abc.abcC;
- }
- else
-#endif
-#if defined(GWES_MGRAST) || defined(GWES_MGRAST2) // raster fonts
- if (GetCharWidth32(hdc, glyph, glyph, &width)) {
- advance = width;
- }
- else
-#endif
- { // fallback
- width = tm.tmMaxCharWidth;
- advance = width;
- }
-
- SelectObject(hdc, oldFont);
- return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, advance, 0).transformed(t);
-#endif
}
QFixed QWindowsFontEngine::ascent() const
@@ -636,22 +589,16 @@ void QWindowsFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qre
HDC hdc = m_fontEngineData->hdc;
SelectObject(hdc, hfont);
-#ifndef Q_OS_WINCE
- if (ttf)
-#endif
- {
+ if (ttf) {
ABC abcWidths;
GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
if (leftBearing)
*leftBearing = abcWidths.abcA;
if (rightBearing)
*rightBearing = abcWidths.abcC;
- }
-#ifndef Q_OS_WINCE
- else {
+ } else {
QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
}
-#endif
}
#endif // Q_CC_MINGW
@@ -670,7 +617,6 @@ qreal QWindowsFontEngine::minLeftBearing() const
qreal QWindowsFontEngine::minRightBearing() const
{
-#ifndef Q_OS_WINCE
if (rbearing == SHRT_MIN) {
int ml = 0;
int mr = 0;
@@ -726,40 +672,6 @@ qreal QWindowsFontEngine::minRightBearing() const
}
return rbearing;
-#else // !Q_OS_WINCE
- if (rbearing == SHRT_MIN) {
- int ml = 0;
- int mr = 0;
- HDC hdc = m_fontEngineData->hdc;
- SelectObject(hdc, hfont);
- if (ttf) {
- ABC *abc = 0;
- int n = tm.tmLastChar - tm.tmFirstChar;
- if (n <= max_font_count) {
- abc = new ABC[n+1];
- GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
- } else {
- abc = new ABC[char_table_entries+1];
- for (int i = 0; i < char_table_entries; i++)
- GetCharABCWidths(hdc, char_table[i], char_table[i], abc+i);
- n = char_table_entries;
- }
- ml = abc[0].abcA;
- mr = abc[0].abcC;
- for (int i = 1; i < n; i++) {
- if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
- ml = qMin(ml,abc[i].abcA);
- mr = qMin(mr,abc[i].abcC);
- }
- }
- delete [] abc;
- }
- lbearing = ml;
- rbearing = mr;
- }
-
- return rbearing;
-#endif // Q_OS_WINCE
}
static inline double qt_fixed_to_double(const FIXED &p) {
@@ -786,7 +698,6 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
GLYPHMETRICS gMetric;
memset(&gMetric, 0, sizeof(GLYPHMETRICS));
-#ifndef Q_OS_WINCE
if (metric) {
// If metrics requested, retrieve first using GGO_METRICS, because the returned
// values are incorrect for OpenType PS fonts if obtained at the same time as the
@@ -801,7 +712,6 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
int(gMetric.gmBlackBoxX), int(gMetric.gmBlackBoxY),
gMetric.gmCellIncX, gMetric.gmCellIncY);
}
-#endif
uint glyphFormat = GGO_NATIVE;
@@ -820,15 +730,6 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
return false;
}
-#ifdef Q_OS_WINCE
- if (metric) {
- // #### obey scale
- *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
- (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY,
- gMetric.gmCellIncX, gMetric.gmCellIncY);
- }
-#endif
-
DWORD offset = 0;
DWORD headerOffset = 0;
@@ -1052,7 +953,6 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph,
bool has_transformation = t.type() > QTransform::TxTranslate;
-#ifndef Q_OS_WINCE
unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
XFORM xform;
@@ -1095,13 +995,6 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph,
xform.eDx -= tgm.gmptGlyphOrigin.x;
xform.eDy += tgm.gmptGlyphOrigin.y;
}
-#else // else wince
- unsigned int options = 0;
- if (has_transformation) {
- qWarning() << "QWindowsFontEngine is unable to apply transformations other than translations for fonts on Windows CE."
- << "If you need them anyway, start your application with -platform windows:fontengine=freetype.";
- }
-#endif // wince
// The padding here needs to be kept in sync with the values in alphaMapBoundingBox.
QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin,
@@ -1123,14 +1016,11 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph,
HGDIOBJ old_font = SelectObject(hdc, font);
-#ifndef Q_OS_WINCE
if (has_transformation) {
SetGraphicsMode(hdc, GM_ADVANCED);
SetWorldTransform(hdc, &xform);
ExtTextOut(hdc, 0, 0, options, 0, reinterpret_cast<LPCWSTR>(&glyph), 1, 0);
- } else
-#endif // !Q_OS_WINCE
- {
+ } else {
ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, reinterpret_cast<LPCWSTR>(&glyph), 1, 0);
}
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h
index d4d98422a1..921351a4b0 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.h
+++ b/src/plugins/platforms/windows/qwindowsfontengine.h
@@ -57,7 +57,7 @@
#include <QtCore/QSharedPointer>
#include <QtCore/QMetaType>
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp
index 0a2d30319e..c1eb664324 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp
@@ -149,15 +149,9 @@ QT_BEGIN_NAMESPACE
QWindowsOpengl32DLL QOpenGLStaticContext::opengl32;
-PROC QWindowsOpengl32DLL::resolve(const char *name)
+FARPROC QWindowsOpengl32DLL::resolve(const char *name)
{
-#ifndef Q_OS_WINCE
- PROC proc = m_lib ? ::GetProcAddress(m_lib, name) : 0;
-#else
- PROC proc = m_lib ? ::GetProcAddress(m_lib, (const wchar_t *) QString::fromLatin1(name).utf16()) : 0;
-#endif
-
- return proc;
+ return m_lib ? ::GetProcAddress(m_lib, name) : nullptr;
}
bool QWindowsOpengl32DLL::init(bool softwareRendering)
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h
index 2944ab7192..4c804a612e 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.h
+++ b/src/plugins/platforms/windows/qwindowsglcontext.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSGLCONTEXT_H
#define QWINDOWSGLCONTEXT_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include "qwindowsopenglcontext.h"
#include <QtGui/QOpenGLContext>
@@ -122,7 +122,7 @@ struct QWindowsOpengl32DLL
void (APIENTRY * glGetIntegerv)(GLenum pname, GLint* params);
const GLubyte * (APIENTRY * glGetString)(GLenum name);
- PROC resolve(const char *name);
+ FARPROC resolve(const char *name);
private:
HMODULE m_lib;
bool m_nonOpengl32;
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index 501b956a68..8adbd494c4 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -190,11 +190,7 @@ bool QWindowsInputContext::hasCapability(Capability capability) const
{
switch (capability) {
case QPlatformInputContext::HiddenTextCapability:
-#ifndef Q_OS_WINCE
return false; // QTBUG-40691, do not show IME on desktop for password entry fields.
-#else
- break; // Windows CE: Show software keyboard.
-#endif
default:
break;
}
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h
index 4c08fa0ef2..a7fa2c4f94 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.h
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSINPUTCONTEXT_H
#define QWINDOWSINPUTCONTEXT_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtCore/QLocale>
#include <QtCore/QPointer>
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 6142aac92e..5b8cc7893a 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -64,7 +64,7 @@
#include <qpa/qplatformnativeinterface.h>
#include <qpa/qwindowsysteminterface.h>
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#ifndef QT_NO_SESSIONMANAGER
# include "qwindowssessionmanager.h"
#endif
#include <QtGui/qtouchdevice.h>
@@ -102,7 +102,7 @@ QT_BEGIN_NAMESPACE
It should compile with:
\list
- \li Microsoft Visual Studio 2008 or later (using the Microsoft Windows SDK,
+ \li Microsoft Visual Studio 2013 or later (using the Microsoft Windows SDK,
(\c Q_CC_MSVC).
\li Stock \l{http://mingw.org/}{MinGW} (\c Q_CC_MINGW).
This version ships with headers that are missing a lot of WinAPI.
@@ -112,15 +112,8 @@ QT_BEGIN_NAMESPACE
(\c Q_CC_MINGW and \c __MINGW64_VERSION_MAJOR indicating the version).
MinGW-w64 provides more complete headers (compared to stock MinGW from mingw.org),
including a considerable part of the Windows SDK.
- \li Visual Studio 2008 for Windows Embedded (\c Q_OS_WINCE).
\endlist
- The file \c qtwindows_additional.h contains defines and declarations that
- are missing in MinGW. When encountering missing declarations, it should
- be added there so that \c #ifdefs for MinGW can be avoided. Similarly,
- \c qplatformfunctions_wince.h contains defines and declarations for
- Windows Embedded.
-
When using a function from the WinAPI, the minimum supported Windows version
and Windows Embedded support should be checked. If the function is not supported
on Windows XP or is not present in the MinGW-headers, it should be dynamically
@@ -215,9 +208,7 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramL
: m_options(0)
, m_fontDatabase(0)
{
-#ifndef Q_OS_WINCE
Q_INIT_RESOURCE(openglblacklists);
-#endif
static bool dpiAwarenessSet = false;
int tabletAbsoluteRange = -1;
@@ -474,46 +465,16 @@ QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext()
}
#endif // !QT_NO_OPENGL
-/* Workaround for QTBUG-24205: In 'Auto', pick the FreeType engine for
- * QML2 applications. */
-
-#ifdef Q_OS_WINCE
-// It's not easy to detect if we are running a QML application
-// Let's try to do so by checking if the Qt Quick module is loaded.
-inline bool isQMLApplication()
-{
- // check if the Qt Quick module is loaded
-#ifdef _DEBUG
- HMODULE handle = GetModuleHandle(L"Qt5Quick" QT_LIBINFIX L"d.dll");
-#else
- HMODULE handle = GetModuleHandle(L"Qt5Quick" QT_LIBINFIX L".dll");
-#endif
- return (handle != NULL);
-}
-#endif
-
QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
{
if (!d->m_fontDatabase) {
#ifdef QT_NO_FREETYPE
d->m_fontDatabase = new QWindowsFontDatabase();
#else // QT_NO_FREETYPE
- if (d->m_options & QWindowsIntegration::FontDatabaseFreeType) {
+ if (d->m_options & QWindowsIntegration::FontDatabaseFreeType)
d->m_fontDatabase = new QWindowsFontDatabaseFT;
- } else if (d->m_options & QWindowsIntegration::FontDatabaseNative){
- d->m_fontDatabase = new QWindowsFontDatabase;
- } else {
-#ifndef Q_OS_WINCE
+ else
d->m_fontDatabase = new QWindowsFontDatabase;
-#else
- if (isQMLApplication()) {
- qCDebug(lcQpaFonts) << "QML application detected, using FreeType rendering";
- d->m_fontDatabase = new QWindowsFontDatabaseFT;
- }
- else
- d->m_fontDatabase = new QWindowsFontDatabase;
-#endif
- }
#endif // QT_NO_FREETYPE
}
return d->m_fontDatabase;
@@ -601,7 +562,7 @@ unsigned QWindowsIntegration::options() const
return d->m_options;
}
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
QPlatformSessionManager *QWindowsIntegration::createPlatformSessionManager(const QString &id, const QString &key) const
{
return new QWindowsSessionManager(id, key);
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index 9658ef711d..437253cedc 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -104,7 +104,7 @@ public:
void beep() const Q_DECL_OVERRIDE;
-#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
+#if !defined(QT_NO_SESSIONMANAGER)
QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const Q_DECL_OVERRIDE;
#endif
diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp b/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp
index 2dfe7fc5f9..21ebee6262 100644
--- a/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp
+++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp
@@ -39,7 +39,6 @@
#include "qwindowsinternalmimedata.h"
#include "qwindowscontext.h"
-#include "qplatformfunctions_wince.h"
#include "qwindowsmime.h"
#include <QDebug>
/*!
diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.h b/src/plugins/platforms/windows/qwindowsinternalmimedata.h
index 4ac7a303af..4d775b1f21 100644
--- a/src/plugins/platforms/windows/qwindowsinternalmimedata.h
+++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSINTERNALMIME_H
#define QWINDOWSINTERNALMIME_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtGui/private/qdnd_p.h> // QInternalMime
#include <QtCore/QVariant>
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index 5b2370b69d..8d6e83298e 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -552,34 +552,6 @@ inline quint32 winceKeyBend(quint32 keyCode)
return KeyTbl[keyCode];
}
-#ifdef Q_OS_WINCE
-QT_BEGIN_INCLUDE_NAMESPACE
-int ToUnicode(UINT vk, int /*scancode*/, unsigned char* /*kbdBuffer*/, LPWSTR unicodeBuffer, int, int)
-{
- QT_USE_NAMESPACE
- QChar* buf = reinterpret_cast< QChar*>(unicodeBuffer);
- if (KeyTbl[vk] == 0) {
- buf[0] = vk;
- return 1;
- }
- return 0;
-}
-
-int ToAscii(UINT vk, int scancode, unsigned char *kbdBuffer, LPWORD unicodeBuffer, int flag)
-{
- return ToUnicode(vk, scancode, kbdBuffer, (LPWSTR) unicodeBuffer, 0, flag);
-
-}
-
-bool GetKeyboardState(unsigned char* kbuffer)
-{
- for (int i=0; i< 256; ++i)
- kbuffer[i] = GetAsyncKeyState(i);
- return true;
-}
-QT_END_INCLUDE_NAMESPACE
-#endif // Q_OS_WINCE
-
// Translate a VK into a Qt key code, or unicode character
static inline quint32 toKeyOrUnicode(quint32 vk, quint32 scancode, unsigned char *kbdBuffer, bool *isDeadkey = 0)
{
@@ -780,7 +752,6 @@ static void showSystemMenu(QWindow* w)
if (!menu)
return; // no menu for this window
-#ifndef Q_OS_WINCE
#define enabled (MF_BYCOMMAND | MF_ENABLED)
#define disabled (MF_BYCOMMAND | MF_GRAYED)
@@ -805,7 +776,6 @@ static void showSystemMenu(QWindow* w)
#undef enabled
#undef disabled
-#endif // !Q_OS_WINCE
const QPoint pos = QHighDpi::toNativePixels(topLevel->geometry().topLeft(), topLevel);
const int ret = TrackPopupMenuEx(menu,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD,
@@ -1172,7 +1142,6 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
modifiers, scancode, quint32(msg.wParam), nModifiers, text, false);
result =true;
bool store = true;
-#ifndef Q_OS_WINCE
// Alt+<alphanumerical> go to the Win32 menu system if unhandled by Qt
if (msgType == WM_SYSKEYDOWN && !result && a) {
HWND parent = GetParent(QWindowsWindow::handleOf(receiver));
@@ -1186,7 +1155,6 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
parent = GetParent(parent);
}
}
-#endif // !Q_OS_WINCE
if (!store)
key_recorder.findKey(int(msg.wParam), true);
}
@@ -1216,7 +1184,6 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
nModifiers,
(rec ? rec->text : QString()), false);
result = true;
-#ifndef Q_OS_WINCE
// don't pass Alt to Windows unless we are embedded in a non-Qt window
if (code == Qt::Key_Alt) {
const QWindowsContext *context = QWindowsContext::instance();
@@ -1229,7 +1196,6 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
parent = GetParent(parent);
}
}
-#endif
}
}
return result;
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h
index e21c913156..069f78197e 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.h
+++ b/src/plugins/platforms/windows/qwindowskeymapper.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSKEYMAPPER_H
#define QWINDOWSKEYMAPPER_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtCore/QLocale>
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index cb112446fc..d6375693d8 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -403,11 +403,9 @@ QDebug operator<<(QDebug d, const FORMATETC &tc)
case CF_UNICODETEXT:
d << "CF_UNICODETEXT";
break;
-#ifndef Q_OS_WINCE
case CF_ENHMETAFILE:
d << "CF_ENHMETAFILE";
break;
-#endif // !Q_OS_WINCE
default:
d << QWindowsMimeConverter::clipboardFormatName(tc.cfFormat);
break;
diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h
index b727f13747..4c0cbf9f31 100644
--- a/src/plugins/platforms/windows/qwindowsmime.h
+++ b/src/plugins/platforms/windows/qwindowsmime.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSMIME_H
#define QWINDOWSMIME_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtCore/QVector>
#include <QtCore/QList>
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index 78fff65d84..45fbb4fdd3 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -56,6 +56,37 @@
#include <windowsx.h>
+/* Touch is supported from Windows 7 onwards and data structures
+ * are present in the Windows SDK's, but not in older MSVC Express
+ * versions. */
+
+#if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE)
+
+typedef struct tagTOUCHINPUT {
+ LONG x;
+ LONG y;
+ HANDLE hSource;
+ DWORD dwID;
+ DWORD dwFlags;
+ DWORD dwMask;
+ DWORD dwTime;
+ ULONG_PTR dwExtraInfo;
+ DWORD cxContact;
+ DWORD cyContact;
+} TOUCHINPUT, *PTOUCHINPUT;
+typedef TOUCHINPUT const * PCTOUCHINPUT;
+
+# define TOUCHEVENTF_MOVE 0x0001
+# define TOUCHEVENTF_DOWN 0x0002
+# define TOUCHEVENTF_UP 0x0004
+# define TOUCHEVENTF_INRANGE 0x0008
+# define TOUCHEVENTF_PRIMARY 0x0010
+# define TOUCHEVENTF_NOCOALESCE 0x0020
+# define TOUCHEVENTF_PALM 0x0080
+# define TOUCHINPUTMASKF_CONTACTAREA 0x0004
+# define TOUCHINPUTMASKF_EXTRAINFO 0x0002
+#endif // if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE)
+
QT_BEGIN_NAMESPACE
static inline void compressMouseMove(MSG *msg)
@@ -203,7 +234,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
-#ifndef Q_OS_WINCE
// Check for events synthesized from touch. Lower byte is touch index, 0 means pen.
static const bool passSynthesizedMouseEvents =
!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch);
@@ -218,7 +248,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
return false;
}
}
-#endif // !Q_OS_WINCE
const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
if (et & QtWindows::NonClientEventFlag) {
@@ -320,7 +349,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
const bool hasCapture = platformWindow->hasMouseCapture();
const bool currentNotCapturing = hasCapture && currentWindowUnderMouse != window;
-#ifndef Q_OS_WINCE
// Enter new window: track to generate leave event.
// If there is an active capture, only track if the current window is capturing,
// so we don't get extra leave when cursor leaves the application.
@@ -334,7 +362,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
qWarning("TrackMouseEvent failed.");
m_trackedWindow = window;
}
-#endif // !Q_OS_WINCE
// No enter or leave events are sent as long as there is an autocapturing window.
if (!hasCapture || !platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)) {
@@ -487,7 +514,6 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
QtWindows::WindowsEventType,
MSG msg, LRESULT *)
{
-#ifndef Q_OS_WINCE
typedef QWindowSystemInterface::TouchPoint QTouchPoint;
typedef QList<QWindowSystemInterface::TouchPoint> QTouchPointList;
@@ -563,109 +589,17 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
QWindowSystemInterface::handleTouchEvent(window,
m_touchDevice,
touchPoints);
-#else // !Q_OS_WINCE
- Q_UNUSED(window)
- Q_UNUSED(msg)
-#endif
return true;
-
}
bool QWindowsMouseHandler::translateGestureEvent(QWindow *window, HWND hwnd,
QtWindows::WindowsEventType,
MSG msg, LRESULT *)
{
-#ifndef Q_OS_WINCE
Q_UNUSED(window)
Q_UNUSED(hwnd)
Q_UNUSED(msg)
return false;
-#else // !Q_OS_WINCE
- GESTUREINFO gi;
- memset(&gi, 0, sizeof(GESTUREINFO));
- gi.cbSize = sizeof(GESTUREINFO);
-
- if (!GetGestureInfo((HGESTUREINFO)msg.lParam, &gi))
- return false;
-
- const QPoint position = QPoint(gi.ptsLocation.x, gi.ptsLocation.y);
-
- if (gi.dwID != GID_DIRECTMANIPULATION)
- return true;
- static QPoint lastTouchPos;
- const QScreen *screen = window->screen();
- if (!screen)
- screen = QGuiApplication::primaryScreen();
- if (!screen)
- return true;
- const QRect screenGeometry = screen->geometry();
- QWindowSystemInterface::TouchPoint touchPoint;
- static QWindowSystemInterface::TouchPoint touchPoint2;
- touchPoint.id = 0;//gi.dwInstanceID;
- touchPoint.pressure = 1.0;
-
- if (gi.dwFlags & GF_BEGIN)
- touchPoint.state = Qt::TouchPointPressed;
- else if (gi.dwFlags & GF_END)
- touchPoint.state = Qt::TouchPointReleased;
- else if (gi.dwFlags == 0)
- touchPoint.state = Qt::TouchPointMoved;
- else
- return true;
- touchPoint2.pressure = 1.0;
- touchPoint2.id = 1;
- const QPoint winEventPosition = position;
- const int deltaX = GID_DIRECTMANIPULATION_DELTA_X(gi.ullArguments);
- const int deltaY = GID_DIRECTMANIPULATION_DELTA_Y(gi.ullArguments);
- //Touch points are taken from the whole screen so map the position to the screen
- const QPoint globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
- const QPoint globalPosition2 = QWindowsGeometryHint::mapToGlobal(hwnd, QPoint(position.x() + deltaX, position.y() + deltaY));
-
- touchPoint.normalPosition =
- QPointF( (qreal)globalPosition.x() / screenGeometry.width(), (qreal)globalPosition.y() / screenGeometry.height() );
-
- touchPoint.area.moveCenter(globalPosition);
-
- QList<QWindowSystemInterface::TouchPoint> pointList;
- pointList.append(touchPoint);
- if (deltaX != 0 && deltaY != 0) {
- touchPoint2.state = m_had2ndTouchPoint ? Qt::TouchPointMoved : Qt::TouchPointPressed;
- m_had2ndTouchPoint = true;
- touchPoint2.normalPosition =
- QPointF( (qreal)globalPosition2.x() / screenGeometry.width(), (qreal)globalPosition2.y() / screenGeometry.height() );
-
- touchPoint2.area.moveCenter(globalPosition2);
- lastTouchPos = globalPosition2;
- pointList.append(touchPoint2);
- } else if (m_had2ndTouchPoint) {
- touchPoint2.normalPosition =
- QPointF( (qreal)lastTouchPos.x() / screenGeometry.width(), (qreal)lastTouchPos.y() / screenGeometry.height() );
-
- touchPoint2.area.moveCenter(lastTouchPos);
- touchPoint2.state = Qt::TouchPointReleased;
- pointList.append(touchPoint2);
- m_had2ndTouchPoint = false;
- }
-
- if (!m_touchDevice) {
- m_touchDevice = new QTouchDevice;
- // TODO: Device used to be hardcoded to screen in previous code.
- m_touchDevice->setType(QTouchDevice::TouchScreen);
- m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition);
- QWindowSystemInterface::registerTouchDevice(m_touchDevice);
- }
-
- QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, pointList);
- // handle window focusing in/out
- if (window != m_windowUnderMouse) {
- if (m_windowUnderMouse)
- QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse);
- if (window)
- QWindowSystemInterface::handleEnterEvent(window);
- m_windowUnderMouse = window;
- }
- return true;
-#endif // Q_OS_WINCE
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h
index d16c9f9e02..bd36d9f44c 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.h
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.h
@@ -41,7 +41,7 @@
#define QWINDOWSMOUSEHANDLER_H
#include "qtwindowsglobal.h"
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtCore/QPointer>
#include <QtCore/QHash>
@@ -91,10 +91,6 @@ private:
QTouchDevice *m_touchDevice;
bool m_leftButtonDown;
QWindow *m_previousCaptureWindow;
-#ifdef Q_OS_WINCE
-//This is required to send a touch up if we don't get a second touch position any more
- bool m_had2ndTouchPoint;
-#endif
};
Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(int wParam)
diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.cpp b/src/plugins/platforms/windows/qwindowsnativeimage.cpp
index bc8bfda32b..ec9683ea8d 100644
--- a/src/plugins/platforms/windows/qwindowsnativeimage.cpp
+++ b/src/plugins/platforms/windows/qwindowsnativeimage.cpp
@@ -126,9 +126,7 @@ QWindowsNativeImage::QWindowsNativeImage(int width, int height,
m_image = QImage(width, height, format);
}
-#ifndef Q_OS_WINCE
GdiFlush();
-#endif
}
QWindowsNativeImage::~QWindowsNativeImage()
diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.h b/src/plugins/platforms/windows/qwindowsnativeimage.h
index c96ca7937a..bfe0f07dfd 100644
--- a/src/plugins/platforms/windows/qwindowsnativeimage.h
+++ b/src/plugins/platforms/windows/qwindowsnativeimage.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSNATIVEIMAGE_H
#define QWINDOWSNATIVEIMAGE_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtGui/QImage>
diff --git a/src/plugins/platforms/windows/qwindowsole.h b/src/plugins/platforms/windows/qwindowsole.h
index 009111e55c..dc31c793e9 100644
--- a/src/plugins/platforms/windows/qwindowsole.h
+++ b/src/plugins/platforms/windows/qwindowsole.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSOLE_H
#define QWINDOWSOLE_H
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtCore/QMap>
#include <QtCore/QPointer>
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp
index 4ca7f0e413..d5d50a69cd 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.cpp
+++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp
@@ -54,17 +54,14 @@
#include <private/qopengl_p.h>
#endif
-#ifndef Q_OS_WINCE
-# include <QtCore/qt_windows.h>
-# include <private/qsystemlibrary_p.h>
-# include <d3d9.h>
-#endif
+#include <QtCore/qt_windows.h>
+#include <private/qsystemlibrary_p.h>
+#include <d3d9.h>
QT_BEGIN_NAMESPACE
GpuDescription GpuDescription::detect()
{
-#ifndef Q_OS_WINCE
typedef IDirect3D9 * (WINAPI *PtrDirect3DCreate9)(UINT);
GpuDescription result;
@@ -95,13 +92,6 @@ GpuDescription GpuDescription::detect()
result.description = adapterIdentifier.Description;
}
return result;
-#else // !Q_OS_WINCE
- GpuDescription result;
- result.vendorId = result.deviceId = result.revision =1;
- result.driverVersion = QVersionNumber(1, 1, 1);
- result.driverName = result.description = QByteArrayLiteral("Generic");
- return result;
-#endif
}
#ifndef QT_NO_DEBUG_STREAM
@@ -155,7 +145,6 @@ QVariant GpuDescription::toVariant() const
QWindowsOpenGLTester::Renderer QWindowsOpenGLTester::requestedGlesRenderer()
{
-#ifndef Q_OS_WINCE
const char platformVar[] = "QT_ANGLE_PLATFORM";
if (qEnvironmentVariableIsSet(platformVar)) {
const QByteArray anglePlatform = qgetenv(platformVar);
@@ -167,13 +156,11 @@ QWindowsOpenGLTester::Renderer QWindowsOpenGLTester::requestedGlesRenderer()
return QWindowsOpenGLTester::AngleRendererD3d11Warp;
qCWarning(lcQpaGl) << "Invalid value set for " << platformVar << ": " << anglePlatform;
}
-#endif // !Q_OS_WINCE
return QWindowsOpenGLTester::InvalidRenderer;
}
QWindowsOpenGLTester::Renderer QWindowsOpenGLTester::requestedRenderer()
{
-#ifndef Q_OS_WINCE
const char openGlVar[] = "QT_OPENGL";
if (QCoreApplication::testAttribute(Qt::AA_UseOpenGLES)) {
const Renderer glesRenderer = QWindowsOpenGLTester::requestedGlesRenderer();
@@ -195,12 +182,9 @@ QWindowsOpenGLTester::Renderer QWindowsOpenGLTester::requestedRenderer()
return QWindowsOpenGLTester::SoftwareRasterizer;
qCWarning(lcQpaGl) << "Invalid value set for " << openGlVar << ": " << requested;
}
-#endif // !Q_OS_WINCE
return QWindowsOpenGLTester::InvalidRenderer;
}
-#ifndef Q_OS_WINCE
-
static inline QString resolveBugListFile(const QString &fileName)
{
if (QFileInfo(fileName).isAbsolute())
@@ -216,12 +200,10 @@ static inline QString resolveBugListFile(const QString &fileName)
return QStandardPaths::locate(QStandardPaths::ConfigLocation, fileName);
}
-# ifndef QT_NO_OPENGL
+#ifndef QT_NO_OPENGL
typedef QHash<QOpenGLConfig::Gpu, QWindowsOpenGLTester::Renderers> SupportedRenderersCache;
Q_GLOBAL_STATIC(SupportedRenderersCache, supportedRenderersCache)
-# endif
-
-#endif // !Q_OS_WINCE
+#endif
QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(const GpuDescription &gpu, bool glesOnly)
{
@@ -229,8 +211,6 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c
Q_UNUSED(glesOnly)
#if defined(QT_NO_OPENGL)
return 0;
-#elif defined(Q_OS_WINCE)
- return QWindowsOpenGLTester::Gles;
#else
QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.vendorId, gpu.deviceId, gpu.driverVersion, gpu.description);
SupportedRenderersCache *srCache = supportedRenderersCache();
@@ -280,7 +260,7 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c
}
srCache->insert(qgpu, result);
return result;
-#endif // !Q_OS_WINCE && !QT_NO_OPENGL
+#endif // !QT_NO_OPENGL
}
QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedGlesRenderers()
@@ -301,7 +281,7 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedRenderers()
bool QWindowsOpenGLTester::testDesktopGL()
{
-#if !defined(QT_NO_OPENGL) && !defined(Q_OS_WINCE)
+#if !defined(QT_NO_OPENGL)
HMODULE lib = 0;
HWND wnd = 0;
HDC dc = 0;
@@ -428,7 +408,7 @@ cleanup:
return result;
#else
return false;
-#endif // !QT_NO_OPENGL && !Q_OS_WINCE
+#endif // !QT_NO_OPENGL
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index b476c9be1d..23d43a95a5 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -43,7 +43,7 @@
#include "qwindowsintegration.h"
#include "qwindowscursor.h"
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtCore/QSettings>
#include <QtGui/QPixmap>
@@ -68,8 +68,6 @@ static inline QDpi deviceDPI(HDC hdc)
return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
}
-#ifndef Q_OS_WINCE
-
static inline QDpi monitorDPI(HMONITOR hMonitor)
{
if (QWindowsContext::shcoredll.isValid()) {
@@ -81,8 +79,6 @@ static inline QDpi monitorDPI(HMONITOR hMonitor)
return QDpi(0, 0);
}
-#endif // !Q_OS_WINCE
-
typedef QList<QWindowsScreenData> WindowsScreenDataList;
static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
@@ -99,20 +95,9 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
if (data->name == QLatin1String("WinDisc")) {
data->flags |= QWindowsScreenData::LockScreen;
} else {
-#ifdef Q_OS_WINCE
- //Windows CE, just supports one Display and expects to get only DISPLAY,
- //instead of DISPLAY0 and so on, which are passed by info.szDevice
- HDC hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
-#else
- HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL);
-#endif
- if (hdc) {
-#ifndef Q_OS_WINCE
+ if (const HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL)) {
const QDpi dpi = monitorDPI(hMonitor);
data->dpi = dpi.first ? dpi : deviceDPI(hdc);
-#else
- data->dpi = deviceDPI(hdc);
-#endif
data->depth = GetDeviceCaps(hdc, BITSPIXEL);
data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE));
@@ -330,7 +315,6 @@ enum OrientationPreference // matching Win32 API ORIENTATION_PREFERENCE
bool QWindowsScreen::setOrientationPreference(Qt::ScreenOrientation o)
{
bool result = false;
-#ifndef Q_OS_WINCE
if (QWindowsContext::user32dll.setDisplayAutoRotationPreferences) {
DWORD orientationPreference = 0;
switch (o) {
@@ -352,14 +336,12 @@ bool QWindowsScreen::setOrientationPreference(Qt::ScreenOrientation o)
}
result = QWindowsContext::user32dll.setDisplayAutoRotationPreferences(orientationPreference);
}
-#endif // !Q_OS_WINCE
return result;
}
Qt::ScreenOrientation QWindowsScreen::orientationPreference()
{
Qt::ScreenOrientation result = Qt::PrimaryOrientation;
-#ifndef Q_OS_WINCE
if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences) {
DWORD orientationPreference = 0;
if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences(&orientationPreference)) {
@@ -379,7 +361,6 @@ Qt::ScreenOrientation QWindowsScreen::orientationPreference()
}
}
}
-#endif // !Q_OS_WINCE
return result;
}
@@ -388,7 +369,7 @@ Qt::ScreenOrientation QWindowsScreen::orientationPreference()
*/
QPlatformScreen::SubpixelAntialiasingType QWindowsScreen::subpixelAntialiasingTypeHint() const
{
-#if defined(Q_OS_WINCE) || !defined(FT_LCD_FILTER_H) || !defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
+#if !defined(FT_LCD_FILTER_H) || !defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
return QPlatformScreen::Subpixel_None;
#else
QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint();
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index 2afc410e07..02a9dc3bc3 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -41,9 +41,6 @@
#define QWINDOWSSCREEN_H
#include "qtwindowsglobal.h"
-#ifdef Q_OS_WINCE
-# include "qplatformfunctions_wince.h"
-#endif
#include <QtCore/QList>
#include <QtCore/QVector>
diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp
index 3c99e3507e..d559273950 100644
--- a/src/plugins/platforms/windows/qwindowsservices.cpp
+++ b/src/plugins/platforms/windows/qwindowsservices.cpp
@@ -39,16 +39,14 @@
#define QT_NO_URL_CAST_FROM_STRING
#include "qwindowsservices.h"
-#include "qtwindows_additional.h"
+#include <QtCore/qt_windows.h>
#include <QtCore/QUrl>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <shlobj.h>
-#ifndef Q_OS_WINCE
-# include <intshcut.h>
-#endif
+#include <intshcut.h>
QT_BEGIN_NAMESPACE
@@ -56,7 +54,6 @@ enum { debug = 0 };
static inline bool shellExecute(const QUrl &url)
{
-#ifndef Q_OS_WINCE
const QString nativeFilePath =
url.isLocalFile() ? QDir::toNativeSeparators(url.toLocalFile()) : url.toString(QUrl::FullyEncoded);
const quintptr result =
@@ -69,10 +66,6 @@ static inline bool shellExecute(const QUrl &url)
return false;
}
return true;
-#else
- Q_UNUSED(url);
- return false;
-#endif
}
// Retrieve the commandline for the default mail client. It contains a
@@ -107,13 +100,9 @@ static inline QString mailCommand()
}
if (!command[0])
return QString();
-#ifndef Q_OS_WINCE
wchar_t expandedCommand[MAX_PATH] = {0};
return ExpandEnvironmentStrings(command, expandedCommand, MAX_PATH) ?
QString::fromWCharArray(expandedCommand) : QString::fromWCharArray(command);
-#else
- return QString();
-#endif
}
static inline bool launchMail(const QUrl &url)
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h
index 4a24d62770..2c05dcddfc 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.h
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.h
@@ -42,7 +42,7 @@
#include "qtwindowsglobal.h"
-#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE)
+#if !defined(QT_NO_TABLETEVENT)
#include <QtCore/QVector>
#include <QtCore/QPointF>
@@ -143,5 +143,5 @@ private:
QT_END_NAMESPACE
-#endif // !QT_NO_TABLETEVENT && !Q_OS_WINCE
+#endif // !QT_NO_TABLETEVENT
#endif // QWINDOWSTABLETSUPPORT_H
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 4bf424f5f6..6c6eb42d63 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -49,17 +49,12 @@
#include "qwindowsintegration.h"
#include "qt_windows.h"
#include "qwindowsfontdatabase.h"
-#ifdef Q_OS_WINCE
-# include "qplatformfunctions_wince.h"
-# include "winuser.h"
-#else
-# include <commctrl.h>
-# include <objbase.h>
-# ifndef Q_CC_MINGW
-# include <commoncontrols.h>
-# endif
-# include <shellapi.h>
+#include <commctrl.h>
+#include <objbase.h>
+#ifndef Q_CC_MINGW
+# include <commoncontrols.h>
#endif
+#include <shellapi.h>
#include <QtCore/QVariant>
#include <QtCore/QCoreApplication>
@@ -128,7 +123,6 @@ static inline QColor getSysColor(int index)
return COLORREFToQColor(GetSysColor(index));
}
-#ifndef QT_NO_WINCE_SHELLSDK
// QTBUG-48823/Windows 10: SHGetFileInfo() (as called by item views on file system
// models has been observed to trigger a WM_PAINT on the mainwindow. Suppress the
// behavior by running it in a thread.
@@ -170,7 +164,6 @@ static bool shGetFileInfoBackground(QWindowsThreadPoolRunner &r,
}
return result;
}
-#endif // !QT_NO_WINCE_SHELLSDK
// from QStyle::standardPalette
static inline QPalette standardPalette()
@@ -281,14 +274,9 @@ static inline QPalette menuPalette(const QPalette &systemPalette)
result.setColor(QPalette::Active, QPalette::ButtonText, menuTextColor);
result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
result.setColor(QPalette::Disabled, QPalette::Text, disabled);
-#ifndef Q_OS_WINCE
const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false);
result.setColor(QPalette::Disabled, QPalette::Highlight,
getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT));
-#else
- result.setColor(QPalette::Disabled, QPalette::Highlight,
- getSysColor(COLOR_HIGHLIGHT));
-#endif
result.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled);
result.setColor(QPalette::Disabled, QPalette::Button,
result.color(QPalette::Active, QPalette::Button));
@@ -314,11 +302,7 @@ static inline QPalette *menuBarPalette(const QPalette &menuPalette)
QPalette *result = 0;
if (booleanSystemParametersInfo(SPI_GETFLATMENU, false)) {
result = new QPalette(menuPalette);
-#ifndef Q_OS_WINCE
const QColor menubar(getSysColor(COLOR_MENUBAR));
-#else
- const QColor menubar(getSysColor(COLOR_MENU));
-#endif
result->setColor(QPalette::Active, QPalette::Button, menubar);
result->setColor(QPalette::Disabled, QPalette::Button, menubar);
result->setColor(QPalette::Inactive, QPalette::Button, menubar);
@@ -388,12 +372,10 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const
return QVariant(iconThemeSearchPaths());
case StyleNames:
return QVariant(styleNames());
-#ifndef Q_OS_WINCE
case TextCursorWidth:
return QVariant(int(dWordSystemParametersInfo(SPI_GETCARETWIDTH, 1u)));
case DropShadow:
return QVariant(booleanSystemParametersInfo(SPI_GETDROPSHADOW, false));
-#endif // !Q_OS_WINCE
case MaximumScrollBarDragDistance:
return QVariant(qRound(qreal(QWindowsContext::instance()->defaultDPI()) * 1.375));
case KeyboardScheme:
@@ -447,7 +429,6 @@ void QWindowsTheme::clearFonts()
void QWindowsTheme::refreshFonts()
{
-#ifndef Q_OS_WINCE // ALL THIS FUNCTIONALITY IS MISSING ON WINCE
clearFonts();
if (!QGuiApplication::desktopSettingsAware())
return;
@@ -476,7 +457,6 @@ void QWindowsTheme::refreshFonts()
m_fonts[DockWidgetTitleFont] = new QFont(titleFont);
m_fonts[ItemViewFont] = new QFont(iconTitleFont);
m_fonts[FixedFont] = new QFont(fixedFont);
-#endif // !Q_OS_WINCE
}
bool QWindowsTheme::usePlatformNativeDialog(DialogType type) const
@@ -500,12 +480,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon);
static QPixmap loadIconFromShell32(int resourceId, QSizeF size)
{
-#ifdef Q_OS_WINCE
- HMODULE hmod = LoadLibrary(L"ceshell");
-#else
- HMODULE hmod = QSystemLibrary::load(L"shell32");
-#endif
- if (hmod) {
+ if (const HMODULE hmod = QSystemLibrary::load(L"shell32")) {
HICON iconHandle =
static_cast<HICON>(LoadImage(hmod, MAKEINTRESOURCE(resourceId),
IMAGE_ICON, int(size.width()), int(size.height()), 0));
@@ -521,7 +496,7 @@ static QPixmap loadIconFromShell32(int resourceId, QSizeF size)
QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSize) const
{
int resourceId = -1;
- int stockId = SIID_INVALID;
+ SHSTOCKICONID stockId = SIID_INVALID;
UINT stockFlags = 0;
LPCTSTR iconName = 0;
switch (sp) {
@@ -584,7 +559,6 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
stockId = SIID_RECYCLER;
resourceId = 191;
break;
-#ifndef Q_OS_WINCE
case MessageBoxInformation:
stockId = SIID_INFO;
iconName = IDI_INFORMATION;
@@ -604,29 +578,22 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
case VistaShield:
stockId = SIID_SHIELD;
break;
-#endif
default:
break;
}
-#ifndef Q_OS_WINCE
if (stockId != SIID_INVALID) {
- if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA
- && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)
- && QWindowsContext::shell32dll.sHGetStockIconInfo) {
- QPixmap pixmap;
- SHSTOCKICONINFO iconInfo;
- memset(&iconInfo, 0, sizeof(iconInfo));
- iconInfo.cbSize = sizeof(iconInfo);
- stockFlags |= (pixmapSize.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON);
- if (QWindowsContext::shell32dll.sHGetStockIconInfo(stockId, SHGFI_ICON | stockFlags, &iconInfo) == S_OK) {
- pixmap = qt_pixmapFromWinHICON(iconInfo.hIcon);
- DestroyIcon(iconInfo.hIcon);
- return pixmap;
- }
+ QPixmap pixmap;
+ SHSTOCKICONINFO iconInfo;
+ memset(&iconInfo, 0, sizeof(iconInfo));
+ iconInfo.cbSize = sizeof(iconInfo);
+ stockFlags |= (pixmapSize.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON);
+ if (SHGetStockIconInfo(stockId, SHGFI_ICON | stockFlags, &iconInfo) == S_OK) {
+ pixmap = qt_pixmapFromWinHICON(iconInfo.hIcon);
+ DestroyIcon(iconInfo.hIcon);
+ return pixmap;
}
}
-#endif
if (resourceId != -1) {
QPixmap pixmap = loadIconFromShell32(resourceId, pixmapSize);
@@ -701,14 +668,8 @@ static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info)
// For MinGW:
static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}};
- if (!QWindowsContext::shell32dll.sHGetImageList)
- return result;
- if (iImageList == sHIL_JUMBO && QSysInfo::WindowsVersion < QSysInfo::WV_VISTA)
- return result;
-
IImageList *imageList = 0;
- HRESULT hr = QWindowsContext::shell32dll.sHGetImageList(iImageList, iID_IImageList,
- reinterpret_cast<void **>(&imageList));
+ HRESULT hr = SHGetImageList(iImageList, iID_IImageList, reinterpret_cast<void **>(&imageList));
if (hr != S_OK)
return result;
HICON hIcon;
@@ -764,22 +725,13 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s
SHFILEINFO info;
const unsigned int flags =
-#ifndef Q_OS_WINCE
SHGFI_ICON|iconSize|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS|SHGFI_OVERLAYINDEX;
-#else
- iconSize|SHGFI_SYSICONINDEX;
-#endif // Q_OS_WINCE
-
-#if !defined(QT_NO_WINCE_SHELLSDK)
const bool val = cacheableDirIcon && useDefaultFolderIcon
? shGetFileInfoBackground(m_threadPoolRunner, L"dummy", FILE_ATTRIBUTE_DIRECTORY,
&info, flags | SHGFI_USEFILEATTRIBUTES)
: shGetFileInfoBackground(m_threadPoolRunner, reinterpret_cast<const wchar_t *>(filePath.utf16()), 0,
&info, flags);
-#else
- const bool val = false;
-#endif // !QT_NO_WINCE_SHELLSDK
// Even if GetFileInfo returns a valid result, hIcon can be empty in some cases
if (val && info.hIcon) {
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 76a36851ce..e58058010d 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -62,6 +62,8 @@
#include <QtCore/QDebug>
+#include <dwmapi.h>
+
QT_BEGIN_NAMESPACE
enum {
@@ -147,7 +149,6 @@ QDebug operator<<(QDebug d, const POINT &p)
return d;
}
-# ifndef Q_OS_WINCE
QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p)
{
QDebugStateSaver saver(d);
@@ -178,14 +179,12 @@ QDebug operator<<(QDebug d, const WINDOWPLACEMENT &wp)
<< ", rcNormalPosition=" << wp.rcNormalPosition;
return d;
}
-# endif // !Q_OS_WINCE
#endif // !QT_NO_DEBUG_STREAM
// QTBUG-43872, for windows that do not have WS_EX_TOOLWINDOW set, WINDOWPLACEMENT
// is in workspace/available area coordinates.
static QPoint windowPlacementOffset(HWND hwnd, const QPoint &point)
{
-#ifndef Q_OS_WINCE
if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
return QPoint(0, 0);
const QWindowsScreenManager &screenManager = QWindowsContext::instance()->screenManager();
@@ -193,10 +192,6 @@ static QPoint windowPlacementOffset(HWND hwnd, const QPoint &point)
? screenManager.screens().constFirst() : screenManager.screenAtDp(point);
if (screen)
return screen->availableGeometry().topLeft() - screen->geometry().topLeft();
-#else
- Q_UNUSED(hwnd)
- Q_UNUSED(point)
-#endif
return QPoint(0, 0);
}
@@ -205,7 +200,6 @@ static QPoint windowPlacementOffset(HWND hwnd, const QPoint &point)
static inline QRect frameGeometry(HWND hwnd, bool topLevel)
{
RECT rect = { 0, 0, 0, 0 };
-#ifndef Q_OS_WINCE
if (topLevel) {
WINDOWPLACEMENT windowPlacement;
windowPlacement.length = sizeof(WINDOWPLACEMENT);
@@ -215,7 +209,6 @@ static inline QRect frameGeometry(HWND hwnd, bool topLevel)
return result.translated(windowPlacementOffset(hwnd, result.topLeft()));
}
}
-#endif // !Q_OS_WINCE
GetWindowRect(hwnd, &rect); // Screen coordinates.
const HWND parent = GetParent(hwnd);
if (parent && !topLevel) {
@@ -236,7 +229,6 @@ static QWindow::Visibility windowVisibility_sys(HWND hwnd)
{
if (!IsWindowVisible(hwnd))
return QWindow::Hidden;
-#ifndef Q_OS_WINCE
WINDOWPLACEMENT windowPlacement;
windowPlacement.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(hwnd, &windowPlacement)) {
@@ -251,7 +243,6 @@ static QWindow::Visibility windowVisibility_sys(HWND hwnd)
break;
}
}
-#endif // !Q_OS_WINCE
return QWindow::Windowed;
}
@@ -269,65 +260,27 @@ static inline bool windowIsOpenGL(const QWindow *w)
static bool applyBlurBehindWindow(HWND hwnd)
{
-#ifdef Q_OS_WINCE
- Q_UNUSED(hwnd);
- return false;
-#else
- enum { dwmBbEnable = 0x1, dwmBbBlurRegion = 0x2 };
-
- struct DwmBlurBehind {
- DWORD dwFlags;
- BOOL fEnable;
- HRGN hRgnBlur;
- BOOL fTransitionOnMaximized;
- };
-
- typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND, const DwmBlurBehind*);
- typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL *);
-
- // DWM API is available only from Windows Vista
- if (QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
- return false;
-
- static bool functionPointersResolved = false;
- static PtrDwmEnableBlurBehindWindow dwmBlurBehind = 0;
- static PtrDwmIsCompositionEnabled dwmIsCompositionEnabled = 0;
-
- if (Q_UNLIKELY(!functionPointersResolved)) {
- QSystemLibrary library(QStringLiteral("dwmapi"));
- if (library.load()) {
- dwmBlurBehind = (PtrDwmEnableBlurBehindWindow)(library.resolve("DwmEnableBlurBehindWindow"));
- dwmIsCompositionEnabled = (PtrDwmIsCompositionEnabled)(library.resolve("DwmIsCompositionEnabled"));
- }
-
- functionPointersResolved = true;
- }
-
- if (Q_UNLIKELY(!dwmBlurBehind || !dwmIsCompositionEnabled))
- return false;
-
BOOL compositionEnabled;
- if (dwmIsCompositionEnabled(&compositionEnabled) != S_OK)
+ if (DwmIsCompositionEnabled(&compositionEnabled) != S_OK)
return false;
- DwmBlurBehind blurBehind = {0, 0, 0, 0};
+ DWM_BLURBEHIND blurBehind = {0, 0, 0, 0};
if (compositionEnabled) {
- blurBehind.dwFlags = dwmBbEnable | dwmBbBlurRegion;
+ blurBehind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
blurBehind.fEnable = TRUE;
blurBehind.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
} else {
- blurBehind.dwFlags = dwmBbEnable;
+ blurBehind.dwFlags = DWM_BB_ENABLE;
blurBehind.fEnable = FALSE;
}
- const bool result = dwmBlurBehind(hwnd, &blurBehind) == S_OK;
+ const bool result = DwmEnableBlurBehindWindow(hwnd, &blurBehind) == S_OK;
if (blurBehind.hRgnBlur)
DeleteObject(blurBehind.hRgnBlur);
return result;
-#endif // Q_OS_WINCE
}
// from qwidget_win.cpp, pass flags separately in case they have been "autofixed".
@@ -346,7 +299,6 @@ static bool shouldShowMaximizeButton(const QWindow *w, Qt::WindowFlags flags)
// Qt::WindowTransparentForInput (in combination with WS_EX_TRANSPARENT).
bool QWindowsWindow::setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity)
{
-#ifndef Q_OS_WINCE // maybe needs revisiting WS_EX_LAYERED
const LONG exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
const bool needsLayered = (flags & Qt::WindowTransparentForInput)
|| (hasAlpha && (flags & Qt::FramelessWindowHint)) || opacity < 1.0;
@@ -359,36 +311,22 @@ bool QWindowsWindow::setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool has
}
}
return needsLayered;
-#else // !Q_OS_WINCE
- Q_UNUSED(hwnd);
- Q_UNUSED(flags);
- Q_UNUSED(hasAlpha);
- Q_UNUSED(opacity);
- return false;
-#endif // Q_OS_WINCE
}
static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bool openGL, qreal level)
{
-#ifdef Q_OS_WINCE // WINCE does not support that feature and microsoft explicitly warns to use those calls
- Q_UNUSED(hwnd);
- Q_UNUSED(flags);
- Q_UNUSED(hasAlpha);
- Q_UNUSED(level);
-#else
if (QWindowsWindow::setWindowLayered(hwnd, flags, hasAlpha, level)) {
const BYTE alpha = BYTE(qRound(255.0 * level));
if (hasAlpha && !openGL && (flags & Qt::FramelessWindowHint)) {
// Non-GL windows with alpha: Use blend function to update.
BLENDFUNCTION blend = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA};
- QWindowsContext::user32dll.updateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA);
+ UpdateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA);
} else {
- QWindowsContext::user32dll.setLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
+ SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
}
} else if (IsWindowVisible(hwnd)) { // Repaint when switching from layered.
InvalidateRect(hwnd, NULL, TRUE);
}
-#endif // !Q_OS_WINCE
}
static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::WindowFlags flags, qreal opacity)
@@ -604,12 +542,10 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
exStyle |= WS_EX_TOOLWINDOW;
}
-#ifndef Q_OS_WINCE
// make mouse events fall through this window
// NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window
if (flagsIn & Qt::WindowTransparentForInput)
exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
-#endif
}
}
@@ -650,10 +586,6 @@ QWindowsWindowData
context->frameX, context->frameY,
context->frameWidth, context->frameHeight,
parentHandle, NULL, appinst, NULL);
-#ifdef Q_OS_WINCE
- if (DisableGestures(result.hwnd, TGF_GID_ALL, TGF_SCOPE_WINDOW))
- EnableGestures(result.hwnd, TGF_GID_DIRECTMANIPULATION, TGF_SCOPE_WINDOW);
-#endif
qCDebug(lcQpaWindows).nospace()
<< "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
<< context->obtainedGeometry << ' ' << context->margins;
@@ -764,9 +696,7 @@ bool QWindowsGeometryHint::validSize(const QSize &s) const
QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
{
RECT rect = {0,0,0,0};
-#ifndef Q_OS_WINCE
style &= ~(WS_OVERLAPPED); // Not permitted, see docs.
-#endif
if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle))
qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__);
const QMargins result(qAbs(rect.left), qAbs(rect.top),
@@ -779,7 +709,6 @@ QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result)
{
-#ifndef Q_OS_WINCE
// NCCALCSIZE_PARAMS structure if wParam==TRUE
if (!msg.wParam || customMargins.isNull())
return false;
@@ -795,15 +724,8 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co
<< ncp->rgrc[0] << ' ' << ncp->rgrc[1] << ' ' << ncp->rgrc[2]
<< ' ' << ncp->lppos->cx << ',' << ncp->lppos->cy;
return true;
-#else
- Q_UNUSED(customMargins)
- Q_UNUSED(msg)
- Q_UNUSED(result)
- return false;
-#endif
}
-#ifndef Q_OS_WINCE
void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
{
return applyToMinMaxInfo(DWORD(GetWindowLong(hwnd, GWL_STYLE)),
@@ -835,7 +757,6 @@ void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXI
<< " frame=" << margins << ' ' << frameWidth << ',' << frameHeight
<< " out " << *mmi;
}
-#endif // !Q_OS_WINCE
bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
{
@@ -1080,9 +1001,6 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data)
m_dropTarget(0),
m_savedStyle(0),
m_format(aWindow->requestedFormat()),
-#ifdef Q_OS_WINCE
- m_previouslyHidden(false),
-#endif
m_iconSmall(0),
m_iconBig(0),
m_surface(0)
@@ -1116,10 +1034,8 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data)
QWindowsWindow::~QWindowsWindow()
{
setFlag(WithinDestroy);
-#ifndef Q_OS_WINCE
if (testFlag(TouchRegistered))
QWindowsContext::user32dll.unregisterTouchWindow(m_data.hwnd);
-#endif // !Q_OS_WINCE
destroyWindow();
destroyIcon();
}
@@ -1163,14 +1079,6 @@ void QWindowsWindow::destroyWindow()
m_surface = 0;
}
#endif
-#ifdef Q_OS_WINCE
- if ((m_windowState & Qt::WindowFullScreen) && !m_previouslyHidden) {
- HWND handle = FindWindow(L"HHTaskBar", L"");
- if (handle) {
- ShowWindow(handle, SW_SHOW);
- }
- }
-#endif // !Q_OS_WINCE
DestroyWindow(m_data.hwnd);
context->removeWindow(m_data.hwnd);
m_data.hwnd = 0;
@@ -1338,7 +1246,6 @@ QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const
return pos;
}
-#ifndef Q_OS_WINCE
static inline HWND transientParentHwnd(HWND hwnd)
{
if (GetAncestor(hwnd, GA_PARENT) == GetDesktopWindow()) {
@@ -1348,15 +1255,18 @@ static inline HWND transientParentHwnd(HWND hwnd)
}
return 0;
}
-#endif // !Q_OS_WINCE
// Update the transient parent for a toplevel window. The concept does not
// really exist on Windows, the relationship is set by passing a parent along with !WS_CHILD
// to window creation or by setting the parent using GWL_HWNDPARENT (as opposed to
// SetParent, which would make it a real child).
+
+#ifndef GWL_HWNDPARENT
+# define GWL_HWNDPARENT (-8)
+#endif
+
void QWindowsWindow::updateTransientParent() const
{
-#ifndef Q_OS_WINCE
if (window()->type() == Qt::Popup)
return; // QTBUG-34503, // a popup stays on top, no parent, see also WindowCreationData::fromWindow().
// Update transient parent.
@@ -1368,7 +1278,6 @@ void QWindowsWindow::updateTransientParent() const
newTransientParent = tw->handle();
if (newTransientParent != oldTransientParent)
SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, LONG_PTR(newTransientParent));
-#endif // !Q_OS_WINCE
}
static inline bool testShowWithoutActivating(const QWindow *window)
@@ -1486,16 +1395,12 @@ void QWindowsWindow::handleCompositionSettingsChanged()
static QRect normalFrameGeometry(HWND hwnd)
{
-#ifndef Q_OS_WINCE
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(hwnd, &wp)) {
const QRect result = qrectFromRECT(wp.rcNormalPosition);
return result.translated(windowPlacementOffset(hwnd, result.topLeft()));
}
-#else
- Q_UNUSED(hwnd)
-#endif
return QRect();
}
@@ -1615,7 +1520,6 @@ void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
<< " new frame: " << frameGeometry;
bool result = false;
-#ifndef Q_OS_WINCE
const HWND hwnd = handle();
WINDOWPLACEMENT windowPlacement;
windowPlacement.length = sizeof(WINDOWPLACEMENT);
@@ -1628,9 +1532,7 @@ void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
RECTfromQRect(frameGeometry.translated(-windowPlacementOffset(hwnd, frameGeometry.topLeft())));
windowPlacement.showCmd = windowPlacement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE;
result = SetWindowPlacement(hwnd, &windowPlacement);
- } else
-#endif // !Q_OS_WINCE
- {
+ } else {
result = MoveWindow(hwnd, frameGeometry.x(), frameGeometry.y(),
frameGeometry.width(), frameGeometry.height(), true);
}
@@ -1667,6 +1569,12 @@ void QWindowsWindow::releaseDC()
}
}
+static inline bool dwmIsCompositionEnabled()
+{
+ BOOL dWmCompositionEnabled = FALSE;
+ return SUCCEEDED(DwmIsCompositionEnabled(&dWmCompositionEnabled)) && dWmCompositionEnabled == TRUE;
+}
+
bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
WPARAM, LPARAM)
{
@@ -1680,8 +1588,7 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
BeginPaint(hwnd, &ps);
// Observed painting problems with Aero style disabled (QTBUG-7865).
- // 5.8: Consider making it dependent on !DwmIsCompositionEnabled().
- if (testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered))
+ if (Q_UNLIKELY(testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered) && !dwmIsCompositionEnabled()))
SelectClipRgn(ps.hdc, NULL);
// If the a window is obscured by another window (such as a child window)
@@ -1823,18 +1730,6 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
setFlag(FrameDirty);
if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) {
-#ifdef Q_OS_WINCE
- HWND handle = FindWindow(L"HHTaskBar", L"");
- if (handle) {
- if (newState == Qt::WindowFullScreen) {
- BOOL hidden = ShowWindow(handle, SW_HIDE);
- if (!hidden)
- m_previouslyHidden = true;
- } else if (!m_previouslyHidden){
- ShowWindow(handle, SW_SHOW);
- }
- }
-#endif
if (newState == Qt::WindowFullScreen) {
#ifndef Q_FLATTEN_EXPOSE
UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
@@ -1846,17 +1741,13 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
// Window state but emulated by changing geometry and style.
if (!m_savedStyle) {
m_savedStyle = style();
-#ifndef Q_OS_WINCE
if (oldState == Qt::WindowMinimized || oldState == Qt::WindowMaximized) {
const QRect nf = normalFrameGeometry(m_data.hwnd);
if (nf.isValid())
m_savedFrameGeometry = nf;
} else {
-#endif
m_savedFrameGeometry = frameGeometry_sys();
-#ifndef Q_OS_WINCE
}
-#endif
}
if (m_savedStyle & WS_SYSMENU)
newStyle |= WS_SYSMENU;
@@ -1969,7 +1860,6 @@ void QWindowsWindow::propagateSizeHints()
bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &margins)
{
-#ifndef Q_OS_WINCE
if (!qWindow->isTopLevel()) // Implement hasHeightForWidth().
return false;
WINDOWPOS *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam);
@@ -1989,10 +1879,6 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *
windowPos->cx = correctedFrameGeometry.width();
windowPos->cy = correctedFrameGeometry.height();
return true;
-#else // !Q_OS_WINCE
- Q_UNUSED(message)
- return false;
-#endif
}
bool QWindowsWindow::handleGeometryChanging(MSG *message) const
@@ -2050,15 +1936,13 @@ static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion)
static HRGN qRegionToWinRegion(const QRegion &region)
{
- const QVector<QRect> rects = region.rects();
- if (rects.isEmpty())
- return NULL;
- const int rectCount = rects.size();
- if (rectCount == 1)
- return createRectRegion(region.boundingRect());
- HRGN hRegion = createRectRegion(rects.front());
- for (int i = 1; i < rectCount; ++i)
- addRectToWinRegion(rects.at(i), &hRegion);
+ auto it = region.begin();
+ const auto end = region.end();
+ if (it == end)
+ return nullptr;
+ HRGN hRegion = createRectRegion(*it);
+ while (++it != end)
+ addRectToWinRegion(*it, &hRegion);
return hRegion;
}
@@ -2087,7 +1971,6 @@ void QWindowsWindow::requestActivateWindow()
// 'Active' state handling is based in focus since it needs to work for
// child windows as well.
if (m_data.hwnd) {
-#ifndef Q_OS_WINCE
const DWORD currentThread = GetCurrentThreadId();
bool attached = false;
DWORD foregroundThread = 0;
@@ -2104,13 +1987,10 @@ void QWindowsWindow::requestActivateWindow()
attached = AttachThreadInput(foregroundThread, currentThread, TRUE) == TRUE;
}
}
-#endif // !Q_OS_WINCE
SetForegroundWindow(m_data.hwnd);
SetFocus(m_data.hwnd);
-#ifndef Q_OS_WINCE
if (attached)
AttachThreadInput(foregroundThread, currentThread, FALSE);
-#endif // !Q_OS_WINCE
}
}
@@ -2192,7 +2072,6 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
}
}
-#ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
{
const QWindowsGeometryHint hint(window(), m_data.customMargins);
@@ -2263,8 +2142,6 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re
return false;
}
-#endif // !Q_OS_WINCE
-
#ifndef QT_NO_CURSOR
// Return the default cursor (Arrow) from QWindowsCursor's cache.
static inline CursorHandlePtr defaultCursor(const QWindow *w)
@@ -2331,7 +2208,6 @@ void QWindowsWindow::setCursor(const CursorHandlePtr &c)
#endif
}
-#ifndef Q_OS_WINCE
void QWindowsWindow::setAlertState(bool enabled)
{
if (isAlertState() == enabled)
@@ -2370,7 +2246,6 @@ void QWindowsWindow::stopAlertWindow()
info.uCount = 0;
FlashWindowEx(&info);
}
-#endif // !Q_OS_WINCE
bool QWindowsWindow::isEnabled() const
{
@@ -2486,7 +2361,6 @@ void QWindowsWindow::setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWind
void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes)
{
-#ifndef Q_OS_WINCE
if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)) {
ULONG touchFlags = 0;
const bool ret = QWindowsContext::user32dll.isTouchWindow(m_data.hwnd, &touchFlags);
@@ -2499,7 +2373,6 @@ void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTou
else
qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(window()->objectName()));
}
-#endif // !Q_OS_WINCE
}
void QWindowsWindow::aboutToMakeCurrent()
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index df7d2295a9..924f242e6e 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -40,10 +40,7 @@
#ifndef QWINDOWSWINDOW_H
#define QWINDOWSWINDOW_H
-#include "qtwindows_additional.h"
-#ifdef Q_OS_WINCE
-# include "qplatformfunctions_wince.h"
-#endif
+#include <QtCore/qt_windows.h>
#include "qwindowscursor.h"
#include <qpa/qplatformwindow.h>
@@ -60,10 +57,8 @@ struct QWindowsGeometryHint
explicit QWindowsGeometryHint(const QWindow *w, const QMargins &customMargins);
static QMargins frame(DWORD style, DWORD exStyle);
static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);
-#ifndef Q_OS_WINCE //MinMax maybe define struct if not available
void applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const;
void applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const;
-#endif
bool validSize(const QSize &s) const;
static inline QPoint mapToGlobal(HWND hwnd, const QPoint &);
@@ -83,10 +78,8 @@ struct QWindowCreationContext
QWindowCreationContext(const QWindow *w, const QRect &r,
const QMargins &customMargins,
DWORD style, DWORD exStyle);
-#ifndef Q_OS_WINCE //MinMax maybe define struct if not available
void applyToMinMaxInfo(MINMAXINFO *mmi) const
{ geometryHint.applyToMinMaxInfo(style, exStyle, mmi); }
-#endif
QWindowsGeometryHint geometryHint;
const QWindow *window;
@@ -293,10 +286,8 @@ public:
HDC getDC();
void releaseDC();
-#ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
void getSizeHints(MINMAXINFO *mmi) const;
bool handleNonClientHitTest(const QPoint &globalPos, LRESULT *result) const;
-#endif // !Q_OS_WINCE
#ifndef QT_NO_CURSOR
CursorHandlePtr cursor() const { return m_cursor; }
@@ -316,12 +307,10 @@ public:
void invalidateSurface() Q_DECL_OVERRIDE;
void aboutToMakeCurrent();
-#ifndef Q_OS_WINCE
void setAlertState(bool enabled) Q_DECL_OVERRIDE;
bool isAlertState() const Q_DECL_OVERRIDE { return testFlag(AlertState); }
void alertWindow(int durationMs = 0);
void stopAlertWindow();
-#endif
static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes);
void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch);
@@ -357,9 +346,6 @@ private:
unsigned m_savedStyle;
QRect m_savedFrameGeometry;
const QSurfaceFormat m_format;
-#ifdef Q_OS_WINCE
- bool m_previouslyHidden;
-#endif
HICON m_iconSmall;
HICON m_iconBig;
void *m_surface;
@@ -368,11 +354,9 @@ private:
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const RECT &r);
QDebug operator<<(QDebug d, const POINT &);
-# ifndef Q_OS_WINCE
QDebug operator<<(QDebug d, const MINMAXINFO &i);
QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p);
QDebug operator<<(QDebug d, const WINDOWPLACEMENT &);
-# endif // !Q_OS_WINCE
#endif // !QT_NO_DEBUG_STREAM
// ---------- QWindowsGeometryHint inline functions.
@@ -436,11 +420,7 @@ inline void QWindowsWindow::destroyIcon()
inline bool QWindowsWindow::isLayered() const
{
-#ifndef Q_OS_WINCE
return GetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE) & WS_EX_LAYERED;
-#else
- return false;
-#endif
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri
index 48c53592d6..1cadcd1954 100644
--- a/src/plugins/platforms/windows/windows.pri
+++ b/src/plugins/platforms/windows/windows.pri
@@ -1,14 +1,11 @@
# Note: OpenGL32 must precede Gdi32 as it overwrites some functions.
-LIBS *= -lole32
-!wince: LIBS *= -luser32 -lwinspool -limm32 -lwinmm -loleaut32
+LIBS += -lole32 -luser32 -lwinspool -limm32 -lwinmm -loleaut32
contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles2):!contains(QT_CONFIG, dynamicgl): LIBS *= -lopengl32
mingw: LIBS *= -luuid
# For the dialog helpers:
-!wince: LIBS *= -lshlwapi -lshell32
-!wince: LIBS *= -ladvapi32
-wince: DEFINES *= QT_LIBINFIX=L"\"\\\"$${QT_LIBINFIX}\\\"\""
+LIBS += -lshlwapi -lshell32 -ladvapi32
DEFINES *= QT_NO_CAST_FROM_ASCII
@@ -53,7 +50,6 @@ HEADERS += \
$$PWD/qwindowsfontdatabase.h \
$$PWD/qwindowsmousehandler.h \
$$PWD/qtwindowsglobal.h \
- $$PWD/qtwindows_additional.h \
$$PWD/qwindowsole.h \
$$PWD/qwindowsmime.h \
$$PWD/qwindowsinternalmimedata.h \
@@ -62,7 +58,6 @@ HEADERS += \
$$PWD/qwindowstheme.h \
$$PWD/qwindowsdialoghelpers.h \
$$PWD/qwindowsservices.h \
- $$PWD/qplatformfunctions_wince.h \
$$PWD/qwindowsnativeimage.h \
$$PWD/qwindowsnativeinterface.h \
$$PWD/qwindowsopengltester.h \
@@ -101,37 +96,30 @@ contains(QT_CONFIG,dynamicgl) {
}
}
-!wince:!contains( DEFINES, QT_NO_TABLETEVENT ) {
+!contains( DEFINES, QT_NO_TABLETEVENT ) {
INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/wintab
HEADERS += $$PWD/qwindowstabletsupport.h
SOURCES += $$PWD/qwindowstabletsupport.cpp
}
-!wince:!contains( DEFINES, QT_NO_SESSIONMANAGER ) {
+!contains( DEFINES, QT_NO_SESSIONMANAGER ) {
SOURCES += $$PWD/qwindowssessionmanager.cpp
HEADERS += $$PWD/qwindowssessionmanager.h
}
-!wince:!contains( DEFINES, QT_NO_IMAGEFORMAT_PNG ) {
- RESOURCES += $$PWD/cursors.qrc
-}
+!contains( DEFINES, QT_NO_IMAGEFORMAT_PNG ):RESOURCES += $$PWD/cursors.qrc
-!wince: RESOURCES += $$PWD/openglblacklists.qrc
+RESOURCES += $$PWD/openglblacklists.qrc
contains(QT_CONFIG, freetype) {
- DEFINES *= QT_NO_FONTCONFIG
- include($$QT_SOURCE_TREE/src/3rdparty/freetype_dependency.pri)
- HEADERS += \
- $$PWD/qwindowsfontdatabase_ft.h
- SOURCES += \
- $$PWD/qwindowsfontdatabase_ft.cpp
-} else:contains(QT_CONFIG, system-freetype) {
- CONFIG += qpa/basicunixfontdatabase
- include($$QT_SOURCE_TREE/src/platformsupport/fontdatabases/basic/basic.pri)
- HEADERS += \
- $$PWD/qwindowsfontdatabase_ft.h
- SOURCES += \
- $$PWD/qwindowsfontdatabase_ft.cpp
+ HEADERS += $$PWD/qwindowsfontdatabase_ft.h
+ SOURCES += $$PWD/qwindowsfontdatabase_ft.cpp
+ contains(QT_CONFIG, system-freetype) {
+ include($$QT_SOURCE_TREE/src/platformsupport/fontdatabases/basic/basic.pri)
+ } else {
+ DEFINES *= QT_NO_FONTCONFIG
+ include($$QT_SOURCE_TREE/src/3rdparty/freetype_dependency.pri)
+ }
}
contains(QT_CONFIG, accessibility):include($$PWD/accessible/accessible.pri)
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
index 2e0f723693..adafa830d5 100644
--- a/src/plugins/platforms/windows/windows.pro
+++ b/src/plugins/platforms/windows/windows.pro
@@ -4,7 +4,7 @@ QT *= core-private
QT *= gui-private
QT *= platformsupport-private
-!wince:LIBS *= -lgdi32
+LIBS += -lgdi32 -ldwmapi
include(windows.pri)
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index a999fb0aa2..130ae9be0c 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -223,14 +223,14 @@ bool QXcbShmImage::scroll(const QRegion &area, int dx, int dy)
preparePaint(area);
const QPoint delta(dx, dy);
- foreach (const QRect &rect, area.rects())
+ for (const QRect &rect : area)
qt_scrollRectInImage(*image(), rect, delta);
if (m_xcb_pixmap) {
flushPixmap(area);
ensureGC(m_xcb_pixmap);
const QRect bounds(QPoint(0, 0), size());
- foreach (const QRect &src, area.rects()) {
+ for (const QRect &src : area) {
const QRect dst = src.translated(delta).intersected(bounds);
Q_XCB_CALL(xcb_copy_area(xcb_connection(),
m_xcb_pixmap,
@@ -531,11 +531,9 @@ void QXcbBackingStore::beginPaint(const QRegion &region)
if (m_image->hasAlpha()) {
QPainter p(paintDevice());
p.setCompositionMode(QPainter::CompositionMode_Source);
- const QVector<QRect> rects = region.rects();
const QColor blank = Qt::transparent;
- for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
- p.fillRect(*it, blank);
- }
+ for (const QRect &rect : region)
+ p.fillRect(rect, blank);
}
}
@@ -555,22 +553,21 @@ void QXcbBackingStore::endPaint()
// Slow path: the paint device was m_rgbImage. Now copy with swapping red
// and blue into m_image.
- const QVector<QRect> rects = region.rects();
- if (rects.isEmpty())
+ auto it = region.begin();
+ const auto end = region.end();
+ if (it == end)
return;
QPainter p(m_image->image());
- for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
+ while (it != end) {
const QRect rect = *it;
p.drawImage(rect.topLeft(), m_rgbImage.copy(rect).rgbSwapped());
}
}
-#ifndef QT_NO_OPENGL
QImage QXcbBackingStore::toImage() const
{
return m_image && m_image->image() ? *m_image->image() : QImage();
}
-#endif
QPlatformGraphicsBuffer *QXcbBackingStore::graphicsBuffer() const
{
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h
index 5a8f385c1b..6af679d28a 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.h
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.h
@@ -63,8 +63,8 @@ public:
void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures, QOpenGLContext *context,
bool translucentBackground) Q_DECL_OVERRIDE;
- QImage toImage() const Q_DECL_OVERRIDE;
#endif
+ QImage toImage() const Q_DECL_OVERRIDE;
QPlatformGraphicsBuffer *graphicsBuffer() const Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index bc62b500e5..5d46c53b30 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1773,24 +1773,6 @@ void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *
window->handleClientMessageEvent(event);
}
-xcb_generic_event_t *QXcbConnection::checkEvent(int type)
-{
- QXcbEventArray *eventqueue = m_reader->lock();
-
- for (int i = 0; i < eventqueue->size(); ++i) {
- xcb_generic_event_t *event = eventqueue->at(i);
- if (event && event->response_type == type) {
- (*eventqueue)[i] = 0;
- m_reader->unlock();
- return event;
- }
- }
-
- m_reader->unlock();
-
- return 0;
-}
-
static const char * xcb_atomnames = {
// window-manager <-> client protocols
"WM_PROTOCOLS\0"
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 891f0fbcb5..1336b3f5d3 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -447,7 +447,6 @@ public:
QXcbWindowEventListener *windowEventListenerFromId(xcb_window_t id);
QXcbWindow *platformWindowFromId(xcb_window_t id);
- xcb_generic_event_t *checkEvent(int type);
template<typename T>
inline xcb_generic_event_t *checkEvent(T &checker);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index bf1fd2e177..c5cc2cd790 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -2807,9 +2807,8 @@ void QXcbWindow::setMask(const QRegion &region)
XCB_SHAPE_SK_BOUNDING, xcb_window(), 0, 0, XCB_NONE);
} else {
QVector<xcb_rectangle_t> rects;
- const QVector<QRect> regionRects = region.rects();
- rects.reserve(regionRects.count());
- foreach (const QRect &r, regionRects)
+ rects.reserve(region.rectCount());
+ for (const QRect &r : region)
rects.push_back(qRectToXCBRectangle(r));
xcb_shape_rectangles(connection()->xcb_connection(), XCB_SHAPE_SO_SET,
XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
index db9ea32cd8..2013f40dd0 100644
--- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro
+++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
@@ -48,10 +48,10 @@ contains(QT_CONFIG, xcb-xlib) {
DEFINES += XCB_USE_XINPUT2
SOURCES += qxcbconnection_xi2.cpp
LIBS += -lXi
- !isEmpty(QMAKE_LIBXI_VERSION_MAJOR) {
- DEFINES += LIBXI_MAJOR=$$QMAKE_LIBXI_VERSION_MAJOR \
- LIBXI_MINOR=$$QMAKE_LIBXI_VERSION_MINOR \
- LIBXI_PATCH=$$QMAKE_LIBXI_VERSION_PATCH
+ !isEmpty(QMAKE_XINPUT2_VERSION_MAJOR) {
+ DEFINES += LIBXI_MAJOR=$$QMAKE_XINPUT2_VERSION_MAJOR \
+ LIBXI_MINOR=$$QMAKE_XINPUT2_VERSION_MINOR \
+ LIBXI_PATCH=$$QMAKE_XINPUT2_VERSION_PATCH
}
}
}
@@ -81,7 +81,7 @@ CONFIG += qpa/genericunixfontdatabase
contains(QT_CONFIG, dbus-linked) {
QT += dbus
- LIBS += $$QT_LIBS_DBUS
+ LIBS += $$QMAKE_LIBS_DBUS
}
contains(QT_CONFIG, xcb-qt) {
diff --git a/src/plugins/platformthemes/gtk3/gtk3.pro b/src/plugins/platformthemes/gtk3/gtk3.pro
index cd19e73ed8..72a33efeac 100644
--- a/src/plugins/platformthemes/gtk3/gtk3.pro
+++ b/src/plugins/platformthemes/gtk3/gtk3.pro
@@ -8,14 +8,16 @@ load(qt_plugin)
QT += core-private gui-private platformsupport-private
CONFIG += X11
-QMAKE_CXXFLAGS += $$QT_CFLAGS_QGTK3
-LIBS += $$QT_LIBS_QGTK3
+QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_GTK3
+LIBS += $$QMAKE_LIBS_GTK3
HEADERS += \
qgtk3dialoghelpers.h \
+ qgtk3menu.h \
qgtk3theme.h
SOURCES += \
main.cpp \
qgtk3dialoghelpers.cpp \
+ qgtk3menu.cpp \
qgtk3theme.cpp
diff --git a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
index a21b4d8a65..eb581f5138 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
@@ -215,8 +215,10 @@ QColor QGtk3ColorDialogHelper::currentColor() const
void QGtk3ColorDialogHelper::onAccepted()
{
+ const QColor color = currentColor();
+ emit currentColorChanged(color);
emit accept();
- emit colorSelected(currentColor());
+ emit colorSelected(color);
}
void QGtk3ColorDialogHelper::onColorChanged(QGtk3ColorDialogHelper *dialog)
@@ -418,6 +420,9 @@ void QGtk3FileDialogHelper::applyOptions()
const bool confirmOverwrite = !opts->testOption(QFileDialogOptions::DontConfirmOverwrite);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(gtkDialog), confirmOverwrite);
+ const bool readOnly = opts->testOption(QFileDialogOptions::ReadOnly);
+ gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(gtkDialog), !readOnly);
+
const QStringList nameFilters = opts->nameFilters();
if (!nameFilters.isEmpty())
setNameFilters(nameFilters);
@@ -586,9 +591,10 @@ QFont QGtk3FontDialogHelper::currentFont() const
void QGtk3FontDialogHelper::onAccepted()
{
- emit currentFontChanged(currentFont());
+ const QFont font = currentFont();
+ emit currentFontChanged(font);
emit accept();
- emit fontSelected(currentFont());
+ emit fontSelected(font);
}
void QGtk3FontDialogHelper::applyOptions()
diff --git a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
new file mode 100644
index 0000000000..288978ae84
--- /dev/null
+++ b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
@@ -0,0 +1,489 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgtk3menu.h"
+
+#include <QtGui/qwindow.h>
+#include <QtGui/qpa/qplatformtheme.h>
+
+#undef signals
+#include <gtk/gtk.h>
+
+QT_BEGIN_NAMESPACE
+
+static guint qt_gdkKey(const QKeySequence &shortcut)
+{
+ if (shortcut.isEmpty())
+ return 0;
+
+ // TODO: proper mapping
+ Qt::KeyboardModifiers mods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
+ return (shortcut[0] ^ mods) & shortcut[0];
+}
+
+static GdkModifierType qt_gdkModifiers(const QKeySequence &shortcut)
+{
+ if (shortcut.isEmpty())
+ return GdkModifierType(0);
+
+ guint mods = 0;
+ int m = shortcut[0];
+ if (m & Qt::ShiftModifier)
+ mods |= GDK_SHIFT_MASK;
+ if (m & Qt::ControlModifier)
+ mods |= GDK_CONTROL_MASK;
+ if (m & Qt::AltModifier)
+ mods |= GDK_MOD1_MASK;
+ if (m & Qt::MetaModifier)
+ mods |= GDK_META_MASK;
+
+ return static_cast<GdkModifierType>(mods);
+}
+
+QGtk3MenuItem::QGtk3MenuItem()
+ : m_visible(true),
+ m_separator(false),
+ m_checkable(false),
+ m_checked(false),
+ m_enabled(true),
+ m_underline(false),
+ m_invalid(true),
+ m_tag(reinterpret_cast<quintptr>(this)),
+ m_menu(nullptr),
+ m_item(nullptr)
+{
+}
+
+QGtk3MenuItem::~QGtk3MenuItem()
+{
+}
+
+bool QGtk3MenuItem::isInvalid() const
+{
+ return m_invalid;
+}
+
+GtkWidget *QGtk3MenuItem::create()
+{
+ if (m_invalid) {
+ if (m_item) {
+ gtk_widget_destroy(m_item);
+ m_item = nullptr;
+ }
+ m_invalid = false;
+ }
+
+ if (!m_item) {
+ if (m_separator) {
+ m_item = gtk_separator_menu_item_new();
+ } else {
+ if (m_checkable) {
+ m_item = gtk_check_menu_item_new();
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(m_item), m_checked);
+ g_signal_connect(m_item, "toggled", G_CALLBACK(onToggle), this);
+ } else {
+ m_item = gtk_menu_item_new();
+ g_signal_connect(m_item, "activate", G_CALLBACK(onActivate), this);
+ }
+ gtk_menu_item_set_label(GTK_MENU_ITEM(m_item), m_text.toUtf8());
+ gtk_menu_item_set_use_underline(GTK_MENU_ITEM(m_item), m_underline);
+ if (m_menu)
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(m_item), m_menu->handle());
+ g_signal_connect(m_item, "select", G_CALLBACK(onSelect), this);
+ if (!m_shortcut.isEmpty()) {
+ GtkWidget *label = gtk_bin_get_child(GTK_BIN(m_item));
+ gtk_accel_label_set_accel(GTK_ACCEL_LABEL(label), qt_gdkKey(m_shortcut), qt_gdkModifiers(m_shortcut));
+ }
+ }
+ gtk_widget_set_sensitive(m_item, m_enabled);
+ gtk_widget_set_visible(m_item, m_visible);
+ if (GTK_IS_CHECK_MENU_ITEM(m_item))
+ g_object_set(m_item, "draw-as-radio", m_exclusive, NULL);
+ }
+
+ return m_item;
+}
+
+GtkWidget *QGtk3MenuItem::handle() const
+{
+ return m_item;
+}
+
+quintptr QGtk3MenuItem::tag() const
+{
+ return m_tag;
+}
+
+void QGtk3MenuItem::setTag(quintptr tag)
+{
+ m_tag = tag;
+}
+
+QString QGtk3MenuItem::text() const
+{
+ return m_text;
+}
+
+static QString convertMnemonics(QString text, bool *found)
+{
+ *found = false;
+
+ int i = text.length() - 1;
+ while (i >= 0) {
+ const QChar c = text.at(i);
+ if (c == QLatin1Char('&')) {
+ if (i == 0 || text.at(i - 1) != QLatin1Char('&')) {
+ // convert Qt to GTK mnemonic
+ if (i < text.length() - 1 && !text.at(i + 1).isSpace()) {
+ text.replace(i, 1, QLatin1Char('_'));
+ *found = true;
+ }
+ } else if (text.at(i - 1) == QLatin1Char('&')) {
+ // unescape ampersand
+ text.replace(--i, 2, QLatin1Char('&'));
+ }
+ } else if (c == QLatin1Char('_')) {
+ // escape GTK mnemonic
+ text.insert(i, QLatin1Char('_'));
+ }
+ --i;
+ }
+
+ return text;
+}
+
+void QGtk3MenuItem::setText(const QString &text)
+{
+ m_text = convertMnemonics(text, &m_underline);
+ if (GTK_IS_MENU_ITEM(m_item)) {
+ gtk_menu_item_set_label(GTK_MENU_ITEM(m_item), m_text.toUtf8());
+ gtk_menu_item_set_use_underline(GTK_MENU_ITEM(m_item), m_underline);
+ }
+}
+
+QGtk3Menu *QGtk3MenuItem::menu() const
+{
+ return m_menu;
+}
+
+void QGtk3MenuItem::setMenu(QPlatformMenu *menu)
+{
+ m_menu = qobject_cast<QGtk3Menu *>(menu);
+ if (GTK_IS_MENU_ITEM(m_item))
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(m_item), m_menu ? m_menu->handle() : NULL);
+}
+
+bool QGtk3MenuItem::isVisible() const
+{
+ return m_visible;
+}
+
+void QGtk3MenuItem::setVisible(bool visible)
+{
+ if (m_visible == visible)
+ return;
+
+ m_visible = visible;
+ if (GTK_IS_MENU_ITEM(m_item))
+ gtk_widget_set_visible(m_item, visible);
+}
+
+bool QGtk3MenuItem::isSeparator() const
+{
+ return m_separator;
+}
+
+void QGtk3MenuItem::setIsSeparator(bool separator)
+{
+ if (m_separator == separator)
+ return;
+
+ m_invalid = true;
+ m_separator = separator;
+}
+
+bool QGtk3MenuItem::isCheckable() const
+{
+ return m_checkable;
+}
+
+void QGtk3MenuItem::setCheckable(bool checkable)
+{
+ if (m_checkable == checkable)
+ return;
+
+ m_invalid = true;
+ m_checkable = checkable;
+}
+
+bool QGtk3MenuItem::isChecked() const
+{
+ return m_checked;
+}
+
+void QGtk3MenuItem::setChecked(bool checked)
+{
+ if (m_checked == checked)
+ return;
+
+ m_checked = checked;
+ if (GTK_IS_CHECK_MENU_ITEM(m_item))
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(m_item), checked);
+}
+
+QKeySequence QGtk3MenuItem::shortcut() const
+{
+ return m_shortcut;
+}
+
+void QGtk3MenuItem::setShortcut(const QKeySequence& shortcut)
+{
+ if (m_shortcut == shortcut)
+ return;
+
+ m_shortcut = shortcut;
+ if (GTK_IS_MENU_ITEM(m_item)) {
+ GtkWidget *label = gtk_bin_get_child(GTK_BIN(m_item));
+ gtk_accel_label_set_accel(GTK_ACCEL_LABEL(label), qt_gdkKey(m_shortcut), qt_gdkModifiers(m_shortcut));
+ }
+}
+
+bool QGtk3MenuItem::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QGtk3MenuItem::setEnabled(bool enabled)
+{
+ if (m_enabled == enabled)
+ return;
+
+ m_enabled = enabled;
+ if (m_item)
+ gtk_widget_set_sensitive(m_item, enabled);
+}
+
+bool QGtk3MenuItem::hasExclusiveGroup() const
+{
+ return m_exclusive;
+}
+
+void QGtk3MenuItem::setHasExclusiveGroup(bool exclusive)
+{
+ if (m_exclusive == exclusive)
+ return;
+
+ m_exclusive = exclusive;
+ if (GTK_IS_CHECK_MENU_ITEM(m_item))
+ g_object_set(m_item, "draw-as-radio", exclusive, NULL);
+}
+
+void QGtk3MenuItem::onSelect(GtkMenuItem *, void *data)
+{
+ QGtk3MenuItem *item = static_cast<QGtk3MenuItem *>(data);
+ if (item)
+ emit item->hovered();
+}
+
+void QGtk3MenuItem::onActivate(GtkMenuItem *, void *data)
+{
+ QGtk3MenuItem *item = static_cast<QGtk3MenuItem *>(data);
+ if (item)
+ emit item->activated();
+}
+
+void QGtk3MenuItem::onToggle(GtkCheckMenuItem *check, void *data)
+{
+ QGtk3MenuItem *item = static_cast<QGtk3MenuItem *>(data);
+ if (item) {
+ bool active = gtk_check_menu_item_get_active(check);
+ if (active != item->isChecked()) {
+ item->setChecked(active);
+ emit item->activated();
+ }
+ }
+}
+
+QGtk3Menu::QGtk3Menu()
+ : m_tag(reinterpret_cast<quintptr>(this))
+{
+ m_menu = gtk_menu_new();
+
+ g_signal_connect(m_menu, "show", G_CALLBACK(onShow), this);
+ g_signal_connect(m_menu, "hide", G_CALLBACK(onHide), this);
+}
+
+QGtk3Menu::~QGtk3Menu()
+{
+ if (GTK_IS_WIDGET(m_menu))
+ gtk_widget_destroy(m_menu);
+}
+
+GtkWidget *QGtk3Menu::handle() const
+{
+ return m_menu;
+}
+
+void QGtk3Menu::insertMenuItem(QPlatformMenuItem *item, QPlatformMenuItem *before)
+{
+ QGtk3MenuItem *gitem = static_cast<QGtk3MenuItem *>(item);
+ if (!gitem || m_items.contains(gitem))
+ return;
+
+ GtkWidget *handle = gitem->create();
+ int index = m_items.indexOf(static_cast<QGtk3MenuItem *>(before));
+ if (index < 0)
+ index = m_items.count();
+ m_items.insert(index, gitem);
+ gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu), handle, index);
+}
+
+void QGtk3Menu::removeMenuItem(QPlatformMenuItem *item)
+{
+ QGtk3MenuItem *gitem = static_cast<QGtk3MenuItem *>(item);
+ if (!gitem && !m_items.removeOne(gitem))
+ return;
+
+ GtkWidget *handle = gitem->handle();
+ if (handle)
+ gtk_container_remove(GTK_CONTAINER(m_menu), handle);
+}
+
+void QGtk3Menu::syncMenuItem(QPlatformMenuItem *item)
+{
+ QGtk3MenuItem *gitem = static_cast<QGtk3MenuItem *>(item);
+ int index = m_items.indexOf(gitem);
+ if (index == -1 || !gitem->isInvalid())
+ return;
+
+ GtkWidget *handle = gitem->create();
+ if (handle)
+ gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu), handle, index);
+}
+
+void QGtk3Menu::syncSeparatorsCollapsible(bool enable)
+{
+ Q_UNUSED(enable);
+}
+
+quintptr QGtk3Menu::tag() const
+{
+ return m_tag;
+}
+
+void QGtk3Menu::setTag(quintptr tag)
+{
+ m_tag = tag;
+}
+
+void QGtk3Menu::setEnabled(bool enabled)
+{
+ gtk_widget_set_sensitive(m_menu, enabled);
+}
+
+void QGtk3Menu::setVisible(bool visible)
+{
+ gtk_widget_set_visible(m_menu, visible);
+}
+
+static void qt_gtk_menu_position_func(GtkMenu *, gint *x, gint *y, gboolean *push_in, gpointer data)
+{
+ QGtk3Menu *menu = static_cast<QGtk3Menu *>(data);
+ QPoint targetPos = menu->targetPos();
+ *x = targetPos.x();
+ *y = targetPos.y();
+ *push_in = true;
+}
+
+QPoint QGtk3Menu::targetPos() const
+{
+ return m_targetPos;
+}
+
+void QGtk3Menu::showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item)
+{
+ int index = m_items.indexOf(static_cast<QGtk3MenuItem *>(const_cast<QPlatformMenuItem *>(item)));
+ if (index != -1)
+ gtk_menu_set_active(GTK_MENU(m_menu), index);
+
+ m_targetPos = targetRect.bottomLeft();
+ if (parentWindow)
+ m_targetPos = parentWindow->mapToGlobal(m_targetPos);
+
+ gtk_menu_popup(GTK_MENU(m_menu), NULL, NULL, qt_gtk_menu_position_func, this, 0, gtk_get_current_event_time());
+}
+
+void QGtk3Menu::dismiss()
+{
+ gtk_menu_popdown(GTK_MENU(m_menu));
+}
+
+QPlatformMenuItem *QGtk3Menu::menuItemAt(int position) const
+{
+ return m_items.value(position);
+}
+
+QPlatformMenuItem *QGtk3Menu::menuItemForTag(quintptr tag) const
+{
+ for (QGtk3MenuItem *item : m_items) {
+ if (item->tag() == tag)
+ return item;
+ }
+ return nullptr;
+}
+
+QPlatformMenuItem *QGtk3Menu::createMenuItem() const
+{
+ return new QGtk3MenuItem;
+}
+
+QPlatformMenu *QGtk3Menu::createSubMenu() const
+{
+ return new QGtk3Menu;
+}
+
+void QGtk3Menu::onShow(GtkWidget *, void *data)
+{
+ QGtk3Menu *menu = static_cast<QGtk3Menu *>(data);
+ if (menu)
+ emit menu->aboutToShow();
+}
+
+void QGtk3Menu::onHide(GtkWidget *, void *data)
+{
+ QGtk3Menu *menu = static_cast<QGtk3Menu *>(data);
+ if (menu)
+ emit menu->aboutToHide();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platformthemes/gtk3/qgtk3menu.h b/src/plugins/platformthemes/gtk3/qgtk3menu.h
new file mode 100644
index 0000000000..ad108f1218
--- /dev/null
+++ b/src/plugins/platformthemes/gtk3/qgtk3menu.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGTK3MENU_H
+#define QGTK3MENU_H
+
+#include <QtGui/qpa/qplatformmenu.h>
+
+typedef struct _GtkWidget GtkWidget;
+typedef struct _GtkMenuItem GtkMenuItem;
+typedef struct _GtkCheckMenuItem GtkCheckMenuItem;
+
+QT_BEGIN_NAMESPACE
+
+class QGtk3Menu;
+
+class QGtk3MenuItem: public QPlatformMenuItem
+{
+public:
+ QGtk3MenuItem();
+ ~QGtk3MenuItem();
+
+ bool isInvalid() const;
+
+ GtkWidget *create();
+ GtkWidget *handle() const;
+
+ quintptr tag() const;
+ void setTag(quintptr tag) override;
+
+ QString text() const;
+ void setText(const QString &text) override;
+
+ QGtk3Menu *menu() const;
+ void setMenu(QPlatformMenu *menu) override;
+
+ bool isVisible() const;
+ void setVisible(bool visible) override;
+
+ bool isSeparator() const;
+ void setIsSeparator(bool separator) override;
+
+ bool isCheckable() const;
+ void setCheckable(bool checkable) override;
+
+ bool isChecked() const;
+ void setChecked(bool checked) override;
+
+ QKeySequence shortcut() const;
+ void setShortcut(const QKeySequence &shortcut) override;
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled) override;
+
+ bool hasExclusiveGroup() const;
+ void setHasExclusiveGroup(bool exclusive) override;
+
+ void setRole(MenuRole role) override { Q_UNUSED(role); }
+ void setFont(const QFont &font) override { Q_UNUSED(font); }
+ void setIcon(const QIcon &icon) override { Q_UNUSED(icon); }
+ void setIconSize(int size) override { Q_UNUSED(size); }
+
+protected:
+ static void onSelect(GtkMenuItem *item, void *data);
+ static void onActivate(GtkMenuItem *item, void *data);
+ static void onToggle(GtkCheckMenuItem *item, void *data);
+
+private:
+ bool m_visible;
+ bool m_separator;
+ bool m_checkable;
+ bool m_checked;
+ bool m_enabled;
+ bool m_exclusive;
+ bool m_underline;
+ bool m_invalid;
+ quintptr m_tag;
+ QGtk3Menu *m_menu;
+ GtkWidget *m_item;
+ QString m_text;
+ QKeySequence m_shortcut;
+};
+
+class QGtk3Menu : public QPlatformMenu
+{
+ Q_OBJECT
+
+public:
+ QGtk3Menu();
+ ~QGtk3Menu();
+
+ GtkWidget *handle() const;
+
+ void insertMenuItem(QPlatformMenuItem *item, QPlatformMenuItem *before) override;
+ void removeMenuItem(QPlatformMenuItem *item) override;
+ void syncMenuItem(QPlatformMenuItem *item) override;
+ void syncSeparatorsCollapsible(bool enable) override;
+
+ quintptr tag() const override;
+ void setTag(quintptr tag) override;
+
+ void setEnabled(bool enabled) override;
+ void setVisible(bool visible) override;
+
+ void setIcon(const QIcon &icon) override { Q_UNUSED(icon); }
+ void setText(const QString &text) override { Q_UNUSED(text); }
+
+ QPoint targetPos() const;
+
+ void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) override;
+ void dismiss() override;
+
+ QPlatformMenuItem *menuItemAt(int position) const override;
+ QPlatformMenuItem *menuItemForTag(quintptr tag) const override;
+
+ QPlatformMenuItem *createMenuItem() const override;
+ QPlatformMenu *createSubMenu() const override;
+
+protected:
+ static void onShow(GtkWidget *menu, void *data);
+ static void onHide(GtkWidget *menu, void *data);
+
+private:
+ quintptr m_tag;
+ GtkWidget *m_menu;
+ QPoint m_targetPos;
+ QVector<QGtk3MenuItem *> m_items;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGTK3MENU_H
diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
index 65bec3dbd1..6df631bff3 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
@@ -39,6 +39,7 @@
#include "qgtk3theme.h"
#include "qgtk3dialoghelpers.h"
+#include "qgtk3menu.h"
#include <QVariant>
#undef signals
@@ -142,4 +143,14 @@ QPlatformDialogHelper *QGtk3Theme::createPlatformDialogHelper(DialogType type) c
}
}
+QPlatformMenu* QGtk3Theme::createPlatformMenu() const
+{
+ return new QGtk3Menu;
+}
+
+QPlatformMenuItem* QGtk3Theme::createPlatformMenuItem() const
+{
+ return new QGtk3MenuItem;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.h b/src/plugins/platformthemes/gtk3/qgtk3theme.h
index 8bb9adeab8..52036680c6 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3theme.h
+++ b/src/plugins/platformthemes/gtk3/qgtk3theme.h
@@ -55,6 +55,9 @@ public:
bool usePlatformNativeDialog(DialogType type) const Q_DECL_OVERRIDE;
QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const Q_DECL_OVERRIDE;
+ QPlatformMenu* createPlatformMenu() const Q_DECL_OVERRIDE;
+ QPlatformMenuItem* createPlatformMenuItem() const Q_DECL_OVERRIDE;
+
static const char *name;
};
diff --git a/src/plugins/sqldrivers/db2/db2.pro b/src/plugins/sqldrivers/db2/db2.pro
index 2365c5bc0e..31822ef8dc 100644
--- a/src/plugins/sqldrivers/db2/db2.pro
+++ b/src/plugins/sqldrivers/db2/db2.pro
@@ -1,8 +1,15 @@
TARGET = qsqldb2
-SOURCES = main.cpp
+HEADERS += $$PWD/qsql_db2_p.h
+SOURCES += $$PWD/qsql_db2.cpp $$PWD/main.cpp
+
+unix {
+ !contains(LIBS, .*db2.*):LIBS += -ldb2
+} else {
+ !contains(LIBS, .*db2.*):LIBS += -ldb2cli
+}
+
OTHER_FILES += db2.json
-include(../../../sql/drivers/db2/qsql_db2.pri)
PLUGIN_CLASS_NAME = QDB2DriverPlugin
include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/db2/main.cpp b/src/plugins/sqldrivers/db2/main.cpp
index 3869d7798d..97338b8eef 100644
--- a/src/plugins/sqldrivers/db2/main.cpp
+++ b/src/plugins/sqldrivers/db2/main.cpp
@@ -39,7 +39,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/db2/qsql_db2_p.h"
+#include "qsql_db2_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/db2/qsql_db2.cpp b/src/plugins/sqldrivers/db2/qsql_db2.cpp
new file mode 100644
index 0000000000..4ccc3aca9e
--- /dev/null
+++ b/src/plugins/sqldrivers/db2/qsql_db2.cpp
@@ -0,0 +1,1700 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsql_db2_p.h"
+#include <qcoreapplication.h>
+#include <qdatetime.h>
+#include <qsqlfield.h>
+#include <qsqlerror.h>
+#include <qsqlindex.h>
+#include <qsqlrecord.h>
+#include <qstringlist.h>
+#include <qvarlengtharray.h>
+#include <qvector.h>
+#include <QDebug>
+#include <QtSql/private/qsqldriver_p.h>
+#include <QtSql/private/qsqlresult_p.h>
+
+#if defined(Q_CC_BOR)
+// DB2's sqlsystm.h (included through sqlcli1.h) defines the SQL_BIGINT_TYPE
+// and SQL_BIGUINT_TYPE to wrong the types for Borland; so do the defines to
+// the right type before including the header
+#define SQL_BIGINT_TYPE qint64
+#define SQL_BIGUINT_TYPE quint64
+#endif
+
+#define UNICODE
+
+#include <sqlcli1.h>
+
+#include <string.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int COLNAMESIZE = 255;
+static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
+
+class QDB2DriverPrivate : public QSqlDriverPrivate
+{
+ Q_DECLARE_PUBLIC(QDB2Driver)
+
+public:
+ QDB2DriverPrivate() : QSqlDriverPrivate(), hEnv(0), hDbc(0) { dbmsType = QSqlDriver::DB2; }
+ SQLHANDLE hEnv;
+ SQLHANDLE hDbc;
+ QString user;
+};
+
+class QDB2ResultPrivate;
+
+class QDB2Result: public QSqlResult
+{
+ Q_DECLARE_PRIVATE(QDB2Result)
+
+public:
+ QDB2Result(const QDB2Driver *drv);
+ ~QDB2Result();
+ bool prepare(const QString &query) Q_DECL_OVERRIDE;
+ bool exec() Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+
+protected:
+ QVariant data(int field) Q_DECL_OVERRIDE;
+ bool reset(const QString &query) Q_DECL_OVERRIDE;
+ bool fetch(int i) Q_DECL_OVERRIDE;
+ bool fetchNext() Q_DECL_OVERRIDE;
+ bool fetchFirst() Q_DECL_OVERRIDE;
+ bool fetchLast() Q_DECL_OVERRIDE;
+ bool isNull(int i) Q_DECL_OVERRIDE;
+ int size() Q_DECL_OVERRIDE;
+ int numRowsAffected() Q_DECL_OVERRIDE;
+ QSqlRecord record() const Q_DECL_OVERRIDE;
+ void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
+ void detachFromResultSet() Q_DECL_OVERRIDE;
+ bool nextResult() Q_DECL_OVERRIDE;
+};
+
+class QDB2ResultPrivate: public QSqlResultPrivate
+{
+ Q_DECLARE_PUBLIC(QDB2Result)
+
+public:
+ Q_DECLARE_SQLDRIVER_PRIVATE(QDB2Driver)
+ QDB2ResultPrivate(QDB2Result *q, const QDB2Driver *drv)
+ : QSqlResultPrivate(q, drv),
+ hStmt(0)
+ {}
+ ~QDB2ResultPrivate()
+ {
+ emptyValueCache();
+ }
+ void clearValueCache()
+ {
+ for (int i = 0; i < valueCache.count(); ++i) {
+ delete valueCache[i];
+ valueCache[i] = NULL;
+ }
+ }
+ void emptyValueCache()
+ {
+ clearValueCache();
+ valueCache.clear();
+ }
+
+ SQLHANDLE hStmt;
+ QSqlRecord recInf;
+ QVector<QVariant*> valueCache;
+};
+
+static QString qFromTChar(SQLTCHAR* str)
+{
+ return QString((const QChar *)str);
+}
+
+// dangerous!! (but fast). Don't use in functions that
+// require out parameters!
+static SQLTCHAR* qToTChar(const QString& str)
+{
+ return (SQLTCHAR*)str.utf16();
+}
+
+static QString qWarnDB2Handle(int handleType, SQLHANDLE handle)
+{
+ SQLINTEGER nativeCode;
+ SQLSMALLINT msgLen;
+ SQLRETURN r = SQL_ERROR;
+ SQLTCHAR state[SQL_SQLSTATE_SIZE + 1];
+ SQLTCHAR description[SQL_MAX_MESSAGE_LENGTH];
+ r = SQLGetDiagRec(handleType,
+ handle,
+ 1,
+ (SQLTCHAR*) state,
+ &nativeCode,
+ (SQLTCHAR*) description,
+ SQL_MAX_MESSAGE_LENGTH - 1, /* in bytes, not in characters */
+ &msgLen);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ return QString(qFromTChar(description));
+ return QString();
+}
+
+static QString qDB2Warn(const QDB2DriverPrivate* d)
+{
+ return (qWarnDB2Handle(SQL_HANDLE_ENV, d->hEnv) + QLatin1Char(' ')
+ + qWarnDB2Handle(SQL_HANDLE_DBC, d->hDbc));
+}
+
+static QString qDB2Warn(const QDB2ResultPrivate* d)
+{
+ return (qWarnDB2Handle(SQL_HANDLE_ENV, d->drv_d_func()->hEnv) + QLatin1Char(' ')
+ + qWarnDB2Handle(SQL_HANDLE_DBC, d->drv_d_func()->hDbc)
+ + qWarnDB2Handle(SQL_HANDLE_STMT, d->hStmt));
+}
+
+static void qSqlWarning(const QString& message, const QDB2DriverPrivate* d)
+{
+ qWarning("%s\tError: %s", message.toLocal8Bit().constData(),
+ qDB2Warn(d).toLocal8Bit().constData());
+}
+
+static void qSqlWarning(const QString& message, const QDB2ResultPrivate* d)
+{
+ qWarning("%s\tError: %s", message.toLocal8Bit().constData(),
+ qDB2Warn(d).toLocal8Bit().constData());
+}
+
+static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
+ const QDB2DriverPrivate* p)
+{
+ return QSqlError(QLatin1String("QDB2: ") + err, qDB2Warn(p), type);
+}
+
+static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
+ const QDB2ResultPrivate* p)
+{
+ return QSqlError(QLatin1String("QDB2: ") + err, qDB2Warn(p), type);
+}
+
+static QVariant::Type qDecodeDB2Type(SQLSMALLINT sqltype)
+{
+ QVariant::Type type = QVariant::Invalid;
+ switch (sqltype) {
+ case SQL_REAL:
+ case SQL_FLOAT:
+ case SQL_DOUBLE:
+ case SQL_DECIMAL:
+ case SQL_NUMERIC:
+ type = QVariant::Double;
+ break;
+ case SQL_SMALLINT:
+ case SQL_INTEGER:
+ case SQL_BIT:
+ case SQL_TINYINT:
+ type = QVariant::Int;
+ break;
+ case SQL_BIGINT:
+ type = QVariant::LongLong;
+ break;
+ case SQL_BLOB:
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ case SQL_LONGVARBINARY:
+ case SQL_CLOB:
+ case SQL_DBCLOB:
+ type = QVariant::ByteArray;
+ break;
+ case SQL_DATE:
+ case SQL_TYPE_DATE:
+ type = QVariant::Date;
+ break;
+ case SQL_TIME:
+ case SQL_TYPE_TIME:
+ type = QVariant::Time;
+ break;
+ case SQL_TIMESTAMP:
+ case SQL_TYPE_TIMESTAMP:
+ type = QVariant::DateTime;
+ break;
+ case SQL_WCHAR:
+ case SQL_WVARCHAR:
+ case SQL_WLONGVARCHAR:
+ case SQL_CHAR:
+ case SQL_VARCHAR:
+ case SQL_LONGVARCHAR:
+ type = QVariant::String;
+ break;
+ default:
+ type = QVariant::ByteArray;
+ break;
+ }
+ return type;
+}
+
+static QSqlField qMakeFieldInfo(const QDB2ResultPrivate* d, int i)
+{
+ SQLSMALLINT colNameLen;
+ SQLSMALLINT colType;
+ SQLUINTEGER colSize;
+ SQLSMALLINT colScale;
+ SQLSMALLINT nullable;
+ SQLRETURN r = SQL_ERROR;
+ SQLTCHAR colName[COLNAMESIZE];
+ r = SQLDescribeCol(d->hStmt,
+ i+1,
+ colName,
+ (SQLSMALLINT) COLNAMESIZE,
+ &colNameLen,
+ &colType,
+ &colSize,
+ &colScale,
+ &nullable);
+
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QString::fromLatin1("qMakeFieldInfo: Unable to describe column %1").arg(i), d);
+ return QSqlField();
+ }
+ QSqlField f(qFromTChar(colName), qDecodeDB2Type(colType));
+ // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
+ if (nullable == SQL_NO_NULLS)
+ f.setRequired(true);
+ else if (nullable == SQL_NULLABLE)
+ f.setRequired(false);
+ // else required is unknown
+ f.setLength(colSize == 0 ? -1 : int(colSize));
+ f.setPrecision(colScale == 0 ? -1 : int(colScale));
+ f.setSqlType(int(colType));
+ return f;
+}
+
+static int qGetIntData(SQLHANDLE hStmt, int column, bool& isNull)
+{
+ SQLINTEGER intbuf;
+ isNull = false;
+ SQLINTEGER lengthIndicator = 0;
+ SQLRETURN r = SQLGetData(hStmt,
+ column + 1,
+ SQL_C_SLONG,
+ (SQLPOINTER) &intbuf,
+ 0,
+ &lengthIndicator);
+ if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || lengthIndicator == SQL_NULL_DATA) {
+ isNull = true;
+ return 0;
+ }
+ return int(intbuf);
+}
+
+static double qGetDoubleData(SQLHANDLE hStmt, int column, bool& isNull)
+{
+ SQLDOUBLE dblbuf;
+ isNull = false;
+ SQLINTEGER lengthIndicator = 0;
+ SQLRETURN r = SQLGetData(hStmt,
+ column+1,
+ SQL_C_DOUBLE,
+ (SQLPOINTER) &dblbuf,
+ 0,
+ &lengthIndicator);
+ if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || lengthIndicator == SQL_NULL_DATA) {
+ isNull = true;
+ return 0.0;
+ }
+
+ return (double) dblbuf;
+}
+
+static SQLBIGINT qGetBigIntData(SQLHANDLE hStmt, int column, bool& isNull)
+{
+ SQLBIGINT lngbuf = Q_INT64_C(0);
+ isNull = false;
+ SQLINTEGER lengthIndicator = 0;
+ SQLRETURN r = SQLGetData(hStmt,
+ column+1,
+ SQL_C_SBIGINT,
+ (SQLPOINTER) &lngbuf,
+ 0,
+ &lengthIndicator);
+ if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || lengthIndicator == SQL_NULL_DATA)
+ isNull = true;
+
+ return lngbuf;
+}
+
+static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool& isNull)
+{
+ QString fieldVal;
+ SQLRETURN r = SQL_ERROR;
+ SQLINTEGER lengthIndicator = 0;
+
+ if (colSize <= 0)
+ colSize = 255;
+ else if (colSize > 65536) // limit buffer size to 64 KB
+ colSize = 65536;
+ else
+ colSize++; // make sure there is room for more than the 0 termination
+ SQLTCHAR* buf = new SQLTCHAR[colSize];
+
+ while (true) {
+ r = SQLGetData(hStmt,
+ column + 1,
+ SQL_C_WCHAR,
+ (SQLPOINTER)buf,
+ colSize * sizeof(SQLTCHAR),
+ &lengthIndicator);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) {
+ fieldVal.clear();
+ isNull = true;
+ break;
+ }
+ fieldVal += qFromTChar(buf);
+ } else if (r == SQL_NO_DATA) {
+ break;
+ } else {
+ qWarning("qGetStringData: Error while fetching data (%d)", r);
+ fieldVal.clear();
+ break;
+ }
+ }
+ delete[] buf;
+ return fieldVal;
+}
+
+static QByteArray qGetBinaryData(SQLHANDLE hStmt, int column, SQLINTEGER& lengthIndicator, bool& isNull)
+{
+ QByteArray fieldVal;
+ SQLSMALLINT colNameLen;
+ SQLSMALLINT colType;
+ SQLUINTEGER colSize;
+ SQLSMALLINT colScale;
+ SQLSMALLINT nullable;
+ SQLRETURN r = SQL_ERROR;
+
+ SQLTCHAR colName[COLNAMESIZE];
+ r = SQLDescribeCol(hStmt,
+ column+1,
+ colName,
+ COLNAMESIZE,
+ &colNameLen,
+ &colType,
+ &colSize,
+ &colScale,
+ &nullable);
+ if (r != SQL_SUCCESS)
+ qWarning("qGetBinaryData: Unable to describe column %d", column);
+ // SQLDescribeCol may return 0 if size cannot be determined
+ if (!colSize)
+ colSize = 255;
+ else if (colSize > 65536) // read the field in 64 KB chunks
+ colSize = 65536;
+ char * buf = new char[colSize];
+ while (true) {
+ r = SQLGetData(hStmt,
+ column+1,
+ colType == SQL_DBCLOB ? SQL_C_CHAR : SQL_C_BINARY,
+ (SQLPOINTER) buf,
+ colSize,
+ &lengthIndicator);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (lengthIndicator == SQL_NULL_DATA) {
+ isNull = true;
+ break;
+ } else {
+ int rSize;
+ r == SQL_SUCCESS ? rSize = lengthIndicator : rSize = colSize;
+ if (lengthIndicator == SQL_NO_TOTAL) // size cannot be determined
+ rSize = colSize;
+ fieldVal.append(QByteArray(buf, rSize));
+ if (r == SQL_SUCCESS) // the whole field was read in one chunk
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ delete [] buf;
+ return fieldVal;
+}
+
+static void qSplitTableQualifier(const QString & qualifier, QString * catalog,
+ QString * schema, QString * table)
+{
+ if (!catalog || !schema || !table)
+ return;
+ QStringList l = qualifier.split(QLatin1Char('.'));
+ if (l.count() > 3)
+ return; // can't possibly be a valid table qualifier
+ int i = 0, n = l.count();
+ if (n == 1) {
+ *table = qualifier;
+ } else {
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ if (n == 3) {
+ if (i == 0)
+ *catalog = *it;
+ else if (i == 1)
+ *schema = *it;
+ else if (i == 2)
+ *table = *it;
+ } else if (n == 2) {
+ if (i == 0)
+ *schema = *it;
+ else if (i == 1)
+ *table = *it;
+ }
+ i++;
+ }
+ }
+}
+
+// creates a QSqlField from a valid hStmt generated
+// by SQLColumns. The hStmt has to point to a valid position.
+static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt)
+{
+ bool isNull;
+ int type = qGetIntData(hStmt, 4, isNull);
+ QSqlField f(qGetStringData(hStmt, 3, -1, isNull), qDecodeDB2Type(type));
+ int required = qGetIntData(hStmt, 10, isNull); // nullable-flag
+ // required can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
+ if (required == SQL_NO_NULLS)
+ f.setRequired(true);
+ else if (required == SQL_NULLABLE)
+ f.setRequired(false);
+ // else we don't know.
+ f.setLength(qGetIntData(hStmt, 6, isNull)); // column size
+ f.setPrecision(qGetIntData(hStmt, 8, isNull)); // precision
+ f.setSqlType(type);
+ return f;
+}
+
+static bool qMakeStatement(QDB2ResultPrivate* d, bool forwardOnly, bool setForwardOnly = true)
+{
+ SQLRETURN r;
+ if (!d->hStmt) {
+ r = SQLAllocHandle(SQL_HANDLE_STMT,
+ d->drv_d_func()->hDbc,
+ &d->hStmt);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QDB2Result::reset: Unable to allocate statement handle"), d);
+ return false;
+ }
+ } else {
+ r = SQLFreeStmt(d->hStmt, SQL_CLOSE);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QDB2Result::reset: Unable to close statement handle"), d);
+ return false;
+ }
+ }
+
+ if (!setForwardOnly)
+ return true;
+
+ if (forwardOnly) {
+ r = SQLSetStmtAttr(d->hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+ } else {
+ r = SQLSetStmtAttr(d->hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER) SQL_CURSOR_STATIC,
+ SQL_IS_UINTEGER);
+ }
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ qSqlWarning(QString::fromLatin1("QDB2Result::reset: Unable to set %1 attribute.").arg(
+ forwardOnly ? QLatin1String("SQL_CURSOR_FORWARD_ONLY")
+ : QLatin1String("SQL_CURSOR_STATIC")), d);
+ return false;
+ }
+ return true;
+}
+
+QVariant QDB2Result::handle() const
+{
+ Q_D(const QDB2Result);
+ return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hStmt);
+}
+
+/************************************/
+
+QDB2Result::QDB2Result(const QDB2Driver *drv)
+ : QSqlResult(*new QDB2ResultPrivate(this, drv))
+{
+}
+
+QDB2Result::~QDB2Result()
+{
+ Q_D(const QDB2Result);
+ if (d->hStmt) {
+ SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QDB2Driver: Unable to free statement handle ")
+ + QString::number(r), d);
+ }
+}
+
+bool QDB2Result::reset (const QString& query)
+{
+ Q_D(QDB2Result);
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+ SQLRETURN r;
+
+ d->recInf.clear();
+ d->emptyValueCache();
+
+ if (!qMakeStatement(d, isForwardOnly()))
+ return false;
+
+ r = SQLExecDirect(d->hStmt,
+ qToTChar(query),
+ (SQLINTEGER) query.length());
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
+ "Unable to execute statement"), QSqlError::StatementError, d));
+ return false;
+ }
+ SQLSMALLINT count = 0;
+ r = SQLNumResultCols(d->hStmt, &count);
+ if (count) {
+ setSelect(true);
+ for (int i = 0; i < count; ++i) {
+ d->recInf.append(qMakeFieldInfo(d, i));
+ }
+ } else {
+ setSelect(false);
+ }
+ d->valueCache.resize(count);
+ d->valueCache.fill(NULL);
+ setActive(true);
+ return true;
+}
+
+bool QDB2Result::prepare(const QString& query)
+{
+ Q_D(QDB2Result);
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+ SQLRETURN r;
+
+ d->recInf.clear();
+ d->emptyValueCache();
+
+ if (!qMakeStatement(d, isForwardOnly()))
+ return false;
+
+ r = SQLPrepare(d->hStmt,
+ qToTChar(query),
+ (SQLINTEGER) query.length());
+
+ if (r != SQL_SUCCESS) {
+ setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
+ "Unable to prepare statement"), QSqlError::StatementError, d));
+ return false;
+ }
+ return true;
+}
+
+bool QDB2Result::exec()
+{
+ Q_D(QDB2Result);
+ QList<QByteArray> tmpStorage; // holds temporary ptrs
+ QVarLengthArray<SQLINTEGER, 32> indicators(boundValues().count());
+
+ memset(indicators.data(), 0, indicators.size() * sizeof(SQLINTEGER));
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+ SQLRETURN r;
+
+ d->recInf.clear();
+ d->emptyValueCache();
+
+ if (!qMakeStatement(d, isForwardOnly(), false))
+ return false;
+
+
+ QVector<QVariant> &values = boundValues();
+ int i;
+ for (i = 0; i < values.count(); ++i) {
+ // bind parameters - only positional binding allowed
+ SQLINTEGER *ind = &indicators[i];
+ if (values.at(i).isNull())
+ *ind = SQL_NULL_DATA;
+ if (bindValueType(i) & QSql::Out)
+ values[i].detach();
+
+ switch (values.at(i).type()) {
+ case QVariant::Date: {
+ QByteArray ba;
+ ba.resize(sizeof(DATE_STRUCT));
+ DATE_STRUCT *dt = (DATE_STRUCT *)ba.constData();
+ QDate qdt = values.at(i).toDate();
+ dt->year = qdt.year();
+ dt->month = qdt.month();
+ dt->day = qdt.day();
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & 3],
+ SQL_C_DATE,
+ SQL_DATE,
+ 0,
+ 0,
+ (void *) dt,
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ tmpStorage.append(ba);
+ break; }
+ case QVariant::Time: {
+ QByteArray ba;
+ ba.resize(sizeof(TIME_STRUCT));
+ TIME_STRUCT *dt = (TIME_STRUCT *)ba.constData();
+ QTime qdt = values.at(i).toTime();
+ dt->hour = qdt.hour();
+ dt->minute = qdt.minute();
+ dt->second = qdt.second();
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & 3],
+ SQL_C_TIME,
+ SQL_TIME,
+ 0,
+ 0,
+ (void *) dt,
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ tmpStorage.append(ba);
+ break; }
+ case QVariant::DateTime: {
+ QByteArray ba;
+ ba.resize(sizeof(TIMESTAMP_STRUCT));
+ TIMESTAMP_STRUCT * dt = (TIMESTAMP_STRUCT *)ba.constData();
+ QDateTime qdt = values.at(i).toDateTime();
+ dt->year = qdt.date().year();
+ dt->month = qdt.date().month();
+ dt->day = qdt.date().day();
+ dt->hour = qdt.time().hour();
+ dt->minute = qdt.time().minute();
+ dt->second = qdt.time().second();
+ dt->fraction = qdt.time().msec() * 1000000;
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & 3],
+ SQL_C_TIMESTAMP,
+ SQL_TIMESTAMP,
+ 0,
+ 0,
+ (void *) dt,
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ tmpStorage.append(ba);
+ break; }
+ case QVariant::Int:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & 3],
+ SQL_C_SLONG,
+ SQL_INTEGER,
+ 0,
+ 0,
+ (void *)values.at(i).constData(),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QVariant::Double:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & 3],
+ SQL_C_DOUBLE,
+ SQL_DOUBLE,
+ 0,
+ 0,
+ (void *)values.at(i).constData(),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QVariant::ByteArray: {
+ int len = values.at(i).toByteArray().size();
+ if (*ind != SQL_NULL_DATA)
+ *ind = len;
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & 3],
+ SQL_C_BINARY,
+ SQL_LONGVARBINARY,
+ len,
+ 0,
+ (void *)values.at(i).toByteArray().constData(),
+ len,
+ ind);
+ break; }
+ case QVariant::String:
+ {
+ QString str(values.at(i).toString());
+ if (*ind != SQL_NULL_DATA)
+ *ind = str.length() * sizeof(QChar);
+ if (bindValueType(i) & QSql::Out) {
+ QByteArray ba((char*)str.utf16(), str.capacity() * sizeof(QChar));
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & 3],
+ SQL_C_WCHAR,
+ SQL_WVARCHAR,
+ str.length(),
+ 0,
+ (void *)ba.constData(),
+ ba.size(),
+ ind);
+ tmpStorage.append(ba);
+ } else {
+ void *data = (void*)str.utf16();
+ int len = str.length();
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & 3],
+ SQL_C_WCHAR,
+ SQL_WVARCHAR,
+ len,
+ 0,
+ data,
+ len * sizeof(QChar),
+ ind);
+ }
+ break;
+ }
+ default: {
+ QByteArray ba = values.at(i).toString().toLatin1();
+ int len = ba.length() + 1;
+ if (*ind != SQL_NULL_DATA)
+ *ind = ba.length();
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & 3],
+ SQL_C_CHAR,
+ SQL_VARCHAR,
+ len,
+ 0,
+ (void *) ba.constData(),
+ len,
+ ind);
+ tmpStorage.append(ba);
+ break; }
+ }
+ if (r != SQL_SUCCESS) {
+ qWarning("QDB2Result::exec: unable to bind variable: %s",
+ qDB2Warn(d).toLocal8Bit().constData());
+ setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
+ "Unable to bind variable"), QSqlError::StatementError, d));
+ return false;
+ }
+ }
+
+ r = SQLExecute(d->hStmt);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ qWarning("QDB2Result::exec: Unable to execute statement: %s",
+ qDB2Warn(d).toLocal8Bit().constData());
+ setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
+ "Unable to execute statement"), QSqlError::StatementError, d));
+ return false;
+ }
+ SQLSMALLINT count = 0;
+ r = SQLNumResultCols(d->hStmt, &count);
+ if (count) {
+ setSelect(true);
+ for (int i = 0; i < count; ++i) {
+ d->recInf.append(qMakeFieldInfo(d, i));
+ }
+ } else {
+ setSelect(false);
+ }
+ setActive(true);
+ d->valueCache.resize(count);
+ d->valueCache.fill(NULL);
+
+ //get out parameters
+ if (!hasOutValues())
+ return true;
+
+ for (i = 0; i < values.count(); ++i) {
+ switch (values[i].type()) {
+ case QVariant::Date: {
+ DATE_STRUCT ds = *((DATE_STRUCT *)tmpStorage.takeFirst().constData());
+ values[i] = QVariant(QDate(ds.year, ds.month, ds.day));
+ break; }
+ case QVariant::Time: {
+ TIME_STRUCT dt = *((TIME_STRUCT *)tmpStorage.takeFirst().constData());
+ values[i] = QVariant(QTime(dt.hour, dt.minute, dt.second));
+ break; }
+ case QVariant::DateTime: {
+ TIMESTAMP_STRUCT dt = *((TIMESTAMP_STRUCT *)tmpStorage.takeFirst().constData());
+ values[i] = QVariant(QDateTime(QDate(dt.year, dt.month, dt.day),
+ QTime(dt.hour, dt.minute, dt.second, dt.fraction / 1000000)));
+ break; }
+ case QVariant::Int:
+ case QVariant::Double:
+ case QVariant::ByteArray:
+ break;
+ case QVariant::String:
+ if (bindValueType(i) & QSql::Out)
+ values[i] = QString((const QChar *)tmpStorage.takeFirst().constData());
+ break;
+ default: {
+ values[i] = QString::fromLatin1(tmpStorage.takeFirst().constData());
+ break; }
+ }
+ if (indicators[i] == SQL_NULL_DATA)
+ values[i] = QVariant(values[i].type());
+ }
+ return true;
+}
+
+bool QDB2Result::fetch(int i)
+{
+ Q_D(QDB2Result);
+ if (isForwardOnly() && i < at())
+ return false;
+ if (i == at())
+ return true;
+ d->clearValueCache();
+ int actualIdx = i + 1;
+ if (actualIdx <= 0) {
+ setAt(QSql::BeforeFirstRow);
+ return false;
+ }
+ SQLRETURN r;
+ if (isForwardOnly()) {
+ bool ok = true;
+ while (ok && i > at())
+ ok = fetchNext();
+ return ok;
+ } else {
+ r = SQLFetchScroll(d->hStmt,
+ SQL_FETCH_ABSOLUTE,
+ actualIdx);
+ }
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
+ setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
+ "Unable to fetch record %1").arg(i), QSqlError::StatementError, d));
+ return false;
+ }
+ else if (r == SQL_NO_DATA)
+ return false;
+ setAt(i);
+ return true;
+}
+
+bool QDB2Result::fetchNext()
+{
+ Q_D(QDB2Result);
+ SQLRETURN r;
+ d->clearValueCache();
+ r = SQLFetchScroll(d->hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (r != SQL_NO_DATA)
+ setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
+ "Unable to fetch next"), QSqlError::StatementError, d));
+ return false;
+ }
+ setAt(at() + 1);
+ return true;
+}
+
+bool QDB2Result::fetchFirst()
+{
+ Q_D(QDB2Result);
+ if (isForwardOnly() && at() != QSql::BeforeFirstRow)
+ return false;
+ if (isForwardOnly())
+ return fetchNext();
+ d->clearValueCache();
+ SQLRETURN r;
+ r = SQLFetchScroll(d->hStmt,
+ SQL_FETCH_FIRST,
+ 0);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if(r!= SQL_NO_DATA)
+ setLastError(qMakeError(QCoreApplication::translate("QDB2Result", "Unable to fetch first"),
+ QSqlError::StatementError, d));
+ return false;
+ }
+ setAt(0);
+ return true;
+}
+
+bool QDB2Result::fetchLast()
+{
+ Q_D(QDB2Result);
+ d->clearValueCache();
+
+ int i = at();
+ if (i == QSql::AfterLastRow) {
+ if (isForwardOnly()) {
+ return false;
+ } else {
+ if (!fetch(0))
+ return false;
+ i = at();
+ }
+ }
+
+ while (fetchNext())
+ ++i;
+
+ if (i == QSql::BeforeFirstRow) {
+ setAt(QSql::AfterLastRow);
+ return false;
+ }
+
+ if (!isForwardOnly())
+ return fetch(i);
+
+ setAt(i);
+ return true;
+}
+
+
+QVariant QDB2Result::data(int field)
+{
+ Q_D(QDB2Result);
+ if (field >= d->recInf.count()) {
+ qWarning("QDB2Result::data: column %d out of range", field);
+ return QVariant();
+ }
+ SQLRETURN r = 0;
+ SQLINTEGER lengthIndicator = 0;
+ bool isNull = false;
+ const QSqlField info = d->recInf.field(field);
+
+ if (!info.isValid() || field >= d->valueCache.size())
+ return QVariant();
+
+ if (d->valueCache[field])
+ return *d->valueCache[field];
+
+
+ QVariant* v = 0;
+ switch (info.type()) {
+ case QVariant::LongLong:
+ v = new QVariant((qint64) qGetBigIntData(d->hStmt, field, isNull));
+ break;
+ case QVariant::Int:
+ v = new QVariant(qGetIntData(d->hStmt, field, isNull));
+ break;
+ case QVariant::Date: {
+ DATE_STRUCT dbuf;
+ r = SQLGetData(d->hStmt,
+ field + 1,
+ SQL_C_DATE,
+ (SQLPOINTER) &dbuf,
+ 0,
+ &lengthIndicator);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA)) {
+ v = new QVariant(QDate(dbuf.year, dbuf.month, dbuf.day));
+ } else {
+ v = new QVariant(QDate());
+ isNull = true;
+ }
+ break; }
+ case QVariant::Time: {
+ TIME_STRUCT tbuf;
+ r = SQLGetData(d->hStmt,
+ field + 1,
+ SQL_C_TIME,
+ (SQLPOINTER) &tbuf,
+ 0,
+ &lengthIndicator);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA)) {
+ v = new QVariant(QTime(tbuf.hour, tbuf.minute, tbuf.second));
+ } else {
+ v = new QVariant(QTime());
+ isNull = true;
+ }
+ break; }
+ case QVariant::DateTime: {
+ TIMESTAMP_STRUCT dtbuf;
+ r = SQLGetData(d->hStmt,
+ field + 1,
+ SQL_C_TIMESTAMP,
+ (SQLPOINTER) &dtbuf,
+ 0,
+ &lengthIndicator);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA)) {
+ v = new QVariant(QDateTime(QDate(dtbuf.year, dtbuf.month, dtbuf.day),
+ QTime(dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000)));
+ } else {
+ v = new QVariant(QDateTime());
+ isNull = true;
+ }
+ break; }
+ case QVariant::ByteArray:
+ v = new QVariant(qGetBinaryData(d->hStmt, field, lengthIndicator, isNull));
+ break;
+ case QVariant::Double:
+ {
+ switch(numericalPrecisionPolicy()) {
+ case QSql::LowPrecisionInt32:
+ v = new QVariant(qGetIntData(d->hStmt, field, isNull));
+ break;
+ case QSql::LowPrecisionInt64:
+ v = new QVariant((qint64) qGetBigIntData(d->hStmt, field, isNull));
+ break;
+ case QSql::LowPrecisionDouble:
+ v = new QVariant(qGetDoubleData(d->hStmt, field, isNull));
+ break;
+ case QSql::HighPrecision:
+ default:
+ // length + 1 for the comma
+ v = new QVariant(qGetStringData(d->hStmt, field, info.length() + 1, isNull));
+ break;
+ }
+ break;
+ }
+ case QVariant::String:
+ default:
+ v = new QVariant(qGetStringData(d->hStmt, field, info.length(), isNull));
+ break;
+ }
+ if (isNull)
+ *v = QVariant(info.type());
+ d->valueCache[field] = v;
+ return *v;
+}
+
+bool QDB2Result::isNull(int i)
+{
+ Q_D(const QDB2Result);
+ if (i >= d->valueCache.size())
+ return true;
+
+ if (d->valueCache[i])
+ return d->valueCache[i]->isNull();
+ return data(i).isNull();
+}
+
+int QDB2Result::numRowsAffected()
+{
+ Q_D(const QDB2Result);
+ SQLINTEGER affectedRowCount = 0;
+ SQLRETURN r = SQLRowCount(d->hStmt, &affectedRowCount);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ return affectedRowCount;
+ else
+ qSqlWarning(QLatin1String("QDB2Result::numRowsAffected: Unable to count affected rows"), d);
+ return -1;
+}
+
+int QDB2Result::size()
+{
+ return -1;
+}
+
+QSqlRecord QDB2Result::record() const
+{
+ Q_D(const QDB2Result);
+ if (isActive())
+ return d->recInf;
+ return QSqlRecord();
+}
+
+bool QDB2Result::nextResult()
+{
+ Q_D(QDB2Result);
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+ d->recInf.clear();
+ d->emptyValueCache();
+ setSelect(false);
+
+ SQLRETURN r = SQLMoreResults(d->hStmt);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (r != SQL_NO_DATA) {
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to fetch last"), QSqlError::ConnectionError, d));
+ }
+ return false;
+ }
+
+ SQLSMALLINT fieldCount = 0;
+ r = SQLNumResultCols(d->hStmt, &fieldCount);
+ setSelect(fieldCount > 0);
+ for (int i = 0; i < fieldCount; ++i)
+ d->recInf.append(qMakeFieldInfo(d, i));
+
+ d->valueCache.resize(fieldCount);
+ d->valueCache.fill(NULL);
+ setActive(true);
+
+ return true;
+}
+
+void QDB2Result::virtual_hook(int id, void *data)
+{
+ QSqlResult::virtual_hook(id, data);
+}
+
+void QDB2Result::detachFromResultSet()
+{
+ Q_D(QDB2Result);
+ if (d->hStmt)
+ SQLCloseCursor(d->hStmt);
+}
+
+/************************************/
+
+QDB2Driver::QDB2Driver(QObject* parent)
+ : QSqlDriver(*new QDB2DriverPrivate, parent)
+{
+}
+
+QDB2Driver::QDB2Driver(Qt::HANDLE env, Qt::HANDLE con, QObject* parent)
+ : QSqlDriver(*new QDB2DriverPrivate, parent)
+{
+ Q_D(QDB2Driver);
+ d->hEnv = reinterpret_cast<intptr_t>(env);
+ d->hDbc = reinterpret_cast<intptr_t>(con);
+ if (env && con) {
+ setOpen(true);
+ setOpenError(false);
+ }
+}
+
+QDB2Driver::~QDB2Driver()
+{
+ close();
+}
+
+bool QDB2Driver::open(const QString& db, const QString& user, const QString& password, const QString& host, int port,
+ const QString& connOpts)
+{
+ Q_D(QDB2Driver);
+ if (isOpen())
+ close();
+ SQLRETURN r;
+ r = SQLAllocHandle(SQL_HANDLE_ENV,
+ SQL_NULL_HANDLE,
+ &d->hEnv);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ qSqlWarning(QLatin1String("QDB2Driver::open: Unable to allocate environment"), d);
+ setOpenError(true);
+ return false;
+ }
+
+ r = SQLAllocHandle(SQL_HANDLE_DBC,
+ d->hEnv,
+ &d->hDbc);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ qSqlWarning(QLatin1String("QDB2Driver::open: Unable to allocate connection"), d);
+ setOpenError(true);
+ return false;
+ }
+
+ QString protocol;
+ // Set connection attributes
+ const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
+ for (int i = 0; i < opts.count(); ++i) {
+ const QString tmp(opts.at(i));
+ int idx;
+ if ((idx = tmp.indexOf(QLatin1Char('='))) == -1) {
+ qWarning("QDB2Driver::open: Illegal connect option value '%s'",
+ tmp.toLocal8Bit().constData());
+ continue;
+ }
+
+ const QString opt(tmp.left(idx));
+ const QString val(tmp.mid(idx + 1).simplified());
+
+ SQLUINTEGER v = 0;
+ r = SQL_SUCCESS;
+ if (opt == QLatin1String("SQL_ATTR_ACCESS_MODE")) {
+ if (val == QLatin1String("SQL_MODE_READ_ONLY")) {
+ v = SQL_MODE_READ_ONLY;
+ } else if (val == QLatin1String("SQL_MODE_READ_WRITE")) {
+ v = SQL_MODE_READ_WRITE;
+ } else {
+ qWarning("QDB2Driver::open: Unknown option value '%s'",
+ tmp.toLocal8Bit().constData());
+ continue;
+ }
+ r = SQLSetConnectAttr(d->hDbc, SQL_ATTR_ACCESS_MODE, reinterpret_cast<SQLPOINTER>(v), 0);
+ } else if (opt == QLatin1String("SQL_ATTR_LOGIN_TIMEOUT")) {
+ v = val.toUInt();
+ r = SQLSetConnectAttr(d->hDbc, SQL_ATTR_LOGIN_TIMEOUT, reinterpret_cast<SQLPOINTER>(v), 0);
+ } else if (opt.compare(QLatin1String("PROTOCOL"), Qt::CaseInsensitive) == 0) {
+ protocol = tmp;
+ }
+ else {
+ qWarning("QDB2Driver::open: Unknown connection attribute '%s'",
+ tmp.toLocal8Bit().constData());
+ }
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
+ qSqlWarning(QString::fromLatin1("QDB2Driver::open: "
+ "Unable to set connection attribute '%1'").arg(opt), d);
+ }
+
+ if (protocol.isEmpty())
+ protocol = QLatin1String("PROTOCOL=TCPIP");
+
+ if (port < 0 )
+ port = 50000;
+
+ QString connQStr;
+ connQStr = protocol + QLatin1String(";DATABASE=") + db + QLatin1String(";HOSTNAME=") + host
+ + QLatin1String(";PORT=") + QString::number(port) + QLatin1String(";UID=") + user
+ + QLatin1String(";PWD=") + password;
+
+
+ SQLTCHAR connOut[SQL_MAX_OPTION_STRING_LENGTH];
+ SQLSMALLINT cb;
+
+ r = SQLDriverConnect(d->hDbc,
+ NULL,
+ qToTChar(connQStr),
+ (SQLSMALLINT) connQStr.length(),
+ connOut,
+ SQL_MAX_OPTION_STRING_LENGTH,
+ &cb,
+ SQL_DRIVER_NOPROMPT);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ setLastError(qMakeError(tr("Unable to connect"),
+ QSqlError::ConnectionError, d));
+ setOpenError(true);
+ return false;
+ }
+
+ d->user = user;
+ setOpen(true);
+ setOpenError(false);
+ return true;
+}
+
+void QDB2Driver::close()
+{
+ Q_D(QDB2Driver);
+ SQLRETURN r;
+ if (d->hDbc) {
+ // Open statements/descriptors handles are automatically cleaned up by SQLDisconnect
+ if (isOpen()) {
+ r = SQLDisconnect(d->hDbc);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QDB2Driver::close: Unable to disconnect datasource"), d);
+ }
+ r = SQLFreeHandle(SQL_HANDLE_DBC, d->hDbc);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QDB2Driver::close: Unable to free connection handle"), d);
+ d->hDbc = 0;
+ }
+
+ if (d->hEnv) {
+ r = SQLFreeHandle(SQL_HANDLE_ENV, d->hEnv);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QDB2Driver::close: Unable to free environment handle"), d);
+ d->hEnv = 0;
+ }
+ setOpen(false);
+ setOpenError(false);
+}
+
+QSqlResult *QDB2Driver::createResult() const
+{
+ return new QDB2Result(this);
+}
+
+QSqlRecord QDB2Driver::record(const QString& tableName) const
+{
+ Q_D(const QDB2Driver);
+ QSqlRecord fil;
+ if (!isOpen())
+ return fil;
+
+ SQLHANDLE hStmt;
+ QString catalog, schema, table;
+ qSplitTableQualifier(tableName, &catalog, &schema, &table);
+ if (schema.isEmpty())
+ schema = d->user;
+
+ if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
+ catalog = stripDelimiters(catalog, QSqlDriver::TableName);
+ else
+ catalog = catalog.toUpper();
+
+ if (isIdentifierEscaped(schema, QSqlDriver::TableName))
+ schema = stripDelimiters(schema, QSqlDriver::TableName);
+ else
+ schema = schema.toUpper();
+
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = table.toUpper();
+
+ SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
+ d->hDbc,
+ &hStmt);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QDB2Driver::record: Unable to allocate handle"), d);
+ return fil;
+ }
+
+ r = SQLSetStmtAttr(hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+
+
+ //Aside: szSchemaName and szTableName parameters of SQLColumns
+ //are case sensitive search patterns, so no escaping is used.
+ r = SQLColumns(hStmt,
+ NULL,
+ 0,
+ qToTChar(schema),
+ schema.length(),
+ qToTChar(table),
+ table.length(),
+ NULL,
+ 0);
+
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QDB2Driver::record: Unable to execute column list"), d);
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ while (r == SQL_SUCCESS) {
+ fil.append(qMakeFieldInfo(hStmt));
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ }
+
+ r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QDB2Driver: Unable to free statement handle ")
+ + QString::number(r), d);
+
+ return fil;
+}
+
+QStringList QDB2Driver::tables(QSql::TableType type) const
+{
+ Q_D(const QDB2Driver);
+ QStringList tl;
+ if (!isOpen())
+ return tl;
+
+ SQLHANDLE hStmt;
+
+ SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
+ d->hDbc,
+ &hStmt);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ qSqlWarning(QLatin1String("QDB2Driver::tables: Unable to allocate handle"), d);
+ return tl;
+ }
+ r = SQLSetStmtAttr(hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+
+ QString tableType;
+ if (type & QSql::Tables)
+ tableType += QLatin1String("TABLE,");
+ if (type & QSql::Views)
+ tableType += QLatin1String("VIEW,");
+ if (type & QSql::SystemTables)
+ tableType += QLatin1String("SYSTEM TABLE,");
+ if (tableType.isEmpty())
+ return tl;
+ tableType.chop(1);
+
+ r = SQLTables(hStmt,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ qToTChar(tableType),
+ tableType.length());
+
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
+ qSqlWarning(QLatin1String("QDB2Driver::tables: Unable to execute table list"), d);
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ while (r == SQL_SUCCESS) {
+ bool isNull;
+ QString fieldVal = qGetStringData(hStmt, 2, -1, isNull);
+ QString userVal = qGetStringData(hStmt, 1, -1, isNull);
+ QString user = d->user;
+ if ( isIdentifierEscaped(user, QSqlDriver::TableName))
+ user = stripDelimiters(user, QSqlDriver::TableName);
+ else
+ user = user.toUpper();
+
+ if (userVal != user)
+ fieldVal = userVal + QLatin1Char('.') + fieldVal;
+ tl.append(fieldVal);
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ }
+
+ r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QDB2Driver::tables: Unable to free statement handle ")
+ + QString::number(r), d);
+ return tl;
+}
+
+QSqlIndex QDB2Driver::primaryIndex(const QString& tablename) const
+{
+ Q_D(const QDB2Driver);
+ QSqlIndex index(tablename);
+ if (!isOpen())
+ return index;
+ QSqlRecord rec = record(tablename);
+
+ SQLHANDLE hStmt;
+ SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
+ d->hDbc,
+ &hStmt);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QDB2Driver::primaryIndex: Unable to list primary key"), d);
+ return index;
+ }
+ QString catalog, schema, table;
+ qSplitTableQualifier(tablename, &catalog, &schema, &table);
+
+ if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
+ catalog = stripDelimiters(catalog, QSqlDriver::TableName);
+ else
+ catalog = catalog.toUpper();
+
+ if (isIdentifierEscaped(schema, QSqlDriver::TableName))
+ schema = stripDelimiters(schema, QSqlDriver::TableName);
+ else
+ schema = schema.toUpper();
+
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = table.toUpper();
+
+ r = SQLSetStmtAttr(hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+
+ r = SQLPrimaryKeys(hStmt,
+ NULL,
+ 0,
+ qToTChar(schema),
+ schema.length(),
+ qToTChar(table),
+ table.length());
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+
+ bool isNull;
+ QString cName, idxName;
+ // Store all fields in a StringList because the driver can't detail fields in this FETCH loop
+ while (r == SQL_SUCCESS) {
+ cName = qGetStringData(hStmt, 3, -1, isNull); // column name
+ idxName = qGetStringData(hStmt, 5, -1, isNull); // pk index name
+ index.append(rec.field(cName));
+ index.setName(idxName);
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ }
+ r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
+ if (r!= SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QDB2Driver: Unable to free statement handle ")
+ + QString::number(r), d);
+ return index;
+}
+
+bool QDB2Driver::hasFeature(DriverFeature f) const
+{
+ switch (f) {
+ case QuerySize:
+ case NamedPlaceholders:
+ case BatchOperations:
+ case LastInsertId:
+ case SimpleLocking:
+ case EventNotifications:
+ case CancelQuery:
+ return false;
+ case BLOB:
+ case Transactions:
+ case MultipleResultSets:
+ case PreparedQueries:
+ case PositionalPlaceholders:
+ case LowPrecisionNumbers:
+ case FinishQuery:
+ return true;
+ case Unicode:
+ return true;
+ }
+ return false;
+}
+
+bool QDB2Driver::beginTransaction()
+{
+ if (!isOpen()) {
+ qWarning("QDB2Driver::beginTransaction: Database not open");
+ return false;
+ }
+ return setAutoCommit(false);
+}
+
+bool QDB2Driver::commitTransaction()
+{
+ Q_D(QDB2Driver);
+ if (!isOpen()) {
+ qWarning("QDB2Driver::commitTransaction: Database not open");
+ return false;
+ }
+ SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
+ d->hDbc,
+ SQL_COMMIT);
+ if (r != SQL_SUCCESS) {
+ setLastError(qMakeError(tr("Unable to commit transaction"),
+ QSqlError::TransactionError, d));
+ return false;
+ }
+ return setAutoCommit(true);
+}
+
+bool QDB2Driver::rollbackTransaction()
+{
+ Q_D(QDB2Driver);
+ if (!isOpen()) {
+ qWarning("QDB2Driver::rollbackTransaction: Database not open");
+ return false;
+ }
+ SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
+ d->hDbc,
+ SQL_ROLLBACK);
+ if (r != SQL_SUCCESS) {
+ setLastError(qMakeError(tr("Unable to rollback transaction"),
+ QSqlError::TransactionError, d));
+ return false;
+ }
+ return setAutoCommit(true);
+}
+
+bool QDB2Driver::setAutoCommit(bool autoCommit)
+{
+ Q_D(QDB2Driver);
+ SQLUINTEGER ac = autoCommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
+ SQLRETURN r = SQLSetConnectAttr(d->hDbc,
+ SQL_ATTR_AUTOCOMMIT,
+ reinterpret_cast<SQLPOINTER>(ac),
+ sizeof(ac));
+ if (r != SQL_SUCCESS) {
+ setLastError(qMakeError(tr("Unable to set autocommit"),
+ QSqlError::TransactionError, d));
+ return false;
+ }
+ return true;
+}
+
+QString QDB2Driver::formatValue(const QSqlField &field, bool trimStrings) const
+{
+ if (field.isNull())
+ return QLatin1String("NULL");
+
+ switch (field.type()) {
+ case QVariant::DateTime: {
+ // Use an escape sequence for the datetime fields
+ if (field.value().toDateTime().isValid()) {
+ QDate dt = field.value().toDateTime().date();
+ QTime tm = field.value().toDateTime().time();
+ // Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10
+ return QLatin1Char('\'') + QString::number(dt.year()) + QLatin1Char('-')
+ + QString::number(dt.month()) + QLatin1Char('-')
+ + QString::number(dt.day()) + QLatin1Char('-')
+ + QString::number(tm.hour()) + QLatin1Char('.')
+ + QString::number(tm.minute()).rightJustified(2, QLatin1Char('0'), true)
+ + QLatin1Char('.')
+ + QString::number(tm.second()).rightJustified(2, QLatin1Char('0'), true)
+ + QLatin1Char('.')
+ + QString::number(tm.msec() * 1000).rightJustified(6, QLatin1Char('0'), true)
+ + QLatin1Char('\'');
+ } else {
+ return QLatin1String("NULL");
+ }
+ }
+ case QVariant::ByteArray: {
+ QByteArray ba = field.value().toByteArray();
+ QString res = QString::fromLatin1("BLOB(X'");
+ static const char hexchars[] = "0123456789abcdef";
+ for (int i = 0; i < ba.size(); ++i) {
+ uchar s = (uchar) ba[i];
+ res += QLatin1Char(hexchars[s >> 4]);
+ res += QLatin1Char(hexchars[s & 0x0f]);
+ }
+ res += QLatin1String("')");
+ return res;
+ }
+ default:
+ return QSqlDriver::formatValue(field, trimStrings);
+ }
+}
+
+QVariant QDB2Driver::handle() const
+{
+ Q_D(const QDB2Driver);
+ return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hDbc);
+}
+
+QString QDB2Driver::escapeIdentifier(const QString &identifier, IdentifierType) const
+{
+ QString res = identifier;
+ if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
+ res.replace(QLatin1Char('"'), QLatin1String("\"\""));
+ res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
+ res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ }
+ return res;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/db2/qsql_db2_p.h b/src/plugins/sqldrivers/db2/qsql_db2_p.h
new file mode 100644
index 0000000000..fa6d739479
--- /dev/null
+++ b/src/plugins/sqldrivers/db2/qsql_db2_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSQL_DB2_H
+#define QSQL_DB2_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#ifdef QT_PLUGIN
+#define Q_EXPORT_SQLDRIVER_DB2
+#else
+#define Q_EXPORT_SQLDRIVER_DB2 Q_SQL_EXPORT
+#endif
+
+#include <QtSql/qsqldriver.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDB2DriverPrivate;
+
+class Q_EXPORT_SQLDRIVER_DB2 QDB2Driver : public QSqlDriver
+{
+ Q_DECLARE_PRIVATE(QDB2Driver)
+ Q_OBJECT
+ friend class QDB2ResultPrivate;
+
+public:
+ explicit QDB2Driver(QObject* parent = 0);
+ QDB2Driver(Qt::HANDLE env, Qt::HANDLE con, QObject* parent = 0);
+ ~QDB2Driver();
+ bool hasFeature(DriverFeature) const Q_DECL_OVERRIDE;
+ void close() Q_DECL_OVERRIDE;
+ QSqlRecord record(const QString &tableName) const Q_DECL_OVERRIDE;
+ QStringList tables(QSql::TableType type) const Q_DECL_OVERRIDE;
+ QSqlResult *createResult() const Q_DECL_OVERRIDE;
+ QSqlIndex primaryIndex(const QString &tablename) const Q_DECL_OVERRIDE;
+ bool beginTransaction() Q_DECL_OVERRIDE;
+ bool commitTransaction() Q_DECL_OVERRIDE;
+ bool rollbackTransaction() Q_DECL_OVERRIDE;
+ QString formatValue(const QSqlField &field, bool trimStrings) const Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+ bool open(const QString &db,
+ const QString &user,
+ const QString &password,
+ const QString &host,
+ int port,
+ const QString& connOpts) Q_DECL_OVERRIDE;
+ QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
+
+private:
+ bool setAutoCommit(bool autoCommit);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQL_DB2_H
diff --git a/src/plugins/sqldrivers/ibase/ibase.pro b/src/plugins/sqldrivers/ibase/ibase.pro
index 1f29597a2b..8237245183 100644
--- a/src/plugins/sqldrivers/ibase/ibase.pro
+++ b/src/plugins/sqldrivers/ibase/ibase.pro
@@ -1,8 +1,17 @@
TARGET = qsqlibase
-SOURCES = main.cpp
+HEADERS += $$PWD/qsql_ibase_p.h
+SOURCES += $$PWD/qsql_ibase.cpp $$PWD/main.cpp
+
+unix {
+ !contains(LIBS, .*gds.*):!contains(LIBS, .*libfb.*):LIBS += -lgds
+} else {
+ !contains(LIBS, .*gds.*):!contains(LIBS, .*fbclient.*) {
+ LIBS += -lgds32_ms
+ }
+}
+
OTHER_FILES += ibase.json
-include(../../../sql/drivers/ibase/qsql_ibase.pri)
PLUGIN_CLASS_NAME = QIBaseDriverPlugin
include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/ibase/main.cpp b/src/plugins/sqldrivers/ibase/main.cpp
index c6f0b785de..8d462afcdc 100644
--- a/src/plugins/sqldrivers/ibase/main.cpp
+++ b/src/plugins/sqldrivers/ibase/main.cpp
@@ -39,7 +39,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/ibase/qsql_ibase_p.h"
+#include "qsql_ibase_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
new file mode 100644
index 0000000000..6fd91b6b76
--- /dev/null
+++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
@@ -0,0 +1,1948 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsql_ibase_p.h"
+#include <qcoreapplication.h>
+#include <qdatetime.h>
+#include <qvariant.h>
+#include <qsqlerror.h>
+#include <qsqlfield.h>
+#include <qsqlindex.h>
+#include <qsqlquery.h>
+#include <QtSql/private/qsqlcachedresult_p.h>
+#include <QtSql/private/qsqldriver_p.h>
+#include <qlist.h>
+#include <qvector.h>
+#include <qtextcodec.h>
+#include <qmutex.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <math.h>
+#include <qdebug.h>
+#include <QVarLengthArray>
+
+QT_BEGIN_NAMESPACE
+
+#define FBVERSION SQL_DIALECT_V6
+
+#ifndef SQLDA_CURRENT_VERSION
+#define SQLDA_CURRENT_VERSION SQLDA_VERSION1
+#endif
+
+enum { QIBaseChunkSize = SHRT_MAX / 2 };
+
+#if defined(FB_API_VER) && FB_API_VER >= 20
+static bool getIBaseError(QString& msg, const ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc)
+#else
+static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc)
+#endif
+{
+ if (status[0] != 1 || status[1] <= 0)
+ return false;
+
+ msg.clear();
+ sqlcode = isc_sqlcode(status);
+ char buf[512];
+#if defined(FB_API_VER) && FB_API_VER >= 20
+ while(fb_interpret(buf, 512, &status)) {
+#else
+ while(isc_interprete(buf, &status)) {
+#endif
+ if(!msg.isEmpty())
+ msg += QLatin1String(" - ");
+ if (tc)
+ msg += tc->toUnicode(buf);
+ else
+ msg += QString::fromUtf8(buf);
+ }
+ return true;
+}
+
+static void createDA(XSQLDA *&sqlda)
+{
+ sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(1));
+ if (sqlda == (XSQLDA*)0) return;
+ sqlda->sqln = 1;
+ sqlda->sqld = 0;
+ sqlda->version = SQLDA_CURRENT_VERSION;
+ sqlda->sqlvar[0].sqlind = 0;
+ sqlda->sqlvar[0].sqldata = 0;
+}
+
+static void enlargeDA(XSQLDA *&sqlda, int n)
+{
+ if (sqlda != (XSQLDA*)0)
+ free(sqlda);
+ sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(n));
+ if (sqlda == (XSQLDA*)0) return;
+ sqlda->sqln = n;
+ sqlda->version = SQLDA_CURRENT_VERSION;
+}
+
+static void initDA(XSQLDA *sqlda)
+{
+ for (int i = 0; i < sqlda->sqld; ++i) {
+ switch (sqlda->sqlvar[i].sqltype & ~1) {
+ case SQL_INT64:
+ case SQL_LONG:
+ case SQL_SHORT:
+ case SQL_FLOAT:
+ case SQL_DOUBLE:
+ case SQL_TIMESTAMP:
+ case SQL_TYPE_TIME:
+ case SQL_TYPE_DATE:
+ case SQL_TEXT:
+ case SQL_BLOB:
+ sqlda->sqlvar[i].sqldata = new char[sqlda->sqlvar[i].sqllen];
+ break;
+ case SQL_ARRAY:
+ sqlda->sqlvar[i].sqldata = new char[sizeof(ISC_QUAD)];
+ memset(sqlda->sqlvar[i].sqldata, 0, sizeof(ISC_QUAD));
+ break;
+ case SQL_VARYING:
+ sqlda->sqlvar[i].sqldata = new char[sqlda->sqlvar[i].sqllen + sizeof(short)];
+ break;
+ default:
+ // not supported - do not bind.
+ sqlda->sqlvar[i].sqldata = 0;
+ break;
+ }
+ if (sqlda->sqlvar[i].sqltype & 1) {
+ sqlda->sqlvar[i].sqlind = new short[1];
+ *(sqlda->sqlvar[i].sqlind) = 0;
+ } else {
+ sqlda->sqlvar[i].sqlind = 0;
+ }
+ }
+}
+
+static void delDA(XSQLDA *&sqlda)
+{
+ if (!sqlda)
+ return;
+ for (int i = 0; i < sqlda->sqld; ++i) {
+ delete [] sqlda->sqlvar[i].sqlind;
+ delete [] sqlda->sqlvar[i].sqldata;
+ }
+ free(sqlda);
+ sqlda = 0;
+}
+
+static QVariant::Type qIBaseTypeName(int iType, bool hasScale)
+{
+ switch (iType) {
+ case blr_varying:
+ case blr_varying2:
+ case blr_text:
+ case blr_cstring:
+ case blr_cstring2:
+ return QVariant::String;
+ case blr_sql_time:
+ return QVariant::Time;
+ case blr_sql_date:
+ return QVariant::Date;
+ case blr_timestamp:
+ return QVariant::DateTime;
+ case blr_blob:
+ return QVariant::ByteArray;
+ case blr_quad:
+ case blr_short:
+ case blr_long:
+ return (hasScale ? QVariant::Double : QVariant::Int);
+ case blr_int64:
+ return (hasScale ? QVariant::Double : QVariant::LongLong);
+ case blr_float:
+ case blr_d_float:
+ case blr_double:
+ return QVariant::Double;
+ }
+ qWarning("qIBaseTypeName: unknown datatype: %d", iType);
+ return QVariant::Invalid;
+}
+
+static QVariant::Type qIBaseTypeName2(int iType, bool hasScale)
+{
+ switch(iType & ~1) {
+ case SQL_VARYING:
+ case SQL_TEXT:
+ return QVariant::String;
+ case SQL_LONG:
+ case SQL_SHORT:
+ return (hasScale ? QVariant::Double : QVariant::Int);
+ case SQL_INT64:
+ return (hasScale ? QVariant::Double : QVariant::LongLong);
+ case SQL_FLOAT:
+ case SQL_DOUBLE:
+ return QVariant::Double;
+ case SQL_TIMESTAMP:
+ return QVariant::DateTime;
+ case SQL_TYPE_TIME:
+ return QVariant::Time;
+ case SQL_TYPE_DATE:
+ return QVariant::Date;
+ case SQL_ARRAY:
+ return QVariant::List;
+ case SQL_BLOB:
+ return QVariant::ByteArray;
+ default:
+ return QVariant::Invalid;
+ }
+}
+
+static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt)
+{
+ static const QTime midnight(0, 0, 0, 0);
+ static const QDate basedate(1858, 11, 17);
+ ISC_TIMESTAMP ts;
+ ts.timestamp_time = midnight.msecsTo(dt.time()) * 10;
+ ts.timestamp_date = basedate.daysTo(dt.date());
+ return ts;
+}
+
+static QDateTime fromTimeStamp(char *buffer)
+{
+ static const QDate bd(1858, 11, 17);
+ QTime t(0, 0);
+ QDate d;
+
+ // have to demangle the structure ourselves because isc_decode_time
+ // strips the msecs
+ t = t.addMSecs(int(((ISC_TIMESTAMP*)buffer)->timestamp_time / 10));
+ d = bd.addDays(int(((ISC_TIMESTAMP*)buffer)->timestamp_date));
+
+ return QDateTime(d, t);
+}
+
+static ISC_TIME toTime(const QTime &t)
+{
+ static const QTime midnight(0, 0, 0, 0);
+ return (ISC_TIME)midnight.msecsTo(t) * 10;
+}
+
+static QTime fromTime(char *buffer)
+{
+ QTime t(0, 0);
+ // have to demangle the structure ourselves because isc_decode_time
+ // strips the msecs
+ t = t.addMSecs(int((*(ISC_TIME*)buffer) / 10));
+
+ return t;
+}
+
+static ISC_DATE toDate(const QDate &t)
+{
+ static const QDate basedate(1858, 11, 17);
+ ISC_DATE date;
+
+ date = basedate.daysTo(t);
+ return date;
+}
+
+static QDate fromDate(char *buffer)
+{
+ static const QDate bd(1858, 11, 17);
+ QDate d;
+
+ // have to demangle the structure ourselves because isc_decode_time
+ // strips the msecs
+ d = bd.addDays(int(((ISC_TIMESTAMP*)buffer)->timestamp_date));
+
+ return d;
+}
+
+static QByteArray encodeString(QTextCodec *tc, const QString &str)
+{
+ if (tc)
+ return tc->fromUnicode(str);
+ return str.toUtf8();
+}
+
+struct QIBaseEventBuffer {
+#if defined(FB_API_VER) && FB_API_VER >= 20
+ ISC_UCHAR *eventBuffer;
+ ISC_UCHAR *resultBuffer;
+#else
+ char *eventBuffer;
+ char *resultBuffer;
+#endif
+ ISC_LONG bufferLength;
+ ISC_LONG eventId;
+
+ enum QIBaseSubscriptionState { Starting, Subscribed, Finished };
+ QIBaseSubscriptionState subscriptionState;
+};
+
+class QIBaseDriverPrivate : public QSqlDriverPrivate
+{
+ Q_DECLARE_PUBLIC(QIBaseDriver)
+public:
+ QIBaseDriverPrivate() : QSqlDriverPrivate(), ibase(0), trans(0), tc(0) { dbmsType = QSqlDriver::Interbase; }
+
+ bool isError(const char *msg, QSqlError::ErrorType typ = QSqlError::UnknownError)
+ {
+ Q_Q(QIBaseDriver);
+ QString imsg;
+ ISC_LONG sqlcode;
+ if (!getIBaseError(imsg, status, sqlcode, tc))
+ return false;
+
+ q->setLastError(QSqlError(QCoreApplication::translate("QIBaseDriver", msg),
+ imsg, typ, int(sqlcode)));
+ return true;
+ }
+
+public:
+ isc_db_handle ibase;
+ isc_tr_handle trans;
+ QTextCodec *tc;
+ ISC_STATUS status[20];
+ QMap<QString, QIBaseEventBuffer*> eventBuffers;
+};
+
+typedef QMap<void *, QIBaseDriver *> QIBaseBufferDriverMap;
+Q_GLOBAL_STATIC(QIBaseBufferDriverMap, qBufferDriverMap)
+Q_GLOBAL_STATIC(QMutex, qMutex);
+
+static void qFreeEventBuffer(QIBaseEventBuffer* eBuffer)
+{
+ qMutex()->lock();
+ qBufferDriverMap()->remove(reinterpret_cast<void *>(eBuffer->resultBuffer));
+ qMutex()->unlock();
+ delete eBuffer;
+}
+
+class QIBaseResultPrivate;
+
+class QIBaseResult : public QSqlCachedResult
+{
+ Q_DECLARE_PRIVATE(QIBaseResult)
+
+public:
+ explicit QIBaseResult(const QIBaseDriver* db);
+
+ bool prepare(const QString &query) Q_DECL_OVERRIDE;
+ bool exec() Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+
+protected:
+ bool gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx) Q_DECL_OVERRIDE;
+ bool reset (const QString &query) Q_DECL_OVERRIDE;
+ int size() Q_DECL_OVERRIDE;
+ int numRowsAffected() Q_DECL_OVERRIDE;
+ QSqlRecord record() const Q_DECL_OVERRIDE;
+};
+
+class QIBaseResultPrivate: public QSqlCachedResultPrivate
+{
+ Q_DECLARE_PUBLIC(QIBaseResult)
+
+public:
+ Q_DECLARE_SQLDRIVER_PRIVATE(QIBaseDriver)
+
+ QIBaseResultPrivate(QIBaseResult *q, const QIBaseDriver *drv);
+ ~QIBaseResultPrivate() { cleanup(); }
+
+ void cleanup();
+ bool isError(const char *msg, QSqlError::ErrorType typ = QSqlError::UnknownError)
+ {
+ Q_Q(QIBaseResult);
+ QString imsg;
+ ISC_LONG sqlcode;
+ if (!getIBaseError(imsg, status, sqlcode, tc))
+ return false;
+
+ q->setLastError(QSqlError(QCoreApplication::translate("QIBaseResult", msg),
+ imsg, typ, int(sqlcode)));
+ return true;
+ }
+
+ bool transaction();
+ bool commit();
+
+ bool isSelect();
+ QVariant fetchBlob(ISC_QUAD *bId);
+ bool writeBlob(int i, const QByteArray &ba);
+ QVariant fetchArray(int pos, ISC_QUAD *arr);
+ bool writeArray(int i, const QList<QVariant> &list);
+
+public:
+ ISC_STATUS status[20];
+ isc_tr_handle trans;
+ //indicator whether we have a local transaction or a transaction on driver level
+ bool localTransaction;
+ isc_stmt_handle stmt;
+ isc_db_handle ibase;
+ XSQLDA *sqlda; // output sqlda
+ XSQLDA *inda; // input parameters
+ int queryType;
+ QTextCodec *tc;
+};
+
+
+QIBaseResultPrivate::QIBaseResultPrivate(QIBaseResult *q, const QIBaseDriver *drv)
+ : QSqlCachedResultPrivate(q, drv),
+ trans(0),
+ localTransaction(!drv_d_func()->ibase),
+ stmt(0),
+ ibase(drv_d_func()->ibase),
+ sqlda(0),
+ inda(0),
+ queryType(-1),
+ tc(drv_d_func()->tc)
+{
+}
+
+void QIBaseResultPrivate::cleanup()
+{
+ Q_Q(QIBaseResult);
+ commit();
+ if (!localTransaction)
+ trans = 0;
+
+ if (stmt) {
+ isc_dsql_free_statement(status, &stmt, DSQL_drop);
+ stmt = 0;
+ }
+
+ delDA(sqlda);
+ delDA(inda);
+
+ queryType = -1;
+ q->cleanup();
+}
+
+bool QIBaseResultPrivate::writeBlob(int i, const QByteArray &ba)
+{
+ isc_blob_handle handle = 0;
+ ISC_QUAD *bId = (ISC_QUAD*)inda->sqlvar[i].sqldata;
+ isc_create_blob2(status, &ibase, &trans, &handle, bId, 0, 0);
+ if (!isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to create BLOB"),
+ QSqlError::StatementError)) {
+ int i = 0;
+ while (i < ba.size()) {
+ isc_put_segment(status, &handle, qMin(ba.size() - i, int(QIBaseChunkSize)),
+ const_cast<char*>(ba.data()) + i);
+ if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to write BLOB")))
+ return false;
+ i += qMin(ba.size() - i, int(QIBaseChunkSize));
+ }
+ }
+ isc_close_blob(status, &handle);
+ return true;
+}
+
+QVariant QIBaseResultPrivate::fetchBlob(ISC_QUAD *bId)
+{
+ isc_blob_handle handle = 0;
+
+ isc_open_blob2(status, &ibase, &trans, &handle, bId, 0, 0);
+ if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to open BLOB"),
+ QSqlError::StatementError))
+ return QVariant();
+
+ unsigned short len = 0;
+ QByteArray ba;
+ int chunkSize = QIBaseChunkSize;
+ ba.resize(chunkSize);
+ int read = 0;
+ while (isc_get_segment(status, &handle, &len, chunkSize, ba.data() + read) == 0 || status[1] == isc_segment) {
+ read += len;
+ ba.resize(read + chunkSize);
+ }
+ ba.resize(read);
+
+ bool isErr = (status[1] == isc_segstr_eof ? false :
+ isError(QT_TRANSLATE_NOOP("QIBaseResult",
+ "Unable to read BLOB"),
+ QSqlError::StatementError));
+
+ isc_close_blob(status, &handle);
+
+ if (isErr)
+ return QVariant();
+
+ ba.resize(read);
+ return ba;
+}
+
+template<typename T>
+static QList<QVariant> toList(char** buf, int count, T* = 0)
+{
+ QList<QVariant> res;
+ for (int i = 0; i < count; ++i) {
+ res.append(*(T*)(*buf));
+ *buf += sizeof(T);
+ }
+ return res;
+}
+/* char** ? seems like bad influence from oracle ... */
+template<>
+QList<QVariant> toList<long>(char** buf, int count, long*)
+{
+ QList<QVariant> res;
+ for (int i = 0; i < count; ++i) {
+ if (sizeof(int) == sizeof(long))
+ res.append(int((*(long*)(*buf))));
+ else
+ res.append((qint64)(*(long*)(*buf)));
+ *buf += sizeof(long);
+ }
+ return res;
+}
+
+static char* readArrayBuffer(QList<QVariant>& list, char *buffer, short curDim,
+ short* numElements, ISC_ARRAY_DESC *arrayDesc,
+ QTextCodec *tc)
+{
+ const short dim = arrayDesc->array_desc_dimensions - 1;
+ const unsigned char dataType = arrayDesc->array_desc_dtype;
+ QList<QVariant> valList;
+ unsigned short strLen = arrayDesc->array_desc_length;
+
+ if (curDim != dim) {
+ for(int i = 0; i < numElements[curDim]; ++i)
+ buffer = readArrayBuffer(list, buffer, curDim + 1, numElements,
+ arrayDesc, tc);
+ } else {
+ switch(dataType) {
+ case blr_varying:
+ case blr_varying2:
+ strLen += 2; // for the two terminating null values
+ case blr_text:
+ case blr_text2: {
+ int o;
+ for (int i = 0; i < numElements[dim]; ++i) {
+ for(o = 0; o < strLen && buffer[o]!=0; ++o )
+ ;
+
+ if (tc)
+ valList.append(tc->toUnicode(buffer, o));
+ else
+ valList.append(QString::fromUtf8(buffer, o));
+
+ buffer += strLen;
+ }
+ break; }
+ case blr_long:
+ valList = toList<long>(&buffer, numElements[dim], static_cast<long *>(0));
+ break;
+ case blr_short:
+ valList = toList<short>(&buffer, numElements[dim]);
+ break;
+ case blr_int64:
+ valList = toList<qint64>(&buffer, numElements[dim]);
+ break;
+ case blr_float:
+ valList = toList<float>(&buffer, numElements[dim]);
+ break;
+ case blr_double:
+ valList = toList<double>(&buffer, numElements[dim]);
+ break;
+ case blr_timestamp:
+ for(int i = 0; i < numElements[dim]; ++i) {
+ valList.append(fromTimeStamp(buffer));
+ buffer += sizeof(ISC_TIMESTAMP);
+ }
+ break;
+ case blr_sql_time:
+ for(int i = 0; i < numElements[dim]; ++i) {
+ valList.append(fromTime(buffer));
+ buffer += sizeof(ISC_TIME);
+ }
+ break;
+ case blr_sql_date:
+ for(int i = 0; i < numElements[dim]; ++i) {
+ valList.append(fromDate(buffer));
+ buffer += sizeof(ISC_DATE);
+ }
+ break;
+ }
+ }
+ if (dim > 0)
+ list.append(valList);
+ else
+ list += valList;
+ return buffer;
+}
+
+QVariant QIBaseResultPrivate::fetchArray(int pos, ISC_QUAD *arr)
+{
+ QList<QVariant> list;
+ ISC_ARRAY_DESC desc;
+
+ if (!arr)
+ return list;
+
+ QByteArray relname(sqlda->sqlvar[pos].relname, sqlda->sqlvar[pos].relname_length);
+ QByteArray sqlname(sqlda->sqlvar[pos].aliasname, sqlda->sqlvar[pos].aliasname_length);
+
+ isc_array_lookup_bounds(status, &ibase, &trans, relname.data(), sqlname.data(), &desc);
+ if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not find array"),
+ QSqlError::StatementError))
+ return list;
+
+
+ int arraySize = 1, subArraySize;
+ short dimensions = desc.array_desc_dimensions;
+ QVarLengthArray<short> numElements(dimensions);
+
+ for(int i = 0; i < dimensions; ++i) {
+ subArraySize = (desc.array_desc_bounds[i].array_bound_upper -
+ desc.array_desc_bounds[i].array_bound_lower + 1);
+ numElements[i] = subArraySize;
+ arraySize = subArraySize * arraySize;
+ }
+
+ ISC_LONG bufLen;
+ QByteArray ba;
+ /* varying arrayelements are stored with 2 trailing null bytes
+ indicating the length of the string
+ */
+ if (desc.array_desc_dtype == blr_varying
+ || desc.array_desc_dtype == blr_varying2) {
+ desc.array_desc_length += 2;
+ bufLen = desc.array_desc_length * arraySize * sizeof(short);
+ } else {
+ bufLen = desc.array_desc_length * arraySize;
+ }
+
+
+ ba.resize(int(bufLen));
+ isc_array_get_slice(status, &ibase, &trans, arr, &desc, ba.data(), &bufLen);
+ if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not get array data"),
+ QSqlError::StatementError))
+ return list;
+
+ readArrayBuffer(list, ba.data(), 0, numElements.data(), &desc, tc);
+
+ return QVariant(list);
+}
+
+template<typename T>
+static char* fillList(char *buffer, const QList<QVariant> &list, T* = 0)
+{
+ for (int i = 0; i < list.size(); ++i) {
+ T val;
+ val = qvariant_cast<T>(list.at(i));
+ memcpy(buffer, &val, sizeof(T));
+ buffer += sizeof(T);
+ }
+ return buffer;
+}
+
+template<>
+char* fillList<float>(char *buffer, const QList<QVariant> &list, float*)
+{
+ for (int i = 0; i < list.size(); ++i) {
+ double val;
+ float val2 = 0;
+ val = qvariant_cast<double>(list.at(i));
+ val2 = (float)val;
+ memcpy(buffer, &val2, sizeof(float));
+ buffer += sizeof(float);
+ }
+ return buffer;
+}
+
+static char* qFillBufferWithString(char *buffer, const QString& string,
+ short buflen, bool varying, bool array,
+ QTextCodec *tc)
+{
+ QByteArray str = encodeString(tc, string); // keep a copy of the string alive in this scope
+ if (varying) {
+ short tmpBuflen = buflen;
+ if (str.length() < buflen)
+ buflen = str.length();
+ if (array) { // interbase stores varying arrayelements different than normal varying elements
+ memcpy(buffer, str.data(), buflen);
+ memset(buffer + buflen, 0, tmpBuflen - buflen);
+ } else {
+ *(short*)buffer = buflen; // first two bytes is the length
+ memcpy(buffer + sizeof(short), str.data(), buflen);
+ }
+ buffer += tmpBuflen;
+ } else {
+ str = str.leftJustified(buflen, ' ', true);
+ memcpy(buffer, str.data(), buflen);
+ buffer += buflen;
+ }
+ return buffer;
+}
+
+static char* createArrayBuffer(char *buffer, const QList<QVariant> &list,
+ QVariant::Type type, short curDim, ISC_ARRAY_DESC *arrayDesc,
+ QString& error, QTextCodec *tc)
+{
+ int i;
+ ISC_ARRAY_BOUND *bounds = arrayDesc->array_desc_bounds;
+ short dim = arrayDesc->array_desc_dimensions - 1;
+
+ int elements = (bounds[curDim].array_bound_upper -
+ bounds[curDim].array_bound_lower + 1);
+
+ if (list.size() != elements) { // size mismatch
+ error = QLatin1String("Expected size: %1. Supplied size: %2");
+ error = QLatin1String("Array size mismatch. Fieldname: %1 ")
+ + error.arg(elements).arg(list.size());
+ return 0;
+ }
+
+ if (curDim != dim) {
+ for(i = 0; i < list.size(); ++i) {
+
+ if (list.at(i).type() != QVariant::List) { // dimensions mismatch
+ error = QLatin1String("Array dimensons mismatch. Fieldname: %1");
+ return 0;
+ }
+
+ buffer = createArrayBuffer(buffer, list.at(i).toList(), type, curDim + 1,
+ arrayDesc, error, tc);
+ if (!buffer)
+ return 0;
+ }
+ } else {
+ switch(type) {
+ case QVariant::Int:
+ case QVariant::UInt:
+ if (arrayDesc->array_desc_dtype == blr_short)
+ buffer = fillList<short>(buffer, list);
+ else
+ buffer = fillList<int>(buffer, list);
+ break;
+ case QVariant::Double:
+ if (arrayDesc->array_desc_dtype == blr_float)
+ buffer = fillList<float>(buffer, list, static_cast<float *>(0));
+ else
+ buffer = fillList<double>(buffer, list);
+ break;
+ case QVariant::LongLong:
+ buffer = fillList<qint64>(buffer, list);
+ break;
+ case QVariant::ULongLong:
+ buffer = fillList<quint64>(buffer, list);
+ break;
+ case QVariant::String:
+ for (i = 0; i < list.size(); ++i)
+ buffer = qFillBufferWithString(buffer, list.at(i).toString(),
+ arrayDesc->array_desc_length,
+ arrayDesc->array_desc_dtype == blr_varying,
+ true, tc);
+ break;
+ case QVariant::Date:
+ for (i = 0; i < list.size(); ++i) {
+ *((ISC_DATE*)buffer) = toDate(list.at(i).toDate());
+ buffer += sizeof(ISC_DATE);
+ }
+ break;
+ case QVariant::Time:
+ for (i = 0; i < list.size(); ++i) {
+ *((ISC_TIME*)buffer) = toTime(list.at(i).toTime());
+ buffer += sizeof(ISC_TIME);
+ }
+ break;
+
+ case QVariant::DateTime:
+ for (i = 0; i < list.size(); ++i) {
+ *((ISC_TIMESTAMP*)buffer) = toTimeStamp(list.at(i).toDateTime());
+ buffer += sizeof(ISC_TIMESTAMP);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return buffer;
+}
+
+bool QIBaseResultPrivate::writeArray(int column, const QList<QVariant> &list)
+{
+ Q_Q(QIBaseResult);
+ QString error;
+ ISC_QUAD *arrayId = (ISC_QUAD*) inda->sqlvar[column].sqldata;
+ ISC_ARRAY_DESC desc;
+
+ QByteArray relname(inda->sqlvar[column].relname, inda->sqlvar[column].relname_length);
+ QByteArray sqlname(inda->sqlvar[column].aliasname, inda->sqlvar[column].aliasname_length);
+
+ isc_array_lookup_bounds(status, &ibase, &trans, relname.data(), sqlname.data(), &desc);
+ if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not find array"),
+ QSqlError::StatementError))
+ return false;
+
+ short arraySize = 1;
+ ISC_LONG bufLen;
+ QList<QVariant> subList = list;
+
+ short dimensions = desc.array_desc_dimensions;
+ for(int i = 0; i < dimensions; ++i) {
+ arraySize *= (desc.array_desc_bounds[i].array_bound_upper -
+ desc.array_desc_bounds[i].array_bound_lower + 1);
+ }
+
+ /* varying arrayelements are stored with 2 trailing null bytes
+ indicating the length of the string
+ */
+ if (desc.array_desc_dtype == blr_varying ||
+ desc.array_desc_dtype == blr_varying2)
+ desc.array_desc_length += 2;
+
+ bufLen = desc.array_desc_length * arraySize;
+ QByteArray ba;
+ ba.resize(int(bufLen));
+
+ if (list.size() > arraySize) {
+ error = QLatin1String("Array size missmatch: size of %1 is %2, size of provided list is %3");
+ error = error.arg(QLatin1String(sqlname)).arg(arraySize).arg(list.size());
+ q->setLastError(QSqlError(error, QLatin1String(""), QSqlError::StatementError));
+ return false;
+ }
+
+ if (!createArrayBuffer(ba.data(), list,
+ qIBaseTypeName(desc.array_desc_dtype, inda->sqlvar[column].sqlscale < 0),
+ 0, &desc, error, tc)) {
+ q->setLastError(QSqlError(error.arg(QLatin1String(sqlname)), QLatin1String(""),
+ QSqlError::StatementError));
+ return false;
+ }
+
+ /* readjust the buffer size*/
+ if (desc.array_desc_dtype == blr_varying
+ || desc.array_desc_dtype == blr_varying2)
+ desc.array_desc_length -= 2;
+
+ isc_array_put_slice(status, &ibase, &trans, arrayId, &desc, ba.data(), &bufLen);
+ return true;
+}
+
+
+bool QIBaseResultPrivate::isSelect()
+{
+ char acBuffer[9];
+ char qType = isc_info_sql_stmt_type;
+ isc_dsql_sql_info(status, &stmt, 1, &qType, sizeof(acBuffer), acBuffer);
+ if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not get query info"),
+ QSqlError::StatementError))
+ return false;
+ int iLength = isc_vax_integer(&acBuffer[1], 2);
+ queryType = isc_vax_integer(&acBuffer[3], iLength);
+ return (queryType == isc_info_sql_stmt_select || queryType == isc_info_sql_stmt_exec_procedure);
+}
+
+bool QIBaseResultPrivate::transaction()
+{
+ if (trans)
+ return true;
+ if (drv_d_func()->trans) {
+ localTransaction = false;
+ trans = drv_d_func()->trans;
+ return true;
+ }
+ localTransaction = true;
+
+ isc_start_transaction(status, &trans, 1, &ibase, 0, NULL);
+ if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not start transaction"),
+ QSqlError::TransactionError))
+ return false;
+
+ return true;
+}
+
+// does nothing if the transaction is on the
+// driver level
+bool QIBaseResultPrivate::commit()
+{
+ if (!trans)
+ return false;
+ // don't commit driver's transaction, the driver will do it for us
+ if (!localTransaction)
+ return true;
+
+ isc_commit_transaction(status, &trans);
+ trans = 0;
+ return !isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to commit transaction"),
+ QSqlError::TransactionError);
+}
+
+//////////
+
+QIBaseResult::QIBaseResult(const QIBaseDriver *db)
+ : QSqlCachedResult(*new QIBaseResultPrivate(this, db))
+{
+}
+
+bool QIBaseResult::prepare(const QString& query)
+{
+ Q_D(QIBaseResult);
+// qDebug("prepare: %s", qPrintable(query));
+ if (!driver() || !driver()->isOpen() || driver()->isOpenError())
+ return false;
+ d->cleanup();
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+
+ createDA(d->sqlda);
+ if (d->sqlda == (XSQLDA*)0) {
+ qWarning()<<"QIOBaseResult: createDA(): failed to allocate memory";
+ return false;
+ }
+
+ createDA(d->inda);
+ if (d->inda == (XSQLDA*)0){
+ qWarning()<<"QIOBaseResult: createDA(): failed to allocate memory";
+ return false;
+ }
+
+ if (!d->transaction())
+ return false;
+
+ isc_dsql_allocate_statement(d->status, &d->ibase, &d->stmt);
+ if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not allocate statement"),
+ QSqlError::StatementError))
+ return false;
+ isc_dsql_prepare(d->status, &d->trans, &d->stmt, 0,
+ const_cast<char*>(encodeString(d->tc, query).constData()), FBVERSION, d->sqlda);
+ if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not prepare statement"),
+ QSqlError::StatementError))
+ return false;
+
+ isc_dsql_describe_bind(d->status, &d->stmt, FBVERSION, d->inda);
+ if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult",
+ "Could not describe input statement"), QSqlError::StatementError))
+ return false;
+ if (d->inda->sqld > d->inda->sqln) {
+ enlargeDA(d->inda, d->inda->sqld);
+ if (d->inda == (XSQLDA*)0) {
+ qWarning()<<"QIOBaseResult: enlargeDA(): failed to allocate memory";
+ return false;
+ }
+
+ isc_dsql_describe_bind(d->status, &d->stmt, FBVERSION, d->inda);
+ if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult",
+ "Could not describe input statement"), QSqlError::StatementError))
+ return false;
+ }
+ initDA(d->inda);
+ if (d->sqlda->sqld > d->sqlda->sqln) {
+ // need more field descriptors
+ enlargeDA(d->sqlda, d->sqlda->sqld);
+ if (d->sqlda == (XSQLDA*)0) {
+ qWarning()<<"QIOBaseResult: enlargeDA(): failed to allocate memory";
+ return false;
+ }
+
+ isc_dsql_describe(d->status, &d->stmt, FBVERSION, d->sqlda);
+ if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not describe statement"),
+ QSqlError::StatementError))
+ return false;
+ }
+ initDA(d->sqlda);
+
+ setSelect(d->isSelect());
+ if (!isSelect()) {
+ free(d->sqlda);
+ d->sqlda = 0;
+ }
+
+ return true;
+}
+
+
+bool QIBaseResult::exec()
+{
+ Q_D(QIBaseResult);
+ bool ok = true;
+
+ if (!d->trans)
+ d->transaction();
+
+ if (!driver() || !driver()->isOpen() || driver()->isOpenError())
+ return false;
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+
+ if (d->inda) {
+ QVector<QVariant>& values = boundValues();
+ int i;
+ if (values.count() > d->inda->sqld) {
+ qWarning("QIBaseResult::exec: Parameter mismatch, expected %d, got %d parameters",
+ d->inda->sqld, values.count());
+ return false;
+ }
+ int para = 0;
+ for (i = 0; i < values.count(); ++i) {
+ para = i;
+ if (!d->inda->sqlvar[para].sqldata)
+ // skip unknown datatypes
+ continue;
+ const QVariant val(values[i]);
+ if (d->inda->sqlvar[para].sqltype & 1) {
+ if (val.isNull()) {
+ // set null indicator
+ *(d->inda->sqlvar[para].sqlind) = -1;
+ // and set the value to 0, otherwise it would count as empty string.
+ // it seems to be working with just setting sqlind to -1
+ //*((char*)d->inda->sqlvar[para].sqldata) = 0;
+ continue;
+ }
+ // a value of 0 means non-null.
+ *(d->inda->sqlvar[para].sqlind) = 0;
+ }
+ switch(d->inda->sqlvar[para].sqltype & ~1) {
+ case SQL_INT64:
+ if (d->inda->sqlvar[para].sqlscale < 0)
+ *((qint64*)d->inda->sqlvar[para].sqldata) =
+ (qint64)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
+ else
+ *((qint64*)d->inda->sqlvar[para].sqldata) = val.toLongLong();
+ break;
+ case SQL_LONG:
+ if (d->inda->sqlvar[para].sqllen == 4) {
+ if (d->inda->sqlvar[para].sqlscale < 0)
+ *((qint32*)d->inda->sqlvar[para].sqldata) =
+ (qint32)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
+ else
+ *((qint32*)d->inda->sqlvar[para].sqldata) = (qint32)val.toInt();
+ } else {
+ *((qint64*)d->inda->sqlvar[para].sqldata) = val.toLongLong();
+ }
+ break;
+ case SQL_SHORT:
+ if (d->inda->sqlvar[para].sqlscale < 0)
+ *((short*)d->inda->sqlvar[para].sqldata) =
+ (short)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
+ else
+ *((short*)d->inda->sqlvar[para].sqldata) = (short)val.toInt();
+ break;
+ case SQL_FLOAT:
+ *((float*)d->inda->sqlvar[para].sqldata) = (float)val.toDouble();
+ break;
+ case SQL_DOUBLE:
+ *((double*)d->inda->sqlvar[para].sqldata) = val.toDouble();
+ break;
+ case SQL_TIMESTAMP:
+ *((ISC_TIMESTAMP*)d->inda->sqlvar[para].sqldata) = toTimeStamp(val.toDateTime());
+ break;
+ case SQL_TYPE_TIME:
+ *((ISC_TIME*)d->inda->sqlvar[para].sqldata) = toTime(val.toTime());
+ break;
+ case SQL_TYPE_DATE:
+ *((ISC_DATE*)d->inda->sqlvar[para].sqldata) = toDate(val.toDate());
+ break;
+ case SQL_VARYING:
+ case SQL_TEXT:
+ qFillBufferWithString(d->inda->sqlvar[para].sqldata, val.toString(),
+ d->inda->sqlvar[para].sqllen,
+ (d->inda->sqlvar[para].sqltype & ~1) == SQL_VARYING, false, d->tc);
+ break;
+ case SQL_BLOB:
+ ok &= d->writeBlob(para, val.toByteArray());
+ break;
+ case SQL_ARRAY:
+ ok &= d->writeArray(para, val.toList());
+ break;
+ default:
+ qWarning("QIBaseResult::exec: Unknown datatype %d",
+ d->inda->sqlvar[para].sqltype & ~1);
+ break;
+ }
+ }
+ }
+
+ if (ok) {
+ if (colCount() && d->queryType != isc_info_sql_stmt_exec_procedure) {
+ isc_dsql_free_statement(d->status, &d->stmt, DSQL_close);
+ if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to close statement")))
+ return false;
+ cleanup();
+ }
+ if (d->queryType == isc_info_sql_stmt_exec_procedure)
+ isc_dsql_execute2(d->status, &d->trans, &d->stmt, FBVERSION, d->inda, d->sqlda);
+ else
+ isc_dsql_execute(d->status, &d->trans, &d->stmt, FBVERSION, d->inda);
+ if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to execute query")))
+ return false;
+
+ // Not all stored procedures necessarily return values.
+ if (d->queryType == isc_info_sql_stmt_exec_procedure && d->sqlda && d->sqlda->sqld == 0)
+ delDA(d->sqlda);
+
+ if (d->sqlda)
+ init(d->sqlda->sqld);
+
+ if (!isSelect())
+ d->commit();
+
+ setActive(true);
+ return true;
+ }
+ return false;
+}
+
+bool QIBaseResult::reset (const QString& query)
+{
+ if (!prepare(query))
+ return false;
+ return exec();
+}
+
+bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
+{
+ Q_D(QIBaseResult);
+ ISC_STATUS stat = 0;
+
+ // Stored Procedures are special - they populate our d->sqlda when executing,
+ // so we don't have to call isc_dsql_fetch
+ if (d->queryType == isc_info_sql_stmt_exec_procedure) {
+ // the first "fetch" shall succeed, all consecutive ones will fail since
+ // we only have one row to fetch for stored procedures
+ if (rowIdx != 0)
+ stat = 100;
+ } else {
+ stat = isc_dsql_fetch(d->status, &d->stmt, FBVERSION, d->sqlda);
+ }
+
+ if (stat == 100) {
+ // no more rows
+ setAt(QSql::AfterLastRow);
+ return false;
+ }
+ if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not fetch next item"),
+ QSqlError::StatementError))
+ return false;
+ if (rowIdx < 0) // not interested in actual values
+ return true;
+
+ for (int i = 0; i < d->sqlda->sqld; ++i) {
+ int idx = rowIdx + i;
+ char *buf = d->sqlda->sqlvar[i].sqldata;
+ int size = d->sqlda->sqlvar[i].sqllen;
+ Q_ASSERT(buf);
+
+ if ((d->sqlda->sqlvar[i].sqltype & 1) && *d->sqlda->sqlvar[i].sqlind) {
+ // null value
+ QVariant v;
+ v.convert(qIBaseTypeName2(d->sqlda->sqlvar[i].sqltype, d->sqlda->sqlvar[i].sqlscale < 0));
+ if(v.type() == QVariant::Double) {
+ switch(numericalPrecisionPolicy()) {
+ case QSql::LowPrecisionInt32:
+ v.convert(QVariant::Int);
+ break;
+ case QSql::LowPrecisionInt64:
+ v.convert(QVariant::LongLong);
+ break;
+ case QSql::HighPrecision:
+ v.convert(QVariant::String);
+ break;
+ case QSql::LowPrecisionDouble:
+ // no conversion
+ break;
+ }
+ }
+ row[idx] = v;
+ continue;
+ }
+
+ switch(d->sqlda->sqlvar[i].sqltype & ~1) {
+ case SQL_VARYING:
+ // pascal strings - a short with a length information followed by the data
+ if (d->tc)
+ row[idx] = d->tc->toUnicode(buf + sizeof(short), *(short*)buf);
+ else
+ row[idx] = QString::fromUtf8(buf + sizeof(short), *(short*)buf);
+ break;
+ case SQL_INT64:
+ if (d->sqlda->sqlvar[i].sqlscale < 0)
+ row[idx] = *(qint64*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale);
+ else
+ row[idx] = QVariant(*(qint64*)buf);
+ break;
+ case SQL_LONG:
+ if (d->sqlda->sqlvar[i].sqllen == 4)
+ if (d->sqlda->sqlvar[i].sqlscale < 0)
+ row[idx] = QVariant(*(qint32*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale));
+ else
+ row[idx] = QVariant(*(qint32*)buf);
+ else
+ row[idx] = QVariant(*(qint64*)buf);
+ break;
+ case SQL_SHORT:
+ if (d->sqlda->sqlvar[i].sqlscale < 0)
+ row[idx] = QVariant(long((*(short*)buf)) * pow(10.0, d->sqlda->sqlvar[i].sqlscale));
+ else
+ row[idx] = QVariant(int((*(short*)buf)));
+ break;
+ case SQL_FLOAT:
+ row[idx] = QVariant(double((*(float*)buf)));
+ break;
+ case SQL_DOUBLE:
+ row[idx] = QVariant(*(double*)buf);
+ break;
+ case SQL_TIMESTAMP:
+ row[idx] = fromTimeStamp(buf);
+ break;
+ case SQL_TYPE_TIME:
+ row[idx] = fromTime(buf);
+ break;
+ case SQL_TYPE_DATE:
+ row[idx] = fromDate(buf);
+ break;
+ case SQL_TEXT:
+ if (d->tc)
+ row[idx] = d->tc->toUnicode(buf, size);
+ else
+ row[idx] = QString::fromUtf8(buf, size);
+ break;
+ case SQL_BLOB:
+ row[idx] = d->fetchBlob((ISC_QUAD*)buf);
+ break;
+ case SQL_ARRAY:
+ row[idx] = d->fetchArray(i, (ISC_QUAD*)buf);
+ break;
+ default:
+ // unknown type - don't even try to fetch
+ row[idx] = QVariant();
+ break;
+ }
+ if (d->sqlda->sqlvar[i].sqlscale < 0) {
+ QVariant v = row[idx];
+ switch(numericalPrecisionPolicy()) {
+ case QSql::LowPrecisionInt32:
+ if(v.convert(QVariant::Int))
+ row[idx]=v;
+ break;
+ case QSql::LowPrecisionInt64:
+ if(v.convert(QVariant::LongLong))
+ row[idx]=v;
+ break;
+ case QSql::LowPrecisionDouble:
+ if(v.convert(QVariant::Double))
+ row[idx]=v;
+ break;
+ case QSql::HighPrecision:
+ if(v.convert(QVariant::String))
+ row[idx]=v;
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+int QIBaseResult::size()
+{
+ return -1;
+
+#if 0 /// ### FIXME
+ static char sizeInfo[] = {isc_info_sql_records};
+ char buf[64];
+
+ //qDebug() << sizeInfo;
+ if (!isActive() || !isSelect())
+ return -1;
+
+ char ct;
+ short len;
+ int val = 0;
+// while(val == 0) {
+ isc_dsql_sql_info(d->status, &d->stmt, sizeof(sizeInfo), sizeInfo, sizeof(buf), buf);
+// isc_database_info(d->status, &d->ibase, sizeof(sizeInfo), sizeInfo, sizeof(buf), buf);
+
+ for(int i = 0; i < 66; ++i)
+ qDebug() << QString::number(buf[i]);
+
+ for (char* c = buf + 3; *c != isc_info_end; /*nothing*/) {
+ ct = *(c++);
+ len = isc_vax_integer(c, 2);
+ c += 2;
+ val = isc_vax_integer(c, len);
+ c += len;
+ qDebug() << "size" << val;
+ if (ct == isc_info_req_select_count)
+ return val;
+ }
+ //qDebug("size -1");
+ return -1;
+
+ unsigned int i, result_size;
+ if (buf[0] == isc_info_sql_records) {
+ i = 3;
+ result_size = isc_vax_integer(&buf[1],2);
+ while (buf[i] != isc_info_end && i < result_size) {
+ len = (short)isc_vax_integer(&buf[i+1],2);
+ if (buf[i] == isc_info_req_select_count)
+ return (isc_vax_integer(&buf[i+3],len));
+ i += len+3;
+ }
+ }
+// }
+ return -1;
+#endif
+}
+
+int QIBaseResult::numRowsAffected()
+{
+ Q_D(QIBaseResult);
+ static char acCountInfo[] = {isc_info_sql_records};
+ char cCountType;
+ bool bIsProcedure = false;
+
+ switch (d->queryType) {
+ case isc_info_sql_stmt_select:
+ cCountType = isc_info_req_select_count;
+ break;
+ case isc_info_sql_stmt_update:
+ cCountType = isc_info_req_update_count;
+ break;
+ case isc_info_sql_stmt_delete:
+ cCountType = isc_info_req_delete_count;
+ break;
+ case isc_info_sql_stmt_insert:
+ cCountType = isc_info_req_insert_count;
+ break;
+ case isc_info_sql_stmt_exec_procedure:
+ bIsProcedure = true; // will sum all changes
+ break;
+ default:
+ qWarning() << "numRowsAffected: Unknown statement type (" << d->queryType << ")";
+ return -1;
+ }
+
+ char acBuffer[33];
+ int iResult = -1;
+ isc_dsql_sql_info(d->status, &d->stmt, sizeof(acCountInfo), acCountInfo, sizeof(acBuffer), acBuffer);
+ if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not get statement info"),
+ QSqlError::StatementError))
+ return -1;
+ for (char *pcBuf = acBuffer + 3; *pcBuf != isc_info_end; /*nothing*/) {
+ char cType = *pcBuf++;
+ short sLength = isc_vax_integer (pcBuf, 2);
+ pcBuf += 2;
+ int iValue = isc_vax_integer (pcBuf, sLength);
+ pcBuf += sLength;
+ if (bIsProcedure) {
+ if (cType == isc_info_req_insert_count || cType == isc_info_req_update_count
+ || cType == isc_info_req_delete_count) {
+ if (iResult == -1)
+ iResult = 0;
+ iResult += iValue;
+ }
+ } else if (cType == cCountType) {
+ iResult = iValue;
+ break;
+ }
+ }
+ return iResult;
+}
+
+QSqlRecord QIBaseResult::record() const
+{
+ Q_D(const QIBaseResult);
+ QSqlRecord rec;
+ if (!isActive() || !d->sqlda)
+ return rec;
+
+ XSQLVAR v;
+ for (int i = 0; i < d->sqlda->sqld; ++i) {
+ v = d->sqlda->sqlvar[i];
+ QSqlField f(QString::fromLatin1(v.aliasname, v.aliasname_length).simplified(),
+ qIBaseTypeName2(v.sqltype, v.sqlscale < 0));
+ f.setLength(v.sqllen);
+ f.setPrecision(qAbs(v.sqlscale));
+ f.setRequiredStatus((v.sqltype & 1) == 0 ? QSqlField::Required : QSqlField::Optional);
+ if(v.sqlscale < 0) {
+ QSqlQuery q(driver()->createResult());
+ q.setForwardOnly(true);
+ q.exec(QLatin1String("select b.RDB$FIELD_PRECISION, b.RDB$FIELD_SCALE, b.RDB$FIELD_LENGTH, a.RDB$NULL_FLAG "
+ "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
+ "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
+ "AND a.RDB$RELATION_NAME = '") + QString::fromLatin1(v.relname, v.relname_length).toUpper() + QLatin1String("' "
+ "AND a.RDB$FIELD_NAME = '") + QString::fromLatin1(v.sqlname, v.sqlname_length).toUpper() + QLatin1String("' "));
+ if(q.first()) {
+ if(v.sqlscale < 0) {
+ f.setLength(q.value(0).toInt());
+ f.setPrecision(qAbs(q.value(1).toInt()));
+ } else {
+ f.setLength(q.value(2).toInt());
+ f.setPrecision(0);
+ }
+ f.setRequiredStatus(q.value(3).toBool() ? QSqlField::Required : QSqlField::Optional);
+ }
+ }
+ f.setSqlType(v.sqltype);
+ rec.append(f);
+ }
+ return rec;
+}
+
+QVariant QIBaseResult::handle() const
+{
+ Q_D(const QIBaseResult);
+ return QVariant(qRegisterMetaType<isc_stmt_handle>("isc_stmt_handle"), &d->stmt);
+}
+
+/*********************************/
+
+QIBaseDriver::QIBaseDriver(QObject * parent)
+ : QSqlDriver(*new QIBaseDriverPrivate, parent)
+{
+}
+
+QIBaseDriver::QIBaseDriver(isc_db_handle connection, QObject *parent)
+ : QSqlDriver(*new QIBaseDriverPrivate, parent)
+{
+ Q_D(QIBaseDriver);
+ d->ibase = connection;
+ setOpen(true);
+ setOpenError(false);
+}
+
+QIBaseDriver::~QIBaseDriver()
+{
+}
+
+bool QIBaseDriver::hasFeature(DriverFeature f) const
+{
+ switch (f) {
+ case QuerySize:
+ case NamedPlaceholders:
+ case LastInsertId:
+ case BatchOperations:
+ case SimpleLocking:
+ case FinishQuery:
+ case MultipleResultSets:
+ case CancelQuery:
+ return false;
+ case Transactions:
+ case PreparedQueries:
+ case PositionalPlaceholders:
+ case Unicode:
+ case BLOB:
+ case EventNotifications:
+ case LowPrecisionNumbers:
+ return true;
+ }
+ return false;
+}
+
+bool QIBaseDriver::open(const QString & db,
+ const QString & user,
+ const QString & password,
+ const QString & host,
+ int port,
+ const QString & connOpts)
+{
+ Q_D(QIBaseDriver);
+ if (isOpen())
+ close();
+
+ const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
+
+ QString encString;
+ QByteArray role;
+ for (int i = 0; i < opts.count(); ++i) {
+ QString tmp(opts.at(i).simplified());
+ int idx;
+ if ((idx = tmp.indexOf(QLatin1Char('='))) != -1) {
+ QString val = tmp.mid(idx + 1).simplified();
+ QString opt = tmp.left(idx).simplified();
+ if (opt.toUpper() == QLatin1String("ISC_DPB_LC_CTYPE"))
+ encString = val;
+ else if (opt.toUpper() == QLatin1String("ISC_DPB_SQL_ROLE_NAME")) {
+ role = val.toLocal8Bit();
+ role.truncate(255);
+ }
+ }
+ }
+
+ // Use UNICODE_FSS when no ISC_DPB_LC_CTYPE is provided
+ if (encString.isEmpty())
+ encString = QLatin1String("UNICODE_FSS");
+ else {
+ d->tc = QTextCodec::codecForName(encString.toLocal8Bit());
+ if (!d->tc) {
+ qWarning("Unsupported encoding: %s. Using UNICODE_FFS for ISC_DPB_LC_CTYPE.", encString.toLocal8Bit().constData());
+ encString = QLatin1String("UNICODE_FSS"); // Fallback to UNICODE_FSS
+ }
+ }
+
+ QByteArray enc = encString.toLocal8Bit();
+ QByteArray usr = user.toLocal8Bit();
+ QByteArray pass = password.toLocal8Bit();
+ enc.truncate(255);
+ usr.truncate(255);
+ pass.truncate(255);
+
+ QByteArray ba;
+ ba.reserve(usr.length() + pass.length() + enc.length() + role.length() + 9);
+ ba.append(char(isc_dpb_version1));
+ ba.append(char(isc_dpb_user_name));
+ ba.append(char(usr.length()));
+ ba.append(usr.data(), usr.length());
+ ba.append(char(isc_dpb_password));
+ ba.append(char(pass.length()));
+ ba.append(pass.data(), pass.length());
+ ba.append(char(isc_dpb_lc_ctype));
+ ba.append(char(enc.length()));
+ ba.append(enc.data(), enc.length());
+
+ if (!role.isEmpty()) {
+ ba.append(char(isc_dpb_sql_role_name));
+ ba.append(char(role.length()));
+ ba.append(role.data(), role.length());
+ }
+
+ QString portString;
+ if (port != -1)
+ portString = QStringLiteral("/%1").arg(port);
+
+ QString ldb;
+ if (!host.isEmpty())
+ ldb += host + portString + QLatin1Char(':');
+ ldb += db;
+ isc_attach_database(d->status, 0, const_cast<char *>(ldb.toLocal8Bit().constData()),
+ &d->ibase, ba.size(), ba.data());
+ if (d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Error opening database"),
+ QSqlError::ConnectionError)) {
+ setOpenError(true);
+ return false;
+ }
+
+ setOpen(true);
+ setOpenError(false);
+ return true;
+}
+
+void QIBaseDriver::close()
+{
+ Q_D(QIBaseDriver);
+ if (isOpen()) {
+
+ if (d->eventBuffers.size()) {
+ ISC_STATUS status[20];
+ QMap<QString, QIBaseEventBuffer *>::const_iterator i;
+ for (i = d->eventBuffers.constBegin(); i != d->eventBuffers.constEnd(); ++i) {
+ QIBaseEventBuffer *eBuffer = i.value();
+ eBuffer->subscriptionState = QIBaseEventBuffer::Finished;
+ isc_cancel_events(status, &d->ibase, &eBuffer->eventId);
+ qFreeEventBuffer(eBuffer);
+ }
+ d->eventBuffers.clear();
+
+#if defined(FB_API_VER)
+ // Workaround for Firebird crash
+ QTime timer;
+ timer.start();
+ while (timer.elapsed() < 500)
+ QCoreApplication::processEvents();
+#endif
+ }
+
+ isc_detach_database(d->status, &d->ibase);
+ d->ibase = 0;
+ setOpen(false);
+ setOpenError(false);
+ }
+}
+
+QSqlResult *QIBaseDriver::createResult() const
+{
+ return new QIBaseResult(this);
+}
+
+bool QIBaseDriver::beginTransaction()
+{
+ Q_D(QIBaseDriver);
+ if (!isOpen() || isOpenError())
+ return false;
+ if (d->trans)
+ return false;
+
+ isc_start_transaction(d->status, &d->trans, 1, &d->ibase, 0, NULL);
+ return !d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Could not start transaction"),
+ QSqlError::TransactionError);
+}
+
+bool QIBaseDriver::commitTransaction()
+{
+ Q_D(QIBaseDriver);
+ if (!isOpen() || isOpenError())
+ return false;
+ if (!d->trans)
+ return false;
+
+ isc_commit_transaction(d->status, &d->trans);
+ d->trans = 0;
+ return !d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Unable to commit transaction"),
+ QSqlError::TransactionError);
+}
+
+bool QIBaseDriver::rollbackTransaction()
+{
+ Q_D(QIBaseDriver);
+ if (!isOpen() || isOpenError())
+ return false;
+ if (!d->trans)
+ return false;
+
+ isc_rollback_transaction(d->status, &d->trans);
+ d->trans = 0;
+ return !d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Unable to rollback transaction"),
+ QSqlError::TransactionError);
+}
+
+QStringList QIBaseDriver::tables(QSql::TableType type) const
+{
+ QStringList res;
+ if (!isOpen())
+ return res;
+
+ QString typeFilter;
+
+ if (type == QSql::SystemTables) {
+ typeFilter += QLatin1String("RDB$SYSTEM_FLAG != 0");
+ } else if (type == (QSql::SystemTables | QSql::Views)) {
+ typeFilter += QLatin1String("RDB$SYSTEM_FLAG != 0 OR RDB$VIEW_BLR NOT NULL");
+ } else {
+ if (!(type & QSql::SystemTables))
+ typeFilter += QLatin1String("RDB$SYSTEM_FLAG = 0 AND ");
+ if (!(type & QSql::Views))
+ typeFilter += QLatin1String("RDB$VIEW_BLR IS NULL AND ");
+ if (!(type & QSql::Tables))
+ typeFilter += QLatin1String("RDB$VIEW_BLR IS NOT NULL AND ");
+ if (!typeFilter.isEmpty())
+ typeFilter.chop(5);
+ }
+ if (!typeFilter.isEmpty())
+ typeFilter.prepend(QLatin1String("where "));
+
+ QSqlQuery q(createResult());
+ q.setForwardOnly(true);
+ if (!q.exec(QLatin1String("select rdb$relation_name from rdb$relations ") + typeFilter))
+ return res;
+ while(q.next())
+ res << q.value(0).toString().simplified();
+
+ return res;
+}
+
+QSqlRecord QIBaseDriver::record(const QString& tablename) const
+{
+ QSqlRecord rec;
+ if (!isOpen())
+ return rec;
+
+ QSqlQuery q(createResult());
+ q.setForwardOnly(true);
+ QString table = tablename;
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = table.toUpper();
+ q.exec(QLatin1String("SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_LENGTH, "
+ "b.RDB$FIELD_SCALE, b.RDB$FIELD_PRECISION, a.RDB$NULL_FLAG "
+ "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
+ "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
+ "AND a.RDB$RELATION_NAME = '") + table + QLatin1String("' "
+ "ORDER BY a.RDB$FIELD_POSITION"));
+
+ while (q.next()) {
+ int type = q.value(1).toInt();
+ bool hasScale = q.value(3).toInt() < 0;
+ QSqlField f(q.value(0).toString().simplified(), qIBaseTypeName(type, hasScale));
+ if(hasScale) {
+ f.setLength(q.value(4).toInt());
+ f.setPrecision(qAbs(q.value(3).toInt()));
+ } else {
+ f.setLength(q.value(2).toInt());
+ f.setPrecision(0);
+ }
+ f.setRequired(q.value(5).toInt() > 0);
+ f.setSqlType(type);
+
+ rec.append(f);
+ }
+ return rec;
+}
+
+QSqlIndex QIBaseDriver::primaryIndex(const QString &table) const
+{
+ QSqlIndex index(table);
+ if (!isOpen())
+ return index;
+
+ QString tablename = table;
+ if (isIdentifierEscaped(tablename, QSqlDriver::TableName))
+ tablename = stripDelimiters(tablename, QSqlDriver::TableName);
+ else
+ tablename = tablename.toUpper();
+
+ QSqlQuery q(createResult());
+ q.setForwardOnly(true);
+ q.exec(QLatin1String("SELECT a.RDB$INDEX_NAME, b.RDB$FIELD_NAME, d.RDB$FIELD_TYPE, d.RDB$FIELD_SCALE "
+ "FROM RDB$RELATION_CONSTRAINTS a, RDB$INDEX_SEGMENTS b, RDB$RELATION_FIELDS c, RDB$FIELDS d "
+ "WHERE a.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' "
+ "AND a.RDB$RELATION_NAME = '") + tablename +
+ QLatin1String(" 'AND a.RDB$INDEX_NAME = b.RDB$INDEX_NAME "
+ "AND c.RDB$RELATION_NAME = a.RDB$RELATION_NAME "
+ "AND c.RDB$FIELD_NAME = b.RDB$FIELD_NAME "
+ "AND d.RDB$FIELD_NAME = c.RDB$FIELD_SOURCE "
+ "ORDER BY b.RDB$FIELD_POSITION"));
+
+ while (q.next()) {
+ QSqlField field(q.value(1).toString().simplified(), qIBaseTypeName(q.value(2).toInt(), q.value(3).toInt() < 0));
+ index.append(field); //TODO: asc? desc?
+ index.setName(q.value(0).toString());
+ }
+
+ return index;
+}
+
+QString QIBaseDriver::formatValue(const QSqlField &field, bool trimStrings) const
+{
+ switch (field.type()) {
+ case QVariant::DateTime: {
+ QDateTime datetime = field.value().toDateTime();
+ if (datetime.isValid())
+ return QLatin1Char('\'') + QString::number(datetime.date().year()) + QLatin1Char('-') +
+ QString::number(datetime.date().month()) + QLatin1Char('-') +
+ QString::number(datetime.date().day()) + QLatin1Char(' ') +
+ QString::number(datetime.time().hour()) + QLatin1Char(':') +
+ QString::number(datetime.time().minute()) + QLatin1Char(':') +
+ QString::number(datetime.time().second()) + QLatin1Char('.') +
+ QString::number(datetime.time().msec()).rightJustified(3, QLatin1Char('0'), true) +
+ QLatin1Char('\'');
+ else
+ return QLatin1String("NULL");
+ }
+ case QVariant::Time: {
+ QTime time = field.value().toTime();
+ if (time.isValid())
+ return QLatin1Char('\'') + QString::number(time.hour()) + QLatin1Char(':') +
+ QString::number(time.minute()) + QLatin1Char(':') +
+ QString::number(time.second()) + QLatin1Char('.') +
+ QString::number(time.msec()).rightJustified(3, QLatin1Char('0'), true) +
+ QLatin1Char('\'');
+ else
+ return QLatin1String("NULL");
+ }
+ case QVariant::Date: {
+ QDate date = field.value().toDate();
+ if (date.isValid())
+ return QLatin1Char('\'') + QString::number(date.year()) + QLatin1Char('-') +
+ QString::number(date.month()) + QLatin1Char('-') +
+ QString::number(date.day()) + QLatin1Char('\'');
+ else
+ return QLatin1String("NULL");
+ }
+ default:
+ return QSqlDriver::formatValue(field, trimStrings);
+ }
+}
+
+QVariant QIBaseDriver::handle() const
+{
+ Q_D(const QIBaseDriver);
+ return QVariant(qRegisterMetaType<isc_db_handle>("isc_db_handle"), &d->ibase);
+}
+
+#if defined(FB_API_VER) && FB_API_VER >= 20
+static ISC_EVENT_CALLBACK qEventCallback(char *result, ISC_USHORT length, const ISC_UCHAR *updated)
+#else
+static isc_callback qEventCallback(char *result, short length, char *updated)
+#endif
+{
+ if (!updated)
+ return 0;
+
+
+ memcpy(result, updated, length);
+ qMutex()->lock();
+ QIBaseDriver *driver = qBufferDriverMap()->value(result);
+ qMutex()->unlock();
+
+ // We use an asynchronous call (i.e., queued connection) because the event callback
+ // is executed in a different thread than the one in which the driver lives.
+ if (driver)
+ QMetaObject::invokeMethod(driver, "qHandleEventNotification", Qt::QueuedConnection, Q_ARG(void *, reinterpret_cast<void *>(result)));
+
+ return 0;
+}
+
+bool QIBaseDriver::subscribeToNotification(const QString &name)
+{
+ Q_D(QIBaseDriver);
+ if (!isOpen()) {
+ qWarning("QIBaseDriver::subscribeFromNotificationImplementation: database not open.");
+ return false;
+ }
+
+ if (d->eventBuffers.contains(name)) {
+ qWarning("QIBaseDriver::subscribeToNotificationImplementation: already subscribing to '%s'.",
+ qPrintable(name));
+ return false;
+ }
+
+ QIBaseEventBuffer *eBuffer = new QIBaseEventBuffer;
+ eBuffer->subscriptionState = QIBaseEventBuffer::Starting;
+ eBuffer->bufferLength = isc_event_block(&eBuffer->eventBuffer,
+ &eBuffer->resultBuffer,
+ 1,
+ name.toLocal8Bit().constData());
+
+ qMutex()->lock();
+ qBufferDriverMap()->insert(eBuffer->resultBuffer, this);
+ qMutex()->unlock();
+
+ d->eventBuffers.insert(name, eBuffer);
+
+ ISC_STATUS status[20];
+ isc_que_events(status,
+ &d->ibase,
+ &eBuffer->eventId,
+ eBuffer->bufferLength,
+ eBuffer->eventBuffer,
+#if defined (FB_API_VER) && FB_API_VER >= 20
+ (ISC_EVENT_CALLBACK)qEventCallback,
+#else
+ (isc_callback)qEventCallback,
+#endif
+ eBuffer->resultBuffer);
+
+ if (status[0] == 1 && status[1]) {
+ setLastError(QSqlError(QString::fromLatin1("Could not subscribe to event notifications for %1.").arg(name)));
+ d->eventBuffers.remove(name);
+ qFreeEventBuffer(eBuffer);
+ return false;
+ }
+
+ return true;
+}
+
+bool QIBaseDriver::unsubscribeFromNotification(const QString &name)
+{
+ Q_D(QIBaseDriver);
+ if (!isOpen()) {
+ qWarning("QIBaseDriver::unsubscribeFromNotificationImplementation: database not open.");
+ return false;
+ }
+
+ if (!d->eventBuffers.contains(name)) {
+ qWarning("QIBaseDriver::QIBaseSubscriptionState not subscribed to '%s'.",
+ qPrintable(name));
+ return false;
+ }
+
+ QIBaseEventBuffer *eBuffer = d->eventBuffers.value(name);
+ ISC_STATUS status[20];
+ eBuffer->subscriptionState = QIBaseEventBuffer::Finished;
+ isc_cancel_events(status, &d->ibase, &eBuffer->eventId);
+
+ if (status[0] == 1 && status[1]) {
+ setLastError(QSqlError(QString::fromLatin1("Could not unsubscribe from event notifications for %1.").arg(name)));
+ return false;
+ }
+
+ d->eventBuffers.remove(name);
+ qFreeEventBuffer(eBuffer);
+
+ return true;
+}
+
+QStringList QIBaseDriver::subscribedToNotifications() const
+{
+ Q_D(const QIBaseDriver);
+ return QStringList(d->eventBuffers.keys());
+}
+
+void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer)
+{
+ Q_D(QIBaseDriver);
+ QMap<QString, QIBaseEventBuffer *>::const_iterator i;
+ for (i = d->eventBuffers.constBegin(); i != d->eventBuffers.constEnd(); ++i) {
+ QIBaseEventBuffer* eBuffer = i.value();
+ if (reinterpret_cast<void *>(eBuffer->resultBuffer) != updatedResultBuffer)
+ continue;
+
+ ISC_ULONG counts[20];
+ memset(counts, 0, sizeof(counts));
+ isc_event_counts(counts, eBuffer->bufferLength, eBuffer->eventBuffer, eBuffer->resultBuffer);
+ if (counts[0]) {
+
+ if (eBuffer->subscriptionState == QIBaseEventBuffer::Subscribed) {
+ emit notification(i.key());
+ emit notification(i.key(), QSqlDriver::UnknownSource, QVariant());
+ }
+ else if (eBuffer->subscriptionState == QIBaseEventBuffer::Starting)
+ eBuffer->subscriptionState = QIBaseEventBuffer::Subscribed;
+
+ ISC_STATUS status[20];
+ isc_que_events(status,
+ &d->ibase,
+ &eBuffer->eventId,
+ eBuffer->bufferLength,
+ eBuffer->eventBuffer,
+#if defined (FB_API_VER) && FB_API_VER >= 20
+ (ISC_EVENT_CALLBACK)qEventCallback,
+#else
+ (isc_callback)qEventCallback,
+#endif
+ eBuffer->resultBuffer);
+ if (Q_UNLIKELY(status[0] == 1 && status[1])) {
+ qCritical("QIBaseDriver::qHandleEventNotification: could not resubscribe to '%s'",
+ qPrintable(i.key()));
+ }
+
+ return;
+ }
+ }
+}
+
+QString QIBaseDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
+{
+ QString res = identifier;
+ if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
+ res.replace(QLatin1Char('"'), QLatin1String("\"\""));
+ res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
+ res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ }
+ return res;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase_p.h b/src/plugins/sqldrivers/ibase/qsql_ibase_p.h
new file mode 100644
index 0000000000..c7cee41462
--- /dev/null
+++ b/src/plugins/sqldrivers/ibase/qsql_ibase_p.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSQL_IBASE_H
+#define QSQL_IBASE_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 <QtSql/qsqldriver.h>
+#include <ibase.h>
+
+#ifdef QT_PLUGIN
+#define Q_EXPORT_SQLDRIVER_IBASE
+#else
+#define Q_EXPORT_SQLDRIVER_IBASE Q_SQL_EXPORT
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QSqlResult;
+class QIBaseDriverPrivate;
+
+class Q_EXPORT_SQLDRIVER_IBASE QIBaseDriver : public QSqlDriver
+{
+ friend class QIBaseResultPrivate;
+ Q_DECLARE_PRIVATE(QIBaseDriver)
+ Q_OBJECT
+public:
+ explicit QIBaseDriver(QObject *parent = 0);
+ explicit QIBaseDriver(isc_db_handle connection, QObject *parent = 0);
+ virtual ~QIBaseDriver();
+ bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
+ bool open(const QString &db,
+ const QString &user,
+ const QString &password,
+ const QString &host,
+ int port,
+ const QString &connOpts) Q_DECL_OVERRIDE;
+ bool open(const QString &db,
+ const QString &user,
+ const QString &password,
+ const QString &host,
+ int port) { return open(db, user, password, host, port, QString()); }
+ void close() Q_DECL_OVERRIDE;
+ QSqlResult *createResult() const Q_DECL_OVERRIDE;
+ bool beginTransaction() Q_DECL_OVERRIDE;
+ bool commitTransaction() Q_DECL_OVERRIDE;
+ bool rollbackTransaction() Q_DECL_OVERRIDE;
+ QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
+
+ QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE;
+ QSqlIndex primaryIndex(const QString &table) const Q_DECL_OVERRIDE;
+
+ QString formatValue(const QSqlField &field, bool trimStrings) const Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+
+ QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
+
+ bool subscribeToNotification(const QString &name) Q_DECL_OVERRIDE;
+ bool unsubscribeFromNotification(const QString &name) Q_DECL_OVERRIDE;
+ QStringList subscribedToNotifications() const Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ void qHandleEventNotification(void* updatedResultBuffer);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQL_IBASE_H
diff --git a/src/plugins/sqldrivers/mysql/main.cpp b/src/plugins/sqldrivers/mysql/main.cpp
index 855a6eeb9c..00d9c5bb34 100644
--- a/src/plugins/sqldrivers/mysql/main.cpp
+++ b/src/plugins/sqldrivers/mysql/main.cpp
@@ -39,7 +39,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/mysql/qsql_mysql_p.h"
+#include "qsql_mysql_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/mysql/mysql.pro b/src/plugins/sqldrivers/mysql/mysql.pro
index c917bfca48..3bd8cd0040 100644
--- a/src/plugins/sqldrivers/mysql/mysql.pro
+++ b/src/plugins/sqldrivers/mysql/mysql.pro
@@ -1,8 +1,23 @@
TARGET = qsqlmysql
-SOURCES = main.cpp
+HEADERS += $$PWD/qsql_mysql_p.h
+SOURCES += $$PWD/qsql_mysql.cpp $$PWD/main.cpp
+
+QMAKE_CXXFLAGS *= $$QMAKE_CFLAGS_MYSQL
+LIBS += $$QMAKE_LIBS_MYSQL
+
+unix {
+ isEmpty(QMAKE_LIBS_MYSQL) {
+ !contains(LIBS, .*mysqlclient.*):!contains(LIBS, .*mysqld.*) {
+ use_libmysqlclient_r:LIBS += -lmysqlclient_r
+ else:LIBS += -lmysqlclient
+ }
+ }
+} else {
+ !contains(LIBS, .*mysql.*):!contains(LIBS, .*mysqld.*):LIBS += -llibmysql
+}
+
OTHER_FILES += mysql.json
-include(../../../sql/drivers/mysql/qsql_mysql.pri)
PLUGIN_CLASS_NAME = QMYSQLDriverPlugin
include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
new file mode 100644
index 0000000000..b13e10e3a5
--- /dev/null
+++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
@@ -0,0 +1,1666 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsql_mysql_p.h"
+
+#include <qcoreapplication.h>
+#include <qvariant.h>
+#include <qdatetime.h>
+#include <qsqlerror.h>
+#include <qsqlfield.h>
+#include <qsqlindex.h>
+#include <qsqlquery.h>
+#include <qsqlrecord.h>
+#include <qstringlist.h>
+#include <qtextcodec.h>
+#include <qvector.h>
+#include <qfile.h>
+#include <qdebug.h>
+#include <QtSql/private/qsqldriver_p.h>
+#include <QtSql/private/qsqlresult_p.h>
+
+#ifdef Q_OS_WIN32
+// comment the next line out if you want to use MySQL/embedded on Win32 systems.
+// note that it will crash if you don't statically link to the mysql/e library!
+# define Q_NO_MYSQL_EMBEDDED
+#endif
+
+Q_DECLARE_METATYPE(MYSQL_RES*)
+Q_DECLARE_METATYPE(MYSQL*)
+
+#if MYSQL_VERSION_ID >= 40108
+Q_DECLARE_METATYPE(MYSQL_STMT*)
+#endif
+
+#if MYSQL_VERSION_ID >= 40100
+# define Q_CLIENT_MULTI_STATEMENTS CLIENT_MULTI_STATEMENTS
+#else
+# define Q_CLIENT_MULTI_STATEMENTS 0
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QMYSQLDriverPrivate : public QSqlDriverPrivate
+{
+ Q_DECLARE_PUBLIC(QMYSQLDriver)
+
+public:
+ QMYSQLDriverPrivate() : QSqlDriverPrivate(), mysql(0),
+#ifndef QT_NO_TEXTCODEC
+ tc(QTextCodec::codecForLocale()),
+#else
+ tc(0),
+#endif
+ preparedQuerysEnabled(false) { dbmsType = QSqlDriver::MySqlServer; }
+ MYSQL *mysql;
+ QTextCodec *tc;
+
+ bool preparedQuerysEnabled;
+};
+
+static inline QString toUnicode(QTextCodec *tc, const char *str)
+{
+#ifdef QT_NO_TEXTCODEC
+ Q_UNUSED(tc);
+ return QString::fromLatin1(str);
+#else
+ return tc->toUnicode(str);
+#endif
+}
+
+static inline QString toUnicode(QTextCodec *tc, const char *str, int length)
+{
+#ifdef QT_NO_TEXTCODEC
+ Q_UNUSED(tc);
+ return QString::fromLatin1(str, length);
+#else
+ return tc->toUnicode(str, length);
+#endif
+}
+
+static inline QByteArray fromUnicode(QTextCodec *tc, const QString &str)
+{
+#ifdef QT_NO_TEXTCODEC
+ Q_UNUSED(tc);
+ return str.toLatin1();
+#else
+ return tc->fromUnicode(str);
+#endif
+}
+
+static inline QVariant qDateFromString(const QString &val)
+{
+#ifdef QT_NO_DATESTRING
+ Q_UNUSED(val);
+ return QVariant(val);
+#else
+ if (val.isEmpty())
+ return QVariant(QDate());
+ return QVariant(QDate::fromString(val, Qt::ISODate));
+#endif
+}
+
+static inline QVariant qTimeFromString(const QString &val)
+{
+#ifdef QT_NO_DATESTRING
+ Q_UNUSED(val);
+ return QVariant(val);
+#else
+ if (val.isEmpty())
+ return QVariant(QTime());
+ return QVariant(QTime::fromString(val, Qt::ISODate));
+#endif
+}
+
+static inline QVariant qDateTimeFromString(QString &val)
+{
+#ifdef QT_NO_DATESTRING
+ Q_UNUSED(val);
+ return QVariant(val);
+#else
+ if (val.isEmpty())
+ return QVariant(QDateTime());
+ if (val.length() == 14)
+ // TIMESTAMPS have the format yyyyMMddhhmmss
+ val.insert(4, QLatin1Char('-')).insert(7, QLatin1Char('-')).insert(10,
+ QLatin1Char('T')).insert(13, QLatin1Char(':')).insert(16, QLatin1Char(':'));
+ return QVariant(QDateTime::fromString(val, Qt::ISODate));
+#endif
+}
+
+class QMYSQLResultPrivate;
+
+class QMYSQLResult : public QSqlResult
+{
+ Q_DECLARE_PRIVATE(QMYSQLResult)
+ friend class QMYSQLDriver;
+
+public:
+ explicit QMYSQLResult(const QMYSQLDriver *db);
+ ~QMYSQLResult();
+
+ QVariant handle() const Q_DECL_OVERRIDE;
+protected:
+ void cleanup();
+ bool fetch(int i) Q_DECL_OVERRIDE;
+ bool fetchNext() Q_DECL_OVERRIDE;
+ bool fetchLast() Q_DECL_OVERRIDE;
+ bool fetchFirst() Q_DECL_OVERRIDE;
+ QVariant data(int field) Q_DECL_OVERRIDE;
+ bool isNull(int field) Q_DECL_OVERRIDE;
+ bool reset (const QString& query) Q_DECL_OVERRIDE;
+ int size() Q_DECL_OVERRIDE;
+ int numRowsAffected() Q_DECL_OVERRIDE;
+ QVariant lastInsertId() const Q_DECL_OVERRIDE;
+ QSqlRecord record() const Q_DECL_OVERRIDE;
+ void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
+ bool nextResult() Q_DECL_OVERRIDE;
+
+#if MYSQL_VERSION_ID >= 40108
+ bool prepare(const QString &stmt) Q_DECL_OVERRIDE;
+ bool exec() Q_DECL_OVERRIDE;
+#endif
+};
+
+class QMYSQLResultPrivate: public QSqlResultPrivate
+{
+ Q_DECLARE_PUBLIC(QMYSQLResult)
+
+public:
+ Q_DECLARE_SQLDRIVER_PRIVATE(QMYSQLDriver)
+
+ QMYSQLResultPrivate(QMYSQLResult *q, const QMYSQLDriver *drv)
+ : QSqlResultPrivate(q, drv),
+ result(0),
+ rowsAffected(0),
+ hasBlobs(false)
+#if MYSQL_VERSION_ID >= 40108
+ , stmt(0), meta(0), inBinds(0), outBinds(0)
+#endif
+ , preparedQuery(false)
+ { }
+
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ int rowsAffected;
+
+ bool bindInValues();
+ void bindBlobs();
+
+ bool hasBlobs;
+ struct QMyField
+ {
+ QMyField()
+ : outField(0), nullIndicator(false), bufLength(0ul),
+ myField(0), type(QVariant::Invalid)
+ {}
+ char *outField;
+ my_bool nullIndicator;
+ ulong bufLength;
+ MYSQL_FIELD *myField;
+ QVariant::Type type;
+ };
+
+ QVector<QMyField> fields;
+
+#if MYSQL_VERSION_ID >= 40108
+ MYSQL_STMT* stmt;
+ MYSQL_RES* meta;
+
+ MYSQL_BIND *inBinds;
+ MYSQL_BIND *outBinds;
+#endif
+
+ bool preparedQuery;
+};
+
+#ifndef QT_NO_TEXTCODEC
+static QTextCodec* codec(MYSQL* mysql)
+{
+#if MYSQL_VERSION_ID >= 32321
+ QTextCodec* heuristicCodec = QTextCodec::codecForName(mysql_character_set_name(mysql));
+ if (heuristicCodec)
+ return heuristicCodec;
+#endif
+ return QTextCodec::codecForLocale();
+}
+#endif // QT_NO_TEXTCODEC
+
+static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
+ const QMYSQLDriverPrivate* p)
+{
+ const char *cerr = p->mysql ? mysql_error(p->mysql) : 0;
+ return QSqlError(QLatin1String("QMYSQL: ") + err,
+ p->tc ? toUnicode(p->tc, cerr) : QString::fromLatin1(cerr),
+ type, mysql_errno(p->mysql));
+}
+
+
+static QVariant::Type qDecodeMYSQLType(int mysqltype, uint flags)
+{
+ QVariant::Type type;
+ switch (mysqltype) {
+ case FIELD_TYPE_TINY :
+ type = static_cast<QVariant::Type>((flags & UNSIGNED_FLAG) ? QMetaType::UChar : QMetaType::Char);
+ break;
+ case FIELD_TYPE_SHORT :
+ type = static_cast<QVariant::Type>((flags & UNSIGNED_FLAG) ? QMetaType::UShort : QMetaType::Short);
+ break;
+ case FIELD_TYPE_LONG :
+ case FIELD_TYPE_INT24 :
+ type = (flags & UNSIGNED_FLAG) ? QVariant::UInt : QVariant::Int;
+ break;
+ case FIELD_TYPE_YEAR :
+ type = QVariant::Int;
+ break;
+ case FIELD_TYPE_LONGLONG :
+ type = (flags & UNSIGNED_FLAG) ? QVariant::ULongLong : QVariant::LongLong;
+ break;
+ case FIELD_TYPE_FLOAT :
+ case FIELD_TYPE_DOUBLE :
+ case FIELD_TYPE_DECIMAL :
+#if defined(FIELD_TYPE_NEWDECIMAL)
+ case FIELD_TYPE_NEWDECIMAL:
+#endif
+ type = QVariant::Double;
+ break;
+ case FIELD_TYPE_DATE :
+ type = QVariant::Date;
+ break;
+ case FIELD_TYPE_TIME :
+ type = QVariant::Time;
+ break;
+ case FIELD_TYPE_DATETIME :
+ case FIELD_TYPE_TIMESTAMP :
+ type = QVariant::DateTime;
+ break;
+ case FIELD_TYPE_STRING :
+ case FIELD_TYPE_VAR_STRING :
+ case FIELD_TYPE_BLOB :
+ case FIELD_TYPE_TINY_BLOB :
+ case FIELD_TYPE_MEDIUM_BLOB :
+ case FIELD_TYPE_LONG_BLOB :
+ type = (flags & BINARY_FLAG) ? QVariant::ByteArray : QVariant::String;
+ break;
+ default:
+ case FIELD_TYPE_ENUM :
+ case FIELD_TYPE_SET :
+ type = QVariant::String;
+ break;
+ }
+ return type;
+}
+
+static QSqlField qToField(MYSQL_FIELD *field, QTextCodec *tc)
+{
+ QSqlField f(toUnicode(tc, field->name),
+ qDecodeMYSQLType(int(field->type), field->flags));
+ f.setRequired(IS_NOT_NULL(field->flags));
+ f.setLength(field->length);
+ f.setPrecision(field->decimals);
+ f.setSqlType(field->type);
+ f.setAutoValue(field->flags & AUTO_INCREMENT_FLAG);
+ return f;
+}
+
+#if MYSQL_VERSION_ID >= 40108
+
+static QSqlError qMakeStmtError(const QString& err, QSqlError::ErrorType type,
+ MYSQL_STMT* stmt)
+{
+ const char *cerr = mysql_stmt_error(stmt);
+ return QSqlError(QLatin1String("QMYSQL3: ") + err,
+ QString::fromLatin1(cerr),
+ type, mysql_stmt_errno(stmt));
+}
+
+static bool qIsBlob(int t)
+{
+ return t == MYSQL_TYPE_TINY_BLOB
+ || t == MYSQL_TYPE_BLOB
+ || t == MYSQL_TYPE_MEDIUM_BLOB
+ || t == MYSQL_TYPE_LONG_BLOB;
+}
+
+static bool qIsInteger(int t)
+{
+ return t == QMetaType::Char || t == QMetaType::UChar
+ || t == QMetaType::Short || t == QMetaType::UShort
+ || t == QMetaType::Int || t == QMetaType::UInt
+ || t == QMetaType::LongLong || t == QMetaType::ULongLong;
+}
+
+void QMYSQLResultPrivate::bindBlobs()
+{
+ int i;
+ MYSQL_FIELD *fieldInfo;
+ MYSQL_BIND *bind;
+
+ for(i = 0; i < fields.count(); ++i) {
+ fieldInfo = fields.at(i).myField;
+ if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo) {
+ bind = &inBinds[i];
+ bind->buffer_length = fieldInfo->max_length;
+ delete[] static_cast<char*>(bind->buffer);
+ bind->buffer = new char[fieldInfo->max_length];
+ fields[i].outField = static_cast<char*>(bind->buffer);
+ }
+ }
+}
+
+bool QMYSQLResultPrivate::bindInValues()
+{
+ MYSQL_BIND *bind;
+ char *field;
+ int i = 0;
+
+ if (!meta)
+ meta = mysql_stmt_result_metadata(stmt);
+ if (!meta)
+ return false;
+
+ fields.resize(mysql_num_fields(meta));
+
+ inBinds = new MYSQL_BIND[fields.size()];
+ memset(inBinds, 0, fields.size() * sizeof(MYSQL_BIND));
+
+ MYSQL_FIELD *fieldInfo;
+
+ while((fieldInfo = mysql_fetch_field(meta))) {
+ QMyField &f = fields[i];
+ f.myField = fieldInfo;
+
+ f.type = qDecodeMYSQLType(fieldInfo->type, fieldInfo->flags);
+ if (qIsBlob(fieldInfo->type)) {
+ // the size of a blob-field is available as soon as we call
+ // mysql_stmt_store_result()
+ // after mysql_stmt_exec() in QMYSQLResult::exec()
+ fieldInfo->length = 0;
+ hasBlobs = true;
+ } else if (qIsInteger(f.type)) {
+ fieldInfo->length = 8;
+ } else {
+ fieldInfo->type = MYSQL_TYPE_STRING;
+ }
+ bind = &inBinds[i];
+ field = new char[fieldInfo->length + 1];
+ memset(field, 0, fieldInfo->length + 1);
+
+ bind->buffer_type = fieldInfo->type;
+ bind->buffer = field;
+ bind->buffer_length = f.bufLength = fieldInfo->length + 1;
+ bind->is_null = &f.nullIndicator;
+ bind->length = &f.bufLength;
+ bind->is_unsigned = fieldInfo->flags & UNSIGNED_FLAG ? 1 : 0;
+ f.outField=field;
+
+ ++i;
+ }
+ return true;
+}
+#endif
+
+QMYSQLResult::QMYSQLResult(const QMYSQLDriver* db)
+ : QSqlResult(*new QMYSQLResultPrivate(this, db))
+{
+}
+
+QMYSQLResult::~QMYSQLResult()
+{
+ cleanup();
+}
+
+QVariant QMYSQLResult::handle() const
+{
+ Q_D(const QMYSQLResult);
+#if MYSQL_VERSION_ID >= 40108
+ if(d->preparedQuery)
+ return d->meta ? QVariant::fromValue(d->meta) : QVariant::fromValue(d->stmt);
+ else
+#endif
+ return QVariant::fromValue(d->result);
+}
+
+void QMYSQLResult::cleanup()
+{
+ Q_D(QMYSQLResult);
+ if (d->result)
+ mysql_free_result(d->result);
+
+// must iterate trough leftover result sets from multi-selects or stored procedures
+// if this isn't done subsequent queries will fail with "Commands out of sync"
+#if MYSQL_VERSION_ID >= 40100
+ while (driver() && d->drv_d_func()->mysql && mysql_next_result(d->drv_d_func()->mysql) == 0) {
+ MYSQL_RES *res = mysql_store_result(d->drv_d_func()->mysql);
+ if (res)
+ mysql_free_result(res);
+ }
+#endif
+
+#if MYSQL_VERSION_ID >= 40108
+ if (d->stmt) {
+ if (mysql_stmt_close(d->stmt))
+ qWarning("QMYSQLResult::cleanup: unable to free statement handle");
+ d->stmt = 0;
+ }
+
+ if (d->meta) {
+ mysql_free_result(d->meta);
+ d->meta = 0;
+ }
+
+ int i;
+ for (i = 0; i < d->fields.count(); ++i)
+ delete[] d->fields[i].outField;
+
+ if (d->outBinds) {
+ delete[] d->outBinds;
+ d->outBinds = 0;
+ }
+
+ if (d->inBinds) {
+ delete[] d->inBinds;
+ d->inBinds = 0;
+ }
+#endif
+
+ d->hasBlobs = false;
+ d->fields.clear();
+ d->result = NULL;
+ d->row = NULL;
+ setAt(-1);
+ setActive(false);
+}
+
+bool QMYSQLResult::fetch(int i)
+{
+ Q_D(QMYSQLResult);
+ if (!driver())
+ return false;
+ if (isForwardOnly()) { // fake a forward seek
+ if (at() < i) {
+ int x = i - at();
+ while (--x && fetchNext()) {};
+ return fetchNext();
+ } else {
+ return false;
+ }
+ }
+ if (at() == i)
+ return true;
+ if (d->preparedQuery) {
+#if MYSQL_VERSION_ID >= 40108
+ mysql_stmt_data_seek(d->stmt, i);
+
+ int nRC = mysql_stmt_fetch(d->stmt);
+ if (nRC) {
+#ifdef MYSQL_DATA_TRUNCATED
+ if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED)
+#else
+ if (nRC == 1)
+#endif
+ setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
+ "Unable to fetch data"), QSqlError::StatementError, d->stmt));
+ return false;
+ }
+#else
+ return false;
+#endif
+ } else {
+ mysql_data_seek(d->result, i);
+ d->row = mysql_fetch_row(d->result);
+ if (!d->row)
+ return false;
+ }
+
+ setAt(i);
+ return true;
+}
+
+bool QMYSQLResult::fetchNext()
+{
+ Q_D(QMYSQLResult);
+ if (!driver())
+ return false;
+ if (d->preparedQuery) {
+#if MYSQL_VERSION_ID >= 40108
+ int nRC = mysql_stmt_fetch(d->stmt);
+ if (nRC) {
+#ifdef MYSQL_DATA_TRUNCATED
+ if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED)
+#else
+ if (nRC == 1)
+#endif // MYSQL_DATA_TRUNCATED
+ setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
+ "Unable to fetch data"), QSqlError::StatementError, d->stmt));
+ return false;
+ }
+#else
+ return false;
+#endif
+ } else {
+ d->row = mysql_fetch_row(d->result);
+ if (!d->row)
+ return false;
+ }
+ setAt(at() + 1);
+ return true;
+}
+
+bool QMYSQLResult::fetchLast()
+{
+ Q_D(QMYSQLResult);
+ if (!driver())
+ return false;
+ if (isForwardOnly()) { // fake this since MySQL can't seek on forward only queries
+ bool success = fetchNext(); // did we move at all?
+ while (fetchNext()) {};
+ return success;
+ }
+
+ my_ulonglong numRows;
+ if (d->preparedQuery) {
+#if MYSQL_VERSION_ID >= 40108
+ numRows = mysql_stmt_num_rows(d->stmt);
+#else
+ numRows = 0;
+#endif
+ } else {
+ numRows = mysql_num_rows(d->result);
+ }
+ if (at() == int(numRows))
+ return true;
+ if (!numRows)
+ return false;
+ return fetch(numRows - 1);
+}
+
+bool QMYSQLResult::fetchFirst()
+{
+ if (at() == 0)
+ return true;
+
+ if (isForwardOnly())
+ return (at() == QSql::BeforeFirstRow) ? fetchNext() : false;
+ return fetch(0);
+}
+
+QVariant QMYSQLResult::data(int field)
+{
+ Q_D(QMYSQLResult);
+ if (!isSelect() || field >= d->fields.count()) {
+ qWarning("QMYSQLResult::data: column %d out of range", field);
+ return QVariant();
+ }
+
+ if (!driver())
+ return QVariant();
+
+ int fieldLength = 0;
+ const QMYSQLResultPrivate::QMyField &f = d->fields.at(field);
+ QString val;
+ if (d->preparedQuery) {
+ if (f.nullIndicator)
+ return QVariant(f.type);
+
+ if (qIsInteger(f.type))
+ return QVariant(f.type, f.outField);
+
+ if (f.type != QVariant::ByteArray)
+ val = toUnicode(d->drv_d_func()->tc, f.outField, f.bufLength);
+ } else {
+ if (d->row[field] == NULL) {
+ // NULL value
+ return QVariant(f.type);
+ }
+
+ fieldLength = mysql_fetch_lengths(d->result)[field];
+
+ if (f.type != QVariant::ByteArray)
+ val = toUnicode(d->drv_d_func()->tc, d->row[field], fieldLength);
+ }
+
+ switch (static_cast<int>(f.type)) {
+ case QVariant::LongLong:
+ return QVariant(val.toLongLong());
+ case QVariant::ULongLong:
+ return QVariant(val.toULongLong());
+ case QMetaType::Char:
+ case QMetaType::Short:
+ case QVariant::Int:
+ return QVariant(val.toInt());
+ case QMetaType::UChar:
+ case QMetaType::UShort:
+ case QVariant::UInt:
+ return QVariant(val.toUInt());
+ case QVariant::Double: {
+ QVariant v;
+ bool ok=false;
+ double dbl = val.toDouble(&ok);
+ switch(numericalPrecisionPolicy()) {
+ case QSql::LowPrecisionInt32:
+ v=QVariant(dbl).toInt();
+ break;
+ case QSql::LowPrecisionInt64:
+ v = QVariant(dbl).toLongLong();
+ break;
+ case QSql::LowPrecisionDouble:
+ v = QVariant(dbl);
+ break;
+ case QSql::HighPrecision:
+ default:
+ v = val;
+ ok = true;
+ break;
+ }
+ if(ok)
+ return v;
+ else
+ return QVariant();
+ }
+ return QVariant(val.toDouble());
+ case QVariant::Date:
+ return qDateFromString(val);
+ case QVariant::Time:
+ return qTimeFromString(val);
+ case QVariant::DateTime:
+ return qDateTimeFromString(val);
+ case QVariant::ByteArray: {
+
+ QByteArray ba;
+ if (d->preparedQuery) {
+ ba = QByteArray(f.outField, f.bufLength);
+ } else {
+ ba = QByteArray(d->row[field], fieldLength);
+ }
+ return QVariant(ba);
+ }
+ default:
+ case QVariant::String:
+ return QVariant(val);
+ }
+ qWarning("QMYSQLResult::data: unknown data type");
+ return QVariant();
+}
+
+bool QMYSQLResult::isNull(int field)
+{
+ Q_D(const QMYSQLResult);
+ if (field < 0 || field >= d->fields.count())
+ return true;
+ if (d->preparedQuery)
+ return d->fields.at(field).nullIndicator;
+ else
+ return d->row[field] == NULL;
+}
+
+bool QMYSQLResult::reset (const QString& query)
+{
+ Q_D(QMYSQLResult);
+ if (!driver() || !driver()->isOpen() || driver()->isOpenError())
+ return false;
+
+ d->preparedQuery = false;
+
+ cleanup();
+
+ const QByteArray encQuery(fromUnicode(d->drv_d_func()->tc, query));
+ if (mysql_real_query(d->drv_d_func()->mysql, encQuery.data(), encQuery.length())) {
+ setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute query"),
+ QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ d->result = mysql_store_result(d->drv_d_func()->mysql);
+ if (!d->result && mysql_field_count(d->drv_d_func()->mysql) > 0) {
+ setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store result"),
+ QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ int numFields = mysql_field_count(d->drv_d_func()->mysql);
+ setSelect(numFields != 0);
+ d->fields.resize(numFields);
+ d->rowsAffected = mysql_affected_rows(d->drv_d_func()->mysql);
+
+ if (isSelect()) {
+ for(int i = 0; i < numFields; i++) {
+ MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i);
+ d->fields[i].type = qDecodeMYSQLType(field->type, field->flags);
+ }
+ setAt(QSql::BeforeFirstRow);
+ }
+ setActive(true);
+ return isActive();
+}
+
+int QMYSQLResult::size()
+{
+ Q_D(const QMYSQLResult);
+ if (driver() && isSelect())
+ if (d->preparedQuery)
+#if MYSQL_VERSION_ID >= 40108
+ return mysql_stmt_num_rows(d->stmt);
+#else
+ return -1;
+#endif
+ else
+ return int(mysql_num_rows(d->result));
+ else
+ return -1;
+}
+
+int QMYSQLResult::numRowsAffected()
+{
+ Q_D(const QMYSQLResult);
+ return d->rowsAffected;
+}
+
+QVariant QMYSQLResult::lastInsertId() const
+{
+ Q_D(const QMYSQLResult);
+ if (!isActive() || !driver())
+ return QVariant();
+
+ if (d->preparedQuery) {
+#if MYSQL_VERSION_ID >= 40108
+ quint64 id = mysql_stmt_insert_id(d->stmt);
+ if (id)
+ return QVariant(id);
+#endif
+ } else {
+ quint64 id = mysql_insert_id(d->drv_d_func()->mysql);
+ if (id)
+ return QVariant(id);
+ }
+ return QVariant();
+}
+
+QSqlRecord QMYSQLResult::record() const
+{
+ Q_D(const QMYSQLResult);
+ QSqlRecord info;
+ MYSQL_RES *res;
+ if (!isActive() || !isSelect() || !driver())
+ return info;
+
+#if MYSQL_VERSION_ID >= 40108
+ res = d->preparedQuery ? d->meta : d->result;
+#else
+ res = d->result;
+#endif
+
+ if (!mysql_errno(d->drv_d_func()->mysql)) {
+ mysql_field_seek(res, 0);
+ MYSQL_FIELD* field = mysql_fetch_field(res);
+ while(field) {
+ info.append(qToField(field, d->drv_d_func()->tc));
+ field = mysql_fetch_field(res);
+ }
+ }
+ mysql_field_seek(res, 0);
+ return info;
+}
+
+bool QMYSQLResult::nextResult()
+{
+ Q_D(QMYSQLResult);
+ if (!driver())
+ return false;
+#if MYSQL_VERSION_ID >= 40100
+ setAt(-1);
+ setActive(false);
+
+ if (d->result && isSelect())
+ mysql_free_result(d->result);
+ d->result = 0;
+ setSelect(false);
+
+ for (int i = 0; i < d->fields.count(); ++i)
+ delete[] d->fields[i].outField;
+ d->fields.clear();
+
+ int status = mysql_next_result(d->drv_d_func()->mysql);
+ if (status > 0) {
+ setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute next query"),
+ QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ } else if (status == -1) {
+ return false; // No more result sets
+ }
+
+ d->result = mysql_store_result(d->drv_d_func()->mysql);
+ int numFields = mysql_field_count(d->drv_d_func()->mysql);
+ if (!d->result && numFields > 0) {
+ setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store next result"),
+ QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+
+ setSelect(numFields > 0);
+ d->fields.resize(numFields);
+ d->rowsAffected = mysql_affected_rows(d->drv_d_func()->mysql);
+
+ if (isSelect()) {
+ for (int i = 0; i < numFields; i++) {
+ MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i);
+ d->fields[i].type = qDecodeMYSQLType(field->type, field->flags);
+ }
+ }
+
+ setActive(true);
+ return true;
+#else
+ return false;
+#endif
+}
+
+void QMYSQLResult::virtual_hook(int id, void *data)
+{
+ QSqlResult::virtual_hook(id, data);
+}
+
+
+#if MYSQL_VERSION_ID >= 40108
+
+static MYSQL_TIME *toMySqlDate(QDate date, QTime time, QVariant::Type type)
+{
+ Q_ASSERT(type == QVariant::Time || type == QVariant::Date
+ || type == QVariant::DateTime);
+
+ MYSQL_TIME *myTime = new MYSQL_TIME;
+ memset(myTime, 0, sizeof(MYSQL_TIME));
+
+ if (type == QVariant::Time || type == QVariant::DateTime) {
+ myTime->hour = time.hour();
+ myTime->minute = time.minute();
+ myTime->second = time.second();
+ myTime->second_part = time.msec() * 1000;
+ }
+ if (type == QVariant::Date || type == QVariant::DateTime) {
+ myTime->year = date.year();
+ myTime->month = date.month();
+ myTime->day = date.day();
+ }
+
+ return myTime;
+}
+
+bool QMYSQLResult::prepare(const QString& query)
+{
+ Q_D(QMYSQLResult);
+ if (!driver())
+ return false;
+#if MYSQL_VERSION_ID >= 40108
+ cleanup();
+ if (!d->drv_d_func()->preparedQuerysEnabled)
+ return QSqlResult::prepare(query);
+
+ int r;
+
+ if (query.isEmpty())
+ return false;
+
+ if (!d->stmt)
+ d->stmt = mysql_stmt_init(d->drv_d_func()->mysql);
+ if (!d->stmt) {
+ setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to prepare statement"),
+ QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+
+ const QByteArray encQuery(fromUnicode(d->drv_d_func()->tc, query));
+ r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.length());
+ if (r != 0) {
+ setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
+ "Unable to prepare statement"), QSqlError::StatementError, d->stmt));
+ cleanup();
+ return false;
+ }
+
+ if (mysql_stmt_param_count(d->stmt) > 0) {// allocate memory for outvalues
+ d->outBinds = new MYSQL_BIND[mysql_stmt_param_count(d->stmt)];
+ }
+
+ setSelect(d->bindInValues());
+ d->preparedQuery = true;
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool QMYSQLResult::exec()
+{
+ Q_D(QMYSQLResult);
+ if (!driver())
+ return false;
+ if (!d->preparedQuery)
+ return QSqlResult::exec();
+ if (!d->stmt)
+ return false;
+
+ int r = 0;
+ MYSQL_BIND* currBind;
+ QVector<MYSQL_TIME *> timeVector;
+ QVector<QByteArray> stringVector;
+ QVector<my_bool> nullVector;
+
+ const QVector<QVariant> values = boundValues();
+
+ r = mysql_stmt_reset(d->stmt);
+ if (r != 0) {
+ setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
+ "Unable to reset statement"), QSqlError::StatementError, d->stmt));
+ return false;
+ }
+
+ if (mysql_stmt_param_count(d->stmt) > 0 &&
+ mysql_stmt_param_count(d->stmt) == (uint)values.count()) {
+
+ nullVector.resize(values.count());
+ for (int i = 0; i < values.count(); ++i) {
+ const QVariant &val = boundValues().at(i);
+ void *data = const_cast<void *>(val.constData());
+
+ currBind = &d->outBinds[i];
+
+ nullVector[i] = static_cast<my_bool>(val.isNull());
+ currBind->is_null = &nullVector[i];
+ currBind->length = 0;
+ currBind->is_unsigned = 0;
+
+ switch (val.type()) {
+ case QVariant::ByteArray:
+ currBind->buffer_type = MYSQL_TYPE_BLOB;
+ currBind->buffer = const_cast<char *>(val.toByteArray().constData());
+ currBind->buffer_length = val.toByteArray().size();
+ break;
+
+ case QVariant::Time:
+ case QVariant::Date:
+ case QVariant::DateTime: {
+ MYSQL_TIME *myTime = toMySqlDate(val.toDate(), val.toTime(), val.type());
+ timeVector.append(myTime);
+
+ currBind->buffer = myTime;
+ switch(val.type()) {
+ case QVariant::Time:
+ currBind->buffer_type = MYSQL_TYPE_TIME;
+ myTime->time_type = MYSQL_TIMESTAMP_TIME;
+ break;
+ case QVariant::Date:
+ currBind->buffer_type = MYSQL_TYPE_DATE;
+ myTime->time_type = MYSQL_TIMESTAMP_DATE;
+ break;
+ case QVariant::DateTime:
+ currBind->buffer_type = MYSQL_TYPE_DATETIME;
+ myTime->time_type = MYSQL_TIMESTAMP_DATETIME;
+ break;
+ default:
+ break;
+ }
+ currBind->buffer_length = sizeof(MYSQL_TIME);
+ currBind->length = 0;
+ break; }
+ case QVariant::UInt:
+ case QVariant::Int:
+ currBind->buffer_type = MYSQL_TYPE_LONG;
+ currBind->buffer = data;
+ currBind->buffer_length = sizeof(int);
+ currBind->is_unsigned = (val.type() != QVariant::Int);
+ break;
+ case QVariant::Bool:
+ currBind->buffer_type = MYSQL_TYPE_TINY;
+ currBind->buffer = data;
+ currBind->buffer_length = sizeof(bool);
+ currBind->is_unsigned = false;
+ break;
+ case QVariant::Double:
+ currBind->buffer_type = MYSQL_TYPE_DOUBLE;
+ currBind->buffer = data;
+ currBind->buffer_length = sizeof(double);
+ break;
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ currBind->buffer_type = MYSQL_TYPE_LONGLONG;
+ currBind->buffer = data;
+ currBind->buffer_length = sizeof(qint64);
+ currBind->is_unsigned = (val.type() == QVariant::ULongLong);
+ break;
+ case QVariant::String:
+ default: {
+ QByteArray ba = fromUnicode(d->drv_d_func()->tc, val.toString());
+ stringVector.append(ba);
+ currBind->buffer_type = MYSQL_TYPE_STRING;
+ currBind->buffer = const_cast<char *>(ba.constData());
+ currBind->buffer_length = ba.length();
+ break; }
+ }
+ }
+
+ r = mysql_stmt_bind_param(d->stmt, d->outBinds);
+ if (r != 0) {
+ setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
+ "Unable to bind value"), QSqlError::StatementError, d->stmt));
+ qDeleteAll(timeVector);
+ return false;
+ }
+ }
+ r = mysql_stmt_execute(d->stmt);
+
+ qDeleteAll(timeVector);
+
+ if (r != 0) {
+ setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
+ "Unable to execute statement"), QSqlError::StatementError, d->stmt));
+ return false;
+ }
+ //if there is meta-data there is also data
+ setSelect(d->meta);
+
+ d->rowsAffected = mysql_stmt_affected_rows(d->stmt);
+
+ if (isSelect()) {
+ my_bool update_max_length = true;
+
+ r = mysql_stmt_bind_result(d->stmt, d->inBinds);
+ if (r != 0) {
+ setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
+ "Unable to bind outvalues"), QSqlError::StatementError, d->stmt));
+ return false;
+ }
+ if (d->hasBlobs)
+ mysql_stmt_attr_set(d->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &update_max_length);
+
+ r = mysql_stmt_store_result(d->stmt);
+ if (r != 0) {
+ setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
+ "Unable to store statement results"), QSqlError::StatementError, d->stmt));
+ return false;
+ }
+
+ if (d->hasBlobs) {
+ // mysql_stmt_store_result() with STMT_ATTR_UPDATE_MAX_LENGTH set to true crashes
+ // when called without a preceding call to mysql_stmt_bind_result()
+ // in versions < 4.1.8
+ d->bindBlobs();
+ r = mysql_stmt_bind_result(d->stmt, d->inBinds);
+ if (r != 0) {
+ setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
+ "Unable to bind outvalues"), QSqlError::StatementError, d->stmt));
+ return false;
+ }
+ }
+ setAt(QSql::BeforeFirstRow);
+ }
+ setActive(true);
+ return true;
+}
+#endif
+/////////////////////////////////////////////////////////
+
+static int qMySqlConnectionCount = 0;
+static bool qMySqlInitHandledByUser = false;
+
+static void qLibraryInit()
+{
+#ifndef Q_NO_MYSQL_EMBEDDED
+# if MYSQL_VERSION_ID >= 40000
+ if (qMySqlInitHandledByUser || qMySqlConnectionCount > 1)
+ return;
+
+# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003
+ if (mysql_library_init(0, 0, 0)) {
+# else
+ if (mysql_server_init(0, 0, 0)) {
+# endif
+ qWarning("QMYSQLDriver::qServerInit: unable to start server.");
+ }
+# endif // MYSQL_VERSION_ID
+#endif // Q_NO_MYSQL_EMBEDDED
+}
+
+static void qLibraryEnd()
+{
+#ifndef Q_NO_MYSQL_EMBEDDED
+# if MYSQL_VERSION_ID > 40000
+# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003
+ mysql_library_end();
+# else
+ mysql_server_end();
+# endif
+# endif
+#endif
+}
+
+QMYSQLDriver::QMYSQLDriver(QObject * parent)
+ : QSqlDriver(*new QMYSQLDriverPrivate, parent)
+{
+ init();
+ qLibraryInit();
+}
+
+/*!
+ Create a driver instance with the open connection handle, \a con.
+ The instance's parent (owner) is \a parent.
+*/
+
+QMYSQLDriver::QMYSQLDriver(MYSQL * con, QObject * parent)
+ : QSqlDriver(*new QMYSQLDriverPrivate, parent)
+{
+ Q_D(QMYSQLDriver);
+ init();
+ if (con) {
+ d->mysql = (MYSQL *) con;
+#ifndef QT_NO_TEXTCODEC
+ d->tc = codec(con);
+#endif
+ setOpen(true);
+ setOpenError(false);
+ if (qMySqlConnectionCount == 1)
+ qMySqlInitHandledByUser = true;
+ } else {
+ qLibraryInit();
+ }
+}
+
+void QMYSQLDriver::init()
+{
+ Q_D(QMYSQLDriver);
+ d->mysql = 0;
+ qMySqlConnectionCount++;
+}
+
+QMYSQLDriver::~QMYSQLDriver()
+{
+ qMySqlConnectionCount--;
+ if (qMySqlConnectionCount == 0 && !qMySqlInitHandledByUser)
+ qLibraryEnd();
+}
+
+bool QMYSQLDriver::hasFeature(DriverFeature f) const
+{
+ Q_D(const QMYSQLDriver);
+ switch (f) {
+ case Transactions:
+// CLIENT_TRANSACTION should be defined in all recent mysql client libs > 3.23.34
+#ifdef CLIENT_TRANSACTIONS
+ if (d->mysql) {
+ if ((d->mysql->server_capabilities & CLIENT_TRANSACTIONS) == CLIENT_TRANSACTIONS)
+ return true;
+ }
+#endif
+ return false;
+ case NamedPlaceholders:
+ case BatchOperations:
+ case SimpleLocking:
+ case EventNotifications:
+ case FinishQuery:
+ case CancelQuery:
+ return false;
+ case QuerySize:
+ case BLOB:
+ case LastInsertId:
+ case Unicode:
+ case LowPrecisionNumbers:
+ return true;
+ case PreparedQueries:
+ case PositionalPlaceholders:
+#if MYSQL_VERSION_ID >= 40108
+ return d->preparedQuerysEnabled;
+#else
+ return false;
+#endif
+ case MultipleResultSets:
+#if MYSQL_VERSION_ID >= 40100
+ return true;
+#else
+ return false;
+#endif
+ }
+ return false;
+}
+
+static void setOptionFlag(uint &optionFlags, const QString &opt)
+{
+ if (opt == QLatin1String("CLIENT_COMPRESS"))
+ optionFlags |= CLIENT_COMPRESS;
+ else if (opt == QLatin1String("CLIENT_FOUND_ROWS"))
+ optionFlags |= CLIENT_FOUND_ROWS;
+ else if (opt == QLatin1String("CLIENT_IGNORE_SPACE"))
+ optionFlags |= CLIENT_IGNORE_SPACE;
+ else if (opt == QLatin1String("CLIENT_INTERACTIVE"))
+ optionFlags |= CLIENT_INTERACTIVE;
+ else if (opt == QLatin1String("CLIENT_NO_SCHEMA"))
+ optionFlags |= CLIENT_NO_SCHEMA;
+ else if (opt == QLatin1String("CLIENT_ODBC"))
+ optionFlags |= CLIENT_ODBC;
+ else if (opt == QLatin1String("CLIENT_SSL"))
+ qWarning("QMYSQLDriver: SSL_KEY, SSL_CERT and SSL_CA should be used instead of CLIENT_SSL.");
+ else
+ qWarning("QMYSQLDriver::open: Unknown connect option '%s'", opt.toLocal8Bit().constData());
+}
+
+bool QMYSQLDriver::open(const QString& db,
+ const QString& user,
+ const QString& password,
+ const QString& host,
+ int port,
+ const QString& connOpts)
+{
+ Q_D(QMYSQLDriver);
+ if (isOpen())
+ close();
+
+ /* This is a hack to get MySQL's stored procedure support working.
+ Since a stored procedure _may_ return multiple result sets,
+ we have to enable CLIEN_MULTI_STATEMENTS here, otherwise _any_
+ stored procedure call will fail.
+ */
+ unsigned int optionFlags = Q_CLIENT_MULTI_STATEMENTS;
+ const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
+ QString unixSocket;
+ QString sslCert;
+ QString sslCA;
+ QString sslKey;
+ QString sslCAPath;
+ QString sslCipher;
+#if MYSQL_VERSION_ID >= 50000
+ my_bool reconnect=false;
+ uint connectTimeout = 0;
+ uint readTimeout = 0;
+ uint writeTimeout = 0;
+#endif
+
+ // extract the real options from the string
+ for (int i = 0; i < opts.count(); ++i) {
+ QString tmp(opts.at(i).simplified());
+ int idx;
+ if ((idx = tmp.indexOf(QLatin1Char('='))) != -1) {
+ QString val = tmp.mid(idx + 1).simplified();
+ QString opt = tmp.left(idx).simplified();
+ if (opt == QLatin1String("UNIX_SOCKET"))
+ unixSocket = val;
+#if MYSQL_VERSION_ID >= 50000
+ else if (opt == QLatin1String("MYSQL_OPT_RECONNECT")) {
+ if (val == QLatin1String("TRUE") || val == QLatin1String("1") || val.isEmpty())
+ reconnect = true;
+ } else if (opt == QLatin1String("MYSQL_OPT_CONNECT_TIMEOUT")) {
+ connectTimeout = val.toInt();
+ } else if (opt == QLatin1String("MYSQL_OPT_READ_TIMEOUT")) {
+ readTimeout = val.toInt();
+ } else if (opt == QLatin1String("MYSQL_OPT_WRITE_TIMEOUT")) {
+ writeTimeout = val.toInt();
+ }
+#endif
+ else if (opt == QLatin1String("SSL_KEY"))
+ sslKey = val;
+ else if (opt == QLatin1String("SSL_CERT"))
+ sslCert = val;
+ else if (opt == QLatin1String("SSL_CA"))
+ sslCA = val;
+ else if (opt == QLatin1String("SSL_CAPATH"))
+ sslCAPath = val;
+ else if (opt == QLatin1String("SSL_CIPHER"))
+ sslCipher = val;
+ else if (val == QLatin1String("TRUE") || val == QLatin1String("1"))
+ setOptionFlag(optionFlags, tmp.left(idx).simplified());
+ else
+ qWarning("QMYSQLDriver::open: Illegal connect option value '%s'",
+ tmp.toLocal8Bit().constData());
+ } else {
+ setOptionFlag(optionFlags, tmp);
+ }
+ }
+
+ if (!(d->mysql = mysql_init((MYSQL*) 0))) {
+ setLastError(qMakeError(tr("Unable to allocate a MYSQL object"),
+ QSqlError::ConnectionError, d));
+ setOpenError(true);
+ return false;
+ }
+
+ if (!sslKey.isNull() || !sslCert.isNull() || !sslCA.isNull() ||
+ !sslCAPath.isNull() || !sslCipher.isNull()) {
+ mysql_ssl_set(d->mysql,
+ sslKey.isNull() ? static_cast<const char *>(0)
+ : QFile::encodeName(sslKey).constData(),
+ sslCert.isNull() ? static_cast<const char *>(0)
+ : QFile::encodeName(sslCert).constData(),
+ sslCA.isNull() ? static_cast<const char *>(0)
+ : QFile::encodeName(sslCA).constData(),
+ sslCAPath.isNull() ? static_cast<const char *>(0)
+ : QFile::encodeName(sslCAPath).constData(),
+ sslCipher.isNull() ? static_cast<const char *>(0)
+ : sslCipher.toLocal8Bit().constData());
+ }
+
+#if MYSQL_VERSION_ID >= 50000
+ if (connectTimeout != 0)
+ mysql_options(d->mysql, MYSQL_OPT_CONNECT_TIMEOUT, &connectTimeout);
+ if (readTimeout != 0)
+ mysql_options(d->mysql, MYSQL_OPT_READ_TIMEOUT, &readTimeout);
+ if (writeTimeout != 0)
+ mysql_options(d->mysql, MYSQL_OPT_WRITE_TIMEOUT, &writeTimeout);
+#endif
+ MYSQL *mysql = mysql_real_connect(d->mysql,
+ host.isNull() ? static_cast<const char *>(0)
+ : host.toLocal8Bit().constData(),
+ user.isNull() ? static_cast<const char *>(0)
+ : user.toLocal8Bit().constData(),
+ password.isNull() ? static_cast<const char *>(0)
+ : password.toLocal8Bit().constData(),
+ db.isNull() ? static_cast<const char *>(0)
+ : db.toLocal8Bit().constData(),
+ (port > -1) ? port : 0,
+ unixSocket.isNull() ? static_cast<const char *>(0)
+ : unixSocket.toLocal8Bit().constData(),
+ optionFlags);
+
+ if (mysql == d->mysql) {
+ if (!db.isEmpty() && mysql_select_db(d->mysql, db.toLocal8Bit().constData())) {
+ setLastError(qMakeError(tr("Unable to open database '%1'").arg(db), QSqlError::ConnectionError, d));
+ mysql_close(d->mysql);
+ setOpenError(true);
+ return false;
+ }
+#if MYSQL_VERSION_ID >= 50000
+ if (reconnect)
+ mysql_options(d->mysql, MYSQL_OPT_RECONNECT, &reconnect);
+#endif
+ } else {
+ setLastError(qMakeError(tr("Unable to connect"),
+ QSqlError::ConnectionError, d));
+ mysql_close(d->mysql);
+ d->mysql = NULL;
+ setOpenError(true);
+ return false;
+ }
+
+#if (MYSQL_VERSION_ID >= 40113 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50007
+ // force the communication to be utf8
+ mysql_set_character_set(d->mysql, "utf8");
+#endif
+#ifndef QT_NO_TEXTCODEC
+ d->tc = codec(d->mysql);
+#endif
+
+#if MYSQL_VERSION_ID >= 40108
+ d->preparedQuerysEnabled = mysql_get_client_version() >= 40108
+ && mysql_get_server_version(d->mysql) >= 40100;
+#else
+ d->preparedQuerysEnabled = false;
+#endif
+
+#ifndef QT_NO_THREAD
+ mysql_thread_init();
+#endif
+
+
+ setOpen(true);
+ setOpenError(false);
+ return true;
+}
+
+void QMYSQLDriver::close()
+{
+ Q_D(QMYSQLDriver);
+ if (isOpen()) {
+#ifndef QT_NO_THREAD
+ mysql_thread_end();
+#endif
+ mysql_close(d->mysql);
+ d->mysql = NULL;
+ setOpen(false);
+ setOpenError(false);
+ }
+}
+
+QSqlResult *QMYSQLDriver::createResult() const
+{
+ return new QMYSQLResult(this);
+}
+
+QStringList QMYSQLDriver::tables(QSql::TableType type) const
+{
+ Q_D(const QMYSQLDriver);
+ QStringList tl;
+#if MYSQL_VERSION_ID >= 40100
+ if( mysql_get_server_version(d->mysql) < 50000)
+ {
+#endif
+ if (!isOpen())
+ return tl;
+ if (!(type & QSql::Tables))
+ return tl;
+
+ MYSQL_RES* tableRes = mysql_list_tables(d->mysql, NULL);
+ MYSQL_ROW row;
+ int i = 0;
+ while (tableRes) {
+ mysql_data_seek(tableRes, i);
+ row = mysql_fetch_row(tableRes);
+ if (!row)
+ break;
+ tl.append(toUnicode(d->tc, row[0]));
+ i++;
+ }
+ mysql_free_result(tableRes);
+#if MYSQL_VERSION_ID >= 40100
+ } else {
+ QSqlQuery q(createResult());
+ if(type & QSql::Tables) {
+ QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'BASE TABLE'");
+ q.exec(sql);
+
+ while(q.next())
+ tl.append(q.value(0).toString());
+ }
+ if(type & QSql::Views) {
+ QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'VIEW'");
+ q.exec(sql);
+
+ while(q.next())
+ tl.append(q.value(0).toString());
+ }
+ }
+#endif
+ return tl;
+}
+
+QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const
+{
+ QSqlIndex idx;
+ if (!isOpen())
+ return idx;
+
+ QSqlQuery i(createResult());
+ QString stmt(QLatin1String("show index from %1;"));
+ QSqlRecord fil = record(tablename);
+ i.exec(stmt.arg(tablename));
+ while (i.isActive() && i.next()) {
+ if (i.value(2).toString() == QLatin1String("PRIMARY")) {
+ idx.append(fil.field(i.value(4).toString()));
+ idx.setCursorName(i.value(0).toString());
+ idx.setName(i.value(2).toString());
+ }
+ }
+
+ return idx;
+}
+
+QSqlRecord QMYSQLDriver::record(const QString& tablename) const
+{
+ Q_D(const QMYSQLDriver);
+ QString table=tablename;
+ if(isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+
+ QSqlRecord info;
+ if (!isOpen())
+ return info;
+ MYSQL_RES* r = mysql_list_fields(d->mysql, table.toLocal8Bit().constData(), 0);
+ if (!r) {
+ return info;
+ }
+ MYSQL_FIELD* field;
+
+ while ((field = mysql_fetch_field(r)))
+ info.append(qToField(field, d->tc));
+ mysql_free_result(r);
+ return info;
+}
+
+QVariant QMYSQLDriver::handle() const
+{
+ Q_D(const QMYSQLDriver);
+ return QVariant::fromValue(d->mysql);
+}
+
+bool QMYSQLDriver::beginTransaction()
+{
+ Q_D(QMYSQLDriver);
+#ifndef CLIENT_TRANSACTIONS
+ return false;
+#endif
+ if (!isOpen()) {
+ qWarning("QMYSQLDriver::beginTransaction: Database not open");
+ return false;
+ }
+ if (mysql_query(d->mysql, "BEGIN WORK")) {
+ setLastError(qMakeError(tr("Unable to begin transaction"),
+ QSqlError::StatementError, d));
+ return false;
+ }
+ return true;
+}
+
+bool QMYSQLDriver::commitTransaction()
+{
+ Q_D(QMYSQLDriver);
+#ifndef CLIENT_TRANSACTIONS
+ return false;
+#endif
+ if (!isOpen()) {
+ qWarning("QMYSQLDriver::commitTransaction: Database not open");
+ return false;
+ }
+ if (mysql_query(d->mysql, "COMMIT")) {
+ setLastError(qMakeError(tr("Unable to commit transaction"),
+ QSqlError::StatementError, d));
+ return false;
+ }
+ return true;
+}
+
+bool QMYSQLDriver::rollbackTransaction()
+{
+ Q_D(QMYSQLDriver);
+#ifndef CLIENT_TRANSACTIONS
+ return false;
+#endif
+ if (!isOpen()) {
+ qWarning("QMYSQLDriver::rollbackTransaction: Database not open");
+ return false;
+ }
+ if (mysql_query(d->mysql, "ROLLBACK")) {
+ setLastError(qMakeError(tr("Unable to rollback transaction"),
+ QSqlError::StatementError, d));
+ return false;
+ }
+ return true;
+}
+
+QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
+{
+ Q_D(const QMYSQLDriver);
+ QString r;
+ if (field.isNull()) {
+ r = QLatin1String("NULL");
+ } else {
+ switch(field.type()) {
+ case QVariant::Double:
+ r = QString::number(field.value().toDouble(), 'g', field.precision());
+ break;
+ case QVariant::String:
+ // Escape '\' characters
+ r = QSqlDriver::formatValue(field, trimStrings);
+ r.replace(QLatin1String("\\"), QLatin1String("\\\\"));
+ break;
+ case QVariant::ByteArray:
+ if (isOpen()) {
+ const QByteArray ba = field.value().toByteArray();
+ // buffer has to be at least length*2+1 bytes
+ char* buffer = new char[ba.size() * 2 + 1];
+ int escapedSize = int(mysql_real_escape_string(d->mysql, buffer,
+ ba.data(), ba.size()));
+ r.reserve(escapedSize + 3);
+ r.append(QLatin1Char('\'')).append(toUnicode(d->tc, buffer)).append(QLatin1Char('\''));
+ delete[] buffer;
+ break;
+ } else {
+ qWarning("QMYSQLDriver::formatValue: Database not open");
+ }
+ // fall through
+ default:
+ r = QSqlDriver::formatValue(field, trimStrings);
+ }
+ }
+ return r;
+}
+
+QString QMYSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
+{
+ QString res = identifier;
+ if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('`')) && !identifier.endsWith(QLatin1Char('`')) ) {
+ res.prepend(QLatin1Char('`')).append(QLatin1Char('`'));
+ res.replace(QLatin1Char('.'), QLatin1String("`.`"));
+ }
+ return res;
+}
+
+bool QMYSQLDriver::isIdentifierEscaped(const QString &identifier, IdentifierType type) const
+{
+ Q_UNUSED(type);
+ return identifier.size() > 2
+ && identifier.startsWith(QLatin1Char('`')) //left delimited
+ && identifier.endsWith(QLatin1Char('`')); //right delimited
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql_p.h b/src/plugins/sqldrivers/mysql/qsql_mysql_p.h
new file mode 100644
index 0000000000..7641f9aa34
--- /dev/null
+++ b/src/plugins/sqldrivers/mysql/qsql_mysql_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSQL_MYSQL_H
+#define QSQL_MYSQL_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 <QtSql/qsqldriver.h>
+
+#if defined (Q_OS_WIN32)
+#include <QtCore/qt_windows.h>
+#endif
+
+#include <mysql.h>
+
+#ifdef QT_PLUGIN
+#define Q_EXPORT_SQLDRIVER_MYSQL
+#else
+#define Q_EXPORT_SQLDRIVER_MYSQL Q_SQL_EXPORT
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QMYSQLDriverPrivate;
+
+class Q_EXPORT_SQLDRIVER_MYSQL QMYSQLDriver : public QSqlDriver
+{
+ friend class QMYSQLResultPrivate;
+ Q_DECLARE_PRIVATE(QMYSQLDriver)
+ Q_OBJECT
+public:
+ explicit QMYSQLDriver(QObject *parent=0);
+ explicit QMYSQLDriver(MYSQL *con, QObject * parent=0);
+ ~QMYSQLDriver();
+ bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
+ bool open(const QString & db,
+ const QString & user,
+ const QString & password,
+ const QString & host,
+ int port,
+ const QString& connOpts) Q_DECL_OVERRIDE;
+ void close() Q_DECL_OVERRIDE;
+ QSqlResult *createResult() const Q_DECL_OVERRIDE;
+ QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
+ QSqlIndex primaryIndex(const QString& tablename) const Q_DECL_OVERRIDE;
+ QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE;
+ QString formatValue(const QSqlField &field,
+ bool trimStrings) const Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+ QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
+
+ bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
+
+protected:
+ bool beginTransaction() Q_DECL_OVERRIDE;
+ bool commitTransaction() Q_DECL_OVERRIDE;
+ bool rollbackTransaction() Q_DECL_OVERRIDE;
+private:
+ void init();
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQL_MYSQL_H
diff --git a/src/plugins/sqldrivers/oci/main.cpp b/src/plugins/sqldrivers/oci/main.cpp
index 980116123d..e576928d31 100644
--- a/src/plugins/sqldrivers/oci/main.cpp
+++ b/src/plugins/sqldrivers/oci/main.cpp
@@ -39,7 +39,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/oci/qsql_oci_p.h"
+#include "qsql_oci_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/oci/oci.pro b/src/plugins/sqldrivers/oci/oci.pro
index 96a0dd9ab6..a22d1181bf 100644
--- a/src/plugins/sqldrivers/oci/oci.pro
+++ b/src/plugins/sqldrivers/oci/oci.pro
@@ -1,8 +1,16 @@
TARGET = qsqloci
-SOURCES = main.cpp
+HEADERS += $$PWD/qsql_oci_p.h
+SOURCES += $$PWD/qsql_oci.cpp $$PWD/main.cpp
+
+unix {
+ !contains(LIBS, .*clnts.*):LIBS += -lclntsh
+} else {
+ LIBS *= -loci
+}
+darwin:QMAKE_LFLAGS += -Wl,-flat_namespace,-U,_environ
+
OTHER_FILES += oci.json
-include(../../../sql/drivers/oci/qsql_oci.pri)
PLUGIN_CLASS_NAME = QOCIDriverPlugin
include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp
new file mode 100644
index 0000000000..47d6db7ea4
--- /dev/null
+++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp
@@ -0,0 +1,2725 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsql_oci_p.h"
+
+#include <qcoreapplication.h>
+#include <qvariant.h>
+#include <qdatetime.h>
+#include <qmetatype.h>
+#include <qregexp.h>
+#include <qshareddata.h>
+#include <qsqlerror.h>
+#include <qsqlfield.h>
+#include <qsqlindex.h>
+#include <qsqlquery.h>
+#include <QtSql/private/qsqlcachedresult_p.h>
+#include <QtSql/private/qsqldriver_p.h>
+#include <qstringlist.h>
+#include <qvarlengtharray.h>
+#include <qvector.h>
+#include <qdebug.h>
+
+// This is needed for oracle oci when compiling with mingw-w64 headers
+#if defined(__MINGW64_VERSION_MAJOR) && defined(_WIN64)
+#define _int64 __int64
+#endif
+
+
+#include <oci.h>
+#ifdef max
+#undef max
+#endif
+#ifdef min
+#undef min
+#endif
+
+#include <stdlib.h>
+
+#define QOCI_DYNAMIC_CHUNK_SIZE 65535
+#define QOCI_PREFETCH_MEM 10240
+
+// setting this define will allow using a query from a different
+// thread than its database connection.
+// warning - this is not fully tested and can lead to race conditions
+#define QOCI_THREADED
+
+//#define QOCI_DEBUG
+
+Q_DECLARE_OPAQUE_POINTER(OCIEnv*);
+Q_DECLARE_METATYPE(OCIEnv*)
+Q_DECLARE_OPAQUE_POINTER(OCIStmt*);
+Q_DECLARE_METATYPE(OCIStmt*)
+
+QT_BEGIN_NAMESPACE
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+enum { QOCIEncoding = 2002 }; // AL16UTF16LE
+#else
+enum { QOCIEncoding = 2000 }; // AL16UTF16
+#endif
+
+#ifdef OCI_ATTR_CHARSET_FORM
+// Always set the OCI_ATTR_CHARSET_FORM to SQLCS_NCHAR is safe
+// because Oracle server will deal with the implicit Conversion
+// Between CHAR and NCHAR.
+// see: http://download.oracle.com/docs/cd/A91202_01/901_doc/appdev.901/a89857/oci05bnd.htm#422705
+static const ub1 qOraCharsetForm = SQLCS_NCHAR;
+#endif
+
+#if defined (OCI_UTF16ID)
+static const ub2 qOraCharset = OCI_UTF16ID;
+#else
+static const ub2 qOraCharset = OCI_UCS2ID;
+#endif
+
+typedef QVarLengthArray<sb2, 32> IndicatorArray;
+typedef QVarLengthArray<ub2, 32> SizeArray;
+
+static QByteArray qMakeOraDate(const QDateTime& dt);
+static QDateTime qMakeDate(const char* oraDate);
+
+static QByteArray qMakeOCINumber(const qlonglong &ll, OCIError *err);
+static QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err);
+
+static qlonglong qMakeLongLong(const char* ociNumber, OCIError* err);
+static qulonglong qMakeULongLong(const char* ociNumber, OCIError* err);
+
+static QString qOraWarn(OCIError *err, int *errorCode = 0);
+
+#ifndef Q_CC_SUN
+static // for some reason, Sun CC can't use qOraWarning when it's declared static
+#endif
+void qOraWarning(const char* msg, OCIError *err);
+static QSqlError qMakeError(const QString& errString, QSqlError::ErrorType type, OCIError *err);
+
+
+
+class QOCIRowId: public QSharedData
+{
+public:
+ QOCIRowId(OCIEnv *env);
+ ~QOCIRowId();
+
+ OCIRowid *id;
+
+private:
+ QOCIRowId(const QOCIRowId &other): QSharedData(other) { Q_ASSERT(false); }
+};
+
+QOCIRowId::QOCIRowId(OCIEnv *env)
+ : id(0)
+{
+ OCIDescriptorAlloc (env, reinterpret_cast<dvoid **>(&id),
+ OCI_DTYPE_ROWID, 0, 0);
+}
+
+QOCIRowId::~QOCIRowId()
+{
+ if (id)
+ OCIDescriptorFree(id, OCI_DTYPE_ROWID);
+}
+
+typedef QSharedDataPointer<QOCIRowId> QOCIRowIdPointer;
+QT_BEGIN_INCLUDE_NAMESPACE
+Q_DECLARE_METATYPE(QOCIRowIdPointer)
+QT_END_INCLUDE_NAMESPACE
+
+class QOCIDriverPrivate : public QSqlDriverPrivate
+{
+ Q_DECLARE_PUBLIC(QOCIDriver)
+
+public:
+ QOCIDriverPrivate();
+
+ OCIEnv *env;
+ OCISvcCtx *svc;
+ OCIServer *srvhp;
+ OCISession *authp;
+ OCIError *err;
+ bool transaction;
+ int serverVersion;
+ int prefetchRows;
+ int prefetchMem;
+ QString user;
+
+ void allocErrorHandle();
+};
+
+class QOCICols;
+class QOCIResultPrivate;
+
+class QOCIResult: public QSqlCachedResult
+{
+ Q_DECLARE_PRIVATE(QOCIResult)
+ friend class QOCIDriver;
+ friend class QOCICols;
+public:
+ QOCIResult(const QOCIDriver *db);
+ ~QOCIResult();
+ bool prepare(const QString &query) Q_DECL_OVERRIDE;
+ bool exec() Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+
+protected:
+ bool gotoNext(ValueCache &values, int index) Q_DECL_OVERRIDE;
+ bool reset(const QString &query) Q_DECL_OVERRIDE;
+ int size() Q_DECL_OVERRIDE;
+ int numRowsAffected() Q_DECL_OVERRIDE;
+ QSqlRecord record() const Q_DECL_OVERRIDE;
+ QVariant lastInsertId() const Q_DECL_OVERRIDE;
+ bool execBatch(bool arrayBind = false) Q_DECL_OVERRIDE;
+ void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
+};
+
+class QOCIResultPrivate: public QSqlCachedResultPrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QOCIResult)
+ Q_DECLARE_SQLDRIVER_PRIVATE(QOCIDriver)
+ QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv);
+ ~QOCIResultPrivate();
+
+ QOCICols *cols;
+ OCIEnv *env;
+ OCIError *err;
+ OCISvcCtx *&svc;
+ OCIStmt *sql;
+ bool transaction;
+ int serverVersion;
+ int prefetchRows, prefetchMem;
+
+ void setStatementAttributes();
+ int bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos,
+ const QVariant &val, dvoid *indPtr, ub2 *tmpSize, QList<QByteArray> &tmpStorage);
+ int bindValues(QVector<QVariant> &values, IndicatorArray &indicators, SizeArray &tmpSizes,
+ QList<QByteArray> &tmpStorage);
+ void outValues(QVector<QVariant> &values, IndicatorArray &indicators,
+ QList<QByteArray> &tmpStorage);
+ inline bool isOutValue(int i) const
+ { Q_Q(const QOCIResult); return q->bindValueType(i) & QSql::Out; }
+ inline bool isBinaryValue(int i) const
+ { Q_Q(const QOCIResult); return q->bindValueType(i) & QSql::Binary; }
+
+ void setCharset(dvoid* handle, ub4 type) const
+ {
+ int r = 0;
+ Q_ASSERT(handle);
+
+#ifdef OCI_ATTR_CHARSET_FORM
+ r = OCIAttrSet(handle,
+ type,
+ // this const cast is safe since OCI doesn't touch
+ // the charset.
+ const_cast<void *>(static_cast<const void *>(&qOraCharsetForm)),
+ 0,
+ OCI_ATTR_CHARSET_FORM,
+ //Strange Oracle bug: some Oracle servers crash the server process with non-zero error handle (mostly for 10g).
+ //So ignore the error message here.
+ 0);
+ #ifdef QOCI_DEBUG
+ if (r != 0)
+ qWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM.");
+ #endif
+#endif
+
+ r = OCIAttrSet(handle,
+ type,
+ // this const cast is safe since OCI doesn't touch
+ // the charset.
+ const_cast<void *>(static_cast<const void *>(&qOraCharset)),
+ 0,
+ OCI_ATTR_CHARSET_ID,
+ err);
+ if (r != 0)
+ qOraWarning("QOCIResultPrivate::setCharsetI Couldn't set OCI_ATTR_CHARSET_ID: ", err);
+
+ }
+};
+
+void QOCIResultPrivate::setStatementAttributes()
+{
+ Q_ASSERT(sql);
+
+ int r = 0;
+
+ if (prefetchRows >= 0) {
+ r = OCIAttrSet(sql,
+ OCI_HTYPE_STMT,
+ &prefetchRows,
+ 0,
+ OCI_ATTR_PREFETCH_ROWS,
+ err);
+ if (r != 0)
+ qOraWarning("QOCIResultPrivate::setStatementAttributes:"
+ " Couldn't set OCI_ATTR_PREFETCH_ROWS: ", err);
+ }
+ if (prefetchMem >= 0) {
+ r = OCIAttrSet(sql,
+ OCI_HTYPE_STMT,
+ &prefetchMem,
+ 0,
+ OCI_ATTR_PREFETCH_MEMORY,
+ err);
+ if (r != 0)
+ qOraWarning("QOCIResultPrivate::setStatementAttributes:"
+ " Couldn't set OCI_ATTR_PREFETCH_MEMORY: ", err);
+ }
+}
+
+int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos,
+ const QVariant &val, dvoid *indPtr, ub2 *tmpSize, QList<QByteArray> &tmpStorage)
+{
+ int r = OCI_SUCCESS;
+ void *data = const_cast<void *>(val.constData());
+
+ switch (val.type()) {
+ case QVariant::ByteArray:
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ isOutValue(pos)
+ ? const_cast<char *>(reinterpret_cast<QByteArray *>(data)->constData())
+ : reinterpret_cast<QByteArray *>(data)->data(),
+ reinterpret_cast<QByteArray *>(data)->size(),
+ SQLT_BIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ break;
+ case QVariant::Time:
+ case QVariant::Date:
+ case QVariant::DateTime: {
+ QByteArray ba = qMakeOraDate(val.toDateTime());
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ ba.data(),
+ ba.size(),
+ SQLT_DAT, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ tmpStorage.append(ba);
+ break; }
+ case QVariant::Int:
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ // if it's an out value, the data is already detached
+ // so the const cast is safe.
+ const_cast<void *>(data),
+ sizeof(int),
+ SQLT_INT, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ break;
+ case QVariant::UInt:
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ // if it's an out value, the data is already detached
+ // so the const cast is safe.
+ const_cast<void *>(data),
+ sizeof(uint),
+ SQLT_UIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ break;
+ case QVariant::LongLong:
+ {
+ QByteArray ba = qMakeOCINumber(val.toLongLong(), err);
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ ba.data(),
+ ba.size(),
+ SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ tmpStorage.append(ba);
+ break;
+ }
+ case QVariant::ULongLong:
+ {
+ QByteArray ba = qMakeOCINumber(val.toULongLong(), err);
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ ba.data(),
+ ba.size(),
+ SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ tmpStorage.append(ba);
+ break;
+ }
+ case QVariant::Double:
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ // if it's an out value, the data is already detached
+ // so the const cast is safe.
+ const_cast<void *>(data),
+ sizeof(double),
+ SQLT_FLT, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ break;
+ case QVariant::UserType:
+ if (val.canConvert<QOCIRowIdPointer>() && !isOutValue(pos)) {
+ // use a const pointer to prevent a detach
+ const QOCIRowIdPointer rptr = qvariant_cast<QOCIRowIdPointer>(val);
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ // it's an IN value, so const_cast is ok
+ const_cast<OCIRowid **>(&rptr->id),
+ -1,
+ SQLT_RDD, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ } else {
+ qWarning("Unknown bind variable");
+ r = OCI_ERROR;
+ }
+ break;
+ case QVariant::String: {
+ const QString s = val.toString();
+ if (isBinaryValue(pos)) {
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ const_cast<ushort *>(s.utf16()),
+ s.length() * sizeof(QChar),
+ SQLT_LNG, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ break;
+ } else if (!isOutValue(pos)) {
+ // don't detach the string
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ // safe since oracle doesn't touch OUT values
+ const_cast<ushort *>(s.utf16()),
+ (s.length() + 1) * sizeof(QChar),
+ SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ if (r == OCI_SUCCESS)
+ setCharset(*hbnd, OCI_HTYPE_BIND);
+ break;
+ }
+ } // fall through for OUT values
+ default: {
+ const QString s = val.toString();
+ // create a deep-copy
+ QByteArray ba(reinterpret_cast<const char *>(s.utf16()), (s.length() + 1) * sizeof(QChar));
+ if (isOutValue(pos)) {
+ ba.reserve((s.capacity() + 1) * sizeof(QChar));
+ *tmpSize = ba.size();
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ ba.data(),
+ ba.capacity(),
+ SQLT_STR, indPtr, tmpSize, 0, 0, 0, OCI_DEFAULT);
+ } else {
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ ba.data(),
+ ba.size(),
+ SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ }
+ if (r == OCI_SUCCESS)
+ setCharset(*hbnd, OCI_HTYPE_BIND);
+ tmpStorage.append(ba);
+ break;
+ } // default case
+ } // switch
+ if (r != OCI_SUCCESS)
+ qOraWarning("QOCIResultPrivate::bindValue:", err);
+ return r;
+}
+
+int QOCIResultPrivate::bindValues(QVector<QVariant> &values, IndicatorArray &indicators,
+ SizeArray &tmpSizes, QList<QByteArray> &tmpStorage)
+{
+ int r = OCI_SUCCESS;
+ for (int i = 0; i < values.count(); ++i) {
+ if (isOutValue(i))
+ values[i].detach();
+ const QVariant &val = values.at(i);
+
+ OCIBind * hbnd = 0; // Oracle handles these automatically
+ sb2 *indPtr = &indicators[i];
+ *indPtr = val.isNull() ? -1 : 0;
+
+ bindValue(sql, &hbnd, err, i, val, indPtr, &tmpSizes[i], tmpStorage);
+ }
+ return r;
+}
+
+// will assign out value and remove its temp storage.
+static void qOraOutValue(QVariant &value, QList<QByteArray> &storage, OCIError* err)
+{
+ switch (value.type()) {
+ case QVariant::Time:
+ value = qMakeDate(storage.takeFirst()).time();
+ break;
+ case QVariant::Date:
+ value = qMakeDate(storage.takeFirst()).date();
+ break;
+ case QVariant::DateTime:
+ value = qMakeDate(storage.takeFirst());
+ break;
+ case QVariant::LongLong:
+ value = qMakeLongLong(storage.takeFirst(), err);
+ break;
+ case QVariant::ULongLong:
+ value = qMakeULongLong(storage.takeFirst(), err);
+ break;
+ case QVariant::String:
+ value = QString(
+ reinterpret_cast<const QChar *>(storage.takeFirst().constData()));
+ break;
+ default:
+ break; //nothing
+ }
+}
+
+void QOCIResultPrivate::outValues(QVector<QVariant> &values, IndicatorArray &indicators,
+ QList<QByteArray> &tmpStorage)
+{
+ for (int i = 0; i < values.count(); ++i) {
+
+ if (!isOutValue(i))
+ continue;
+
+ qOraOutValue(values[i], tmpStorage, err);
+
+ QVariant::Type typ = values.at(i).type();
+ if (indicators[i] == -1) // NULL
+ values[i] = QVariant(typ);
+ else
+ values[i] = QVariant(typ, values.at(i).constData());
+ }
+}
+
+
+QOCIDriverPrivate::QOCIDriverPrivate()
+ : QSqlDriverPrivate(), env(0), svc(0), srvhp(0), authp(0), err(0), transaction(false),
+ serverVersion(-1), prefetchRows(-1), prefetchMem(QOCI_PREFETCH_MEM)
+{
+ dbmsType = QSqlDriver::Oracle;
+}
+
+void QOCIDriverPrivate::allocErrorHandle()
+{
+ int r = OCIHandleAlloc(env,
+ reinterpret_cast<void **>(&err),
+ OCI_HTYPE_ERROR,
+ 0,
+ 0);
+ if (r != 0)
+ qWarning("QOCIDriver: unable to allocate error handle");
+}
+
+struct OraFieldInfo
+{
+ QString name;
+ QVariant::Type type;
+ ub1 oraIsNull;
+ ub4 oraType;
+ sb1 oraScale;
+ ub4 oraLength; // size in bytes
+ ub4 oraFieldLength; // amount of characters
+ sb2 oraPrecision;
+};
+
+QString qOraWarn(OCIError *err, int *errorCode)
+{
+ sb4 errcode;
+ text errbuf[1024];
+ errbuf[0] = 0;
+ errbuf[1] = 0;
+
+ OCIErrorGet(err,
+ 1,
+ 0,
+ &errcode,
+ errbuf,
+ sizeof(errbuf),
+ OCI_HTYPE_ERROR);
+ if (errorCode)
+ *errorCode = errcode;
+ return QString(reinterpret_cast<const QChar *>(errbuf));
+}
+
+void qOraWarning(const char* msg, OCIError *err)
+{
+#ifdef QOCI_DEBUG
+ qWarning("%s %s", msg, qPrintable(qOraWarn(err)));
+#else
+ Q_UNUSED(msg);
+ Q_UNUSED(err);
+#endif
+}
+
+static int qOraErrorNumber(OCIError *err)
+{
+ sb4 errcode;
+ OCIErrorGet(err,
+ 1,
+ 0,
+ &errcode,
+ 0,
+ 0,
+ OCI_HTYPE_ERROR);
+ return errcode;
+}
+
+QSqlError qMakeError(const QString& errString, QSqlError::ErrorType type, OCIError *err)
+{
+ int errorCode = 0;
+ const QString oraErrorString = qOraWarn(err, &errorCode);
+ return QSqlError(errString, oraErrorString, type, errorCode);
+}
+
+QVariant::Type qDecodeOCIType(const QString& ocitype, QSql::NumericalPrecisionPolicy precisionPolicy)
+{
+ QVariant::Type type = QVariant::Invalid;
+ if (ocitype == QLatin1String("VARCHAR2") || ocitype == QLatin1String("VARCHAR")
+ || ocitype.startsWith(QLatin1String("INTERVAL"))
+ || ocitype == QLatin1String("CHAR") || ocitype == QLatin1String("NVARCHAR2")
+ || ocitype == QLatin1String("NCHAR"))
+ type = QVariant::String;
+ else if (ocitype == QLatin1String("NUMBER")
+ || ocitype == QLatin1String("FLOAT")
+ || ocitype == QLatin1String("BINARY_FLOAT")
+ || ocitype == QLatin1String("BINARY_DOUBLE")) {
+ switch(precisionPolicy) {
+ case QSql::LowPrecisionInt32:
+ type = QVariant::Int;
+ break;
+ case QSql::LowPrecisionInt64:
+ type = QVariant::LongLong;
+ break;
+ case QSql::LowPrecisionDouble:
+ type = QVariant::Double;
+ break;
+ case QSql::HighPrecision:
+ default:
+ type = QVariant::String;
+ break;
+ }
+ }
+ else if (ocitype == QLatin1String("LONG") || ocitype == QLatin1String("NCLOB")
+ || ocitype == QLatin1String("CLOB"))
+ type = QVariant::ByteArray;
+ else if (ocitype == QLatin1String("RAW") || ocitype == QLatin1String("LONG RAW")
+ || ocitype == QLatin1String("ROWID") || ocitype == QLatin1String("BLOB")
+ || ocitype == QLatin1String("CFILE") || ocitype == QLatin1String("BFILE"))
+ type = QVariant::ByteArray;
+ else if (ocitype == QLatin1String("DATE") || ocitype.startsWith(QLatin1String("TIME")))
+ type = QVariant::DateTime;
+ else if (ocitype == QLatin1String("UNDEFINED"))
+ type = QVariant::Invalid;
+ if (type == QVariant::Invalid)
+ qWarning("qDecodeOCIType: unknown type: %s", ocitype.toLocal8Bit().constData());
+ return type;
+}
+
+QVariant::Type qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precisionPolicy)
+{
+ QVariant::Type type = QVariant::Invalid;
+ switch (ocitype) {
+ case SQLT_STR:
+ case SQLT_VST:
+ case SQLT_CHR:
+ case SQLT_AFC:
+ case SQLT_VCS:
+ case SQLT_AVC:
+ case SQLT_RDD:
+ case SQLT_LNG:
+#ifdef SQLT_INTERVAL_YM
+ case SQLT_INTERVAL_YM:
+#endif
+#ifdef SQLT_INTERVAL_DS
+ case SQLT_INTERVAL_DS:
+#endif
+ type = QVariant::String;
+ break;
+ case SQLT_INT:
+ type = QVariant::Int;
+ break;
+ case SQLT_FLT:
+ case SQLT_NUM:
+ case SQLT_VNU:
+ case SQLT_UIN:
+ switch(precisionPolicy) {
+ case QSql::LowPrecisionInt32:
+ type = QVariant::Int;
+ break;
+ case QSql::LowPrecisionInt64:
+ type = QVariant::LongLong;
+ break;
+ case QSql::LowPrecisionDouble:
+ type = QVariant::Double;
+ break;
+ case QSql::HighPrecision:
+ default:
+ type = QVariant::String;
+ break;
+ }
+ break;
+ case SQLT_VBI:
+ case SQLT_BIN:
+ case SQLT_LBI:
+ case SQLT_LVC:
+ case SQLT_LVB:
+ case SQLT_BLOB:
+ case SQLT_CLOB:
+ case SQLT_FILE:
+ case SQLT_NTY:
+ case SQLT_REF:
+ case SQLT_RID:
+ type = QVariant::ByteArray;
+ break;
+ case SQLT_DAT:
+ case SQLT_ODT:
+#ifdef SQLT_TIMESTAMP
+ case SQLT_TIMESTAMP:
+ case SQLT_TIMESTAMP_TZ:
+ case SQLT_TIMESTAMP_LTZ:
+#endif
+ type = QVariant::DateTime;
+ break;
+ default:
+ type = QVariant::Invalid;
+ qWarning("qDecodeOCIType: unknown OCI datatype: %d", ocitype);
+ break;
+ }
+ return type;
+}
+
+static QSqlField qFromOraInf(const OraFieldInfo &ofi)
+{
+ QSqlField f(ofi.name, ofi.type);
+ f.setRequired(ofi.oraIsNull == 0);
+
+ if (ofi.type == QVariant::String && ofi.oraType != SQLT_NUM && ofi.oraType != SQLT_VNU)
+ f.setLength(ofi.oraFieldLength);
+ else
+ f.setLength(ofi.oraPrecision == 0 ? 38 : int(ofi.oraPrecision));
+
+ f.setPrecision(ofi.oraScale);
+ f.setSqlType(int(ofi.oraType));
+ return f;
+}
+
+/*!
+ \internal
+
+ Convert QDateTime to the internal Oracle DATE format NB!
+ It does not handle BCE dates.
+*/
+QByteArray qMakeOraDate(const QDateTime& dt)
+{
+ QByteArray ba;
+ ba.resize(7);
+ int year = dt.date().year();
+ ba[0]= (year / 100) + 100; // century
+ ba[1]= (year % 100) + 100; // year
+ ba[2]= dt.date().month();
+ ba[3]= dt.date().day();
+ ba[4]= dt.time().hour() + 1;
+ ba[5]= dt.time().minute() + 1;
+ ba[6]= dt.time().second() + 1;
+ return ba;
+}
+
+/*!
+ \internal
+
+ Convert qlonglong to the internal Oracle OCINumber format.
+ */
+QByteArray qMakeOCINumber(const qlonglong& ll, OCIError* err)
+{
+ QByteArray ba(sizeof(OCINumber), 0);
+
+ OCINumberFromInt(err,
+ &ll,
+ sizeof(qlonglong),
+ OCI_NUMBER_SIGNED,
+ reinterpret_cast<OCINumber*>(ba.data()));
+ return ba;
+}
+
+/*!
+ \internal
+
+ Convert qulonglong to the internal Oracle OCINumber format.
+ */
+QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err)
+{
+ QByteArray ba(sizeof(OCINumber), 0);
+
+ OCINumberFromInt(err,
+ &ull,
+ sizeof(qlonglong),
+ OCI_NUMBER_UNSIGNED,
+ reinterpret_cast<OCINumber*>(ba.data()));
+ return ba;
+}
+
+qlonglong qMakeLongLong(const char* ociNumber, OCIError* err)
+{
+ qlonglong qll = 0;
+ OCINumberToInt(err, reinterpret_cast<const OCINumber *>(ociNumber), sizeof(qlonglong),
+ OCI_NUMBER_SIGNED, &qll);
+ return qll;
+}
+
+qulonglong qMakeULongLong(const char* ociNumber, OCIError* err)
+{
+ qulonglong qull = 0;
+ OCINumberToInt(err, reinterpret_cast<const OCINumber *>(ociNumber), sizeof(qulonglong),
+ OCI_NUMBER_UNSIGNED, &qull);
+ return qull;
+}
+
+QDateTime qMakeDate(const char* oraDate)
+{
+ int century = uchar(oraDate[0]);
+ if(century >= 100){
+ int year = uchar(oraDate[1]);
+ year = ((century-100)*100) + (year-100);
+ int month = oraDate[2];
+ int day = oraDate[3];
+ int hour = oraDate[4] - 1;
+ int min = oraDate[5] - 1;
+ int sec = oraDate[6] - 1;
+ return QDateTime(QDate(year,month,day), QTime(hour,min,sec));
+ }
+ return QDateTime();
+}
+
+class QOCICols
+{
+public:
+ QOCICols(int size, QOCIResultPrivate* dp);
+ ~QOCICols();
+ int readPiecewise(QVector<QVariant> &values, int index = 0);
+ int readLOBs(QVector<QVariant> &values, int index = 0);
+ int fieldFromDefine(OCIDefine* d);
+ void getValues(QVector<QVariant> &v, int index);
+ inline int size() { return fieldInf.size(); }
+ static bool execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, bool arrayBind);
+
+ QSqlRecord rec;
+
+private:
+ char* create(int position, int size);
+ OCILobLocator ** createLobLocator(int position, OCIEnv* env);
+ OraFieldInfo qMakeOraField(const QOCIResultPrivate* p, OCIParam* param) const;
+
+ class OraFieldInf
+ {
+ public:
+ OraFieldInf(): data(0), len(0), ind(0), typ(QVariant::Invalid), oraType(0), def(0), lob(0)
+ {}
+ ~OraFieldInf();
+ char *data;
+ int len;
+ sb2 ind;
+ QVariant::Type typ;
+ ub4 oraType;
+ OCIDefine *def;
+ OCILobLocator *lob;
+ };
+
+ QVector<OraFieldInf> fieldInf;
+ const QOCIResultPrivate *const d;
+};
+
+QOCICols::OraFieldInf::~OraFieldInf()
+{
+ delete [] data;
+ if (lob) {
+ int r = OCIDescriptorFree(lob, OCI_DTYPE_LOB);
+ if (r != 0)
+ qWarning("QOCICols: Cannot free LOB descriptor");
+ }
+}
+
+QOCICols::QOCICols(int size, QOCIResultPrivate* dp)
+ : fieldInf(size), d(dp)
+{
+ ub4 dataSize = 0;
+ OCIDefine* dfn = 0;
+ int r;
+
+ OCIParam* param = 0;
+ sb4 parmStatus = 0;
+ ub4 count = 1;
+ int idx = 0;
+ parmStatus = OCIParamGet(d->sql,
+ OCI_HTYPE_STMT,
+ d->err,
+ reinterpret_cast<void **>(&param),
+ count);
+
+ while (parmStatus == OCI_SUCCESS) {
+ OraFieldInfo ofi = qMakeOraField(d, param);
+ if (ofi.oraType == SQLT_RDD)
+ dataSize = 50;
+#ifdef SQLT_INTERVAL_YM
+#ifdef SQLT_INTERVAL_DS
+ else if (ofi.oraType == SQLT_INTERVAL_YM || ofi.oraType == SQLT_INTERVAL_DS)
+ // since we are binding interval datatype as string,
+ // we are not interested in the number of bytes but characters.
+ dataSize = 50; // magic number
+#endif //SQLT_INTERVAL_DS
+#endif //SQLT_INTERVAL_YM
+ else if (ofi.oraType == SQLT_NUM || ofi.oraType == SQLT_VNU){
+ if (ofi.oraPrecision > 0)
+ dataSize = (ofi.oraPrecision + 1) * sizeof(utext);
+ else
+ dataSize = (38 + 1) * sizeof(utext);
+ }
+ else
+ dataSize = ofi.oraLength;
+
+ fieldInf[idx].typ = ofi.type;
+ fieldInf[idx].oraType = ofi.oraType;
+ rec.append(qFromOraInf(ofi));
+
+ switch (ofi.type) {
+ case QVariant::DateTime:
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ create(idx, dataSize+1),
+ dataSize+1,
+ SQLT_DAT,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DEFAULT);
+ break;
+ case QVariant::Double:
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ create(idx, sizeof(double) - 1),
+ sizeof(double),
+ SQLT_FLT,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DEFAULT);
+ break;
+ case QVariant::Int:
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ create(idx, sizeof(qint32) - 1),
+ sizeof(qint32),
+ SQLT_INT,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DEFAULT);
+ break;
+ case QVariant::LongLong:
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ create(idx, sizeof(OCINumber)),
+ sizeof(OCINumber),
+ SQLT_VNU,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DEFAULT);
+ break;
+ case QVariant::ByteArray:
+ // RAW and LONG RAW fields can't be bound to LOB locators
+ if (ofi.oraType == SQLT_BIN) {
+// qDebug("binding SQLT_BIN");
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ create(idx, dataSize),
+ dataSize,
+ SQLT_BIN,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DYNAMIC_FETCH);
+ } else if (ofi.oraType == SQLT_LBI) {
+// qDebug("binding SQLT_LBI");
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ 0,
+ SB4MAXVAL,
+ SQLT_LBI,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DYNAMIC_FETCH);
+ } else if (ofi.oraType == SQLT_CLOB) {
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ createLobLocator(idx, d->env),
+ -1,
+ SQLT_CLOB,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DEFAULT);
+ } else {
+// qDebug("binding SQLT_BLOB");
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ createLobLocator(idx, d->env),
+ -1,
+ SQLT_BLOB,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DEFAULT);
+ }
+ break;
+ case QVariant::String:
+ if (ofi.oraType == SQLT_LNG) {
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ 0,
+ SB4MAXVAL,
+ SQLT_LNG,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DYNAMIC_FETCH);
+ } else {
+ dataSize += dataSize + sizeof(QChar);
+ //qDebug("OCIDefineByPosStr(%d): %d", count, dataSize);
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ create(idx, dataSize),
+ dataSize,
+ SQLT_STR,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DEFAULT);
+ if (r == 0)
+ d->setCharset(dfn, OCI_HTYPE_DEFINE);
+ }
+ break;
+ default:
+ // this should make enough space even with character encoding
+ dataSize = (dataSize + 1) * sizeof(utext) ;
+ //qDebug("OCIDefineByPosDef(%d): %d", count, dataSize);
+ r = OCIDefineByPos(d->sql,
+ &dfn,
+ d->err,
+ count,
+ create(idx, dataSize),
+ dataSize+1,
+ SQLT_STR,
+ &(fieldInf[idx].ind),
+ 0, 0, OCI_DEFAULT);
+ break;
+ }
+ if (r != 0)
+ qOraWarning("QOCICols::bind:", d->err);
+ fieldInf[idx].def = dfn;
+ ++count;
+ ++idx;
+ parmStatus = OCIParamGet(d->sql,
+ OCI_HTYPE_STMT,
+ d->err,
+ reinterpret_cast<void **>(&param),
+ count);
+ }
+}
+
+QOCICols::~QOCICols()
+{
+}
+
+char* QOCICols::create(int position, int size)
+{
+ char* c = new char[size+1];
+ // Oracle may not fill fixed width fields
+ memset(c, 0, size+1);
+ fieldInf[position].data = c;
+ fieldInf[position].len = size;
+ return c;
+}
+
+OCILobLocator **QOCICols::createLobLocator(int position, OCIEnv* env)
+{
+ OCILobLocator *& lob = fieldInf[position].lob;
+ int r = OCIDescriptorAlloc(env,
+ reinterpret_cast<void **>(&lob),
+ OCI_DTYPE_LOB,
+ 0,
+ 0);
+ if (r != 0) {
+ qWarning("QOCICols: Cannot create LOB locator");
+ lob = 0;
+ }
+ return &lob;
+}
+
+int QOCICols::readPiecewise(QVector<QVariant> &values, int index)
+{
+ OCIDefine* dfn;
+ ub4 typep;
+ ub1 in_outp;
+ ub4 iterp;
+ ub4 idxp;
+ ub1 piecep;
+ sword status;
+ text col [QOCI_DYNAMIC_CHUNK_SIZE+1];
+ int fieldNum = -1;
+ int r = 0;
+ bool nullField;
+
+ do {
+ r = OCIStmtGetPieceInfo(d->sql, d->err, reinterpret_cast<void **>(&dfn), &typep,
+ &in_outp, &iterp, &idxp, &piecep);
+ if (r != OCI_SUCCESS)
+ qOraWarning("OCIResultPrivate::readPiecewise: unable to get piece info:", d->err);
+ fieldNum = fieldFromDefine(dfn);
+ bool isStringField = fieldInf.at(fieldNum).oraType == SQLT_LNG;
+ ub4 chunkSize = QOCI_DYNAMIC_CHUNK_SIZE;
+ nullField = false;
+ r = OCIStmtSetPieceInfo(dfn, OCI_HTYPE_DEFINE,
+ d->err, col,
+ &chunkSize, piecep, NULL, NULL);
+ if (r != OCI_SUCCESS)
+ qOraWarning("OCIResultPrivate::readPiecewise: unable to set piece info:", d->err);
+ status = OCIStmtFetch (d->sql, d->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
+ if (status == -1) {
+ sb4 errcode;
+ OCIErrorGet(d->err, 1, 0, &errcode, 0, 0,OCI_HTYPE_ERROR);
+ switch (errcode) {
+ case 1405: /* NULL */
+ nullField = true;
+ break;
+ default:
+ qOraWarning("OCIResultPrivate::readPiecewise: unable to fetch next:", d->err);
+ break;
+ }
+ }
+ if (status == OCI_NO_DATA)
+ break;
+ if (nullField || !chunkSize) {
+ fieldInf[fieldNum].ind = -1;
+ } else {
+ if (isStringField) {
+ QString str = values.at(fieldNum + index).toString();
+ str += QString(reinterpret_cast<const QChar *>(col), chunkSize / 2);
+ values[fieldNum + index] = str;
+ fieldInf[fieldNum].ind = 0;
+ } else {
+ QByteArray ba = values.at(fieldNum + index).toByteArray();
+ int sz = ba.size();
+ ba.resize(sz + chunkSize);
+ memcpy(ba.data() + sz, reinterpret_cast<char *>(col), chunkSize);
+ values[fieldNum + index] = ba;
+ fieldInf[fieldNum].ind = 0;
+ }
+ }
+ } while (status == OCI_SUCCESS_WITH_INFO || status == OCI_NEED_DATA);
+ return r;
+}
+
+OraFieldInfo QOCICols::qMakeOraField(const QOCIResultPrivate* p, OCIParam* param) const
+{
+ OraFieldInfo ofi;
+ ub2 colType(0);
+ text *colName = 0;
+ ub4 colNameLen(0);
+ sb1 colScale(0);
+ ub2 colLength(0);
+ ub2 colFieldLength(0);
+ sb2 colPrecision(0);
+ ub1 colIsNull(0);
+ int r(0);
+ QVariant::Type type(QVariant::Invalid);
+
+ r = OCIAttrGet(param,
+ OCI_DTYPE_PARAM,
+ &colType,
+ 0,
+ OCI_ATTR_DATA_TYPE,
+ p->err);
+ if (r != 0)
+ qOraWarning("qMakeOraField:", p->err);
+
+ r = OCIAttrGet(param,
+ OCI_DTYPE_PARAM,
+ &colName,
+ &colNameLen,
+ OCI_ATTR_NAME,
+ p->err);
+ if (r != 0)
+ qOraWarning("qMakeOraField:", p->err);
+
+ r = OCIAttrGet(param,
+ OCI_DTYPE_PARAM,
+ &colLength,
+ 0,
+ OCI_ATTR_DATA_SIZE, /* in bytes */
+ p->err);
+ if (r != 0)
+ qOraWarning("qMakeOraField:", p->err);
+
+#ifdef OCI_ATTR_CHAR_SIZE
+ r = OCIAttrGet(param,
+ OCI_DTYPE_PARAM,
+ &colFieldLength,
+ 0,
+ OCI_ATTR_CHAR_SIZE,
+ p->err);
+ if (r != 0)
+ qOraWarning("qMakeOraField:", p->err);
+#else
+ // for Oracle8.
+ colFieldLength = colLength;
+#endif
+
+ r = OCIAttrGet(param,
+ OCI_DTYPE_PARAM,
+ &colPrecision,
+ 0,
+ OCI_ATTR_PRECISION,
+ p->err);
+ if (r != 0)
+ qOraWarning("qMakeOraField:", p->err);
+
+ r = OCIAttrGet(param,
+ OCI_DTYPE_PARAM,
+ &colScale,
+ 0,
+ OCI_ATTR_SCALE,
+ p->err);
+ if (r != 0)
+ qOraWarning("qMakeOraField:", p->err);
+ r = OCIAttrGet(param,
+ OCI_DTYPE_PARAM,
+ &colType,
+ 0,
+ OCI_ATTR_DATA_TYPE,
+ p->err);
+ if (r != 0)
+ qOraWarning("qMakeOraField:", p->err);
+ r = OCIAttrGet(param,
+ OCI_DTYPE_PARAM,
+ &colIsNull,
+ 0,
+ OCI_ATTR_IS_NULL,
+ p->err);
+ if (r != 0)
+ qOraWarning("qMakeOraField:", p->err);
+
+ type = qDecodeOCIType(colType, p->q_func()->numericalPrecisionPolicy());
+
+ if (type == QVariant::Int) {
+ if (colLength == 22 && colPrecision == 0 && colScale == 0)
+ type = QVariant::String;
+ if (colScale > 0)
+ type = QVariant::String;
+ }
+
+ // bind as double if the precision policy asks for it
+ if (((colType == SQLT_FLT) || (colType == SQLT_NUM))
+ && (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionDouble)) {
+ type = QVariant::Double;
+ }
+
+ // bind as int32 or int64 if the precision policy asks for it
+ if ((colType == SQLT_NUM) || (colType == SQLT_VNU) || (colType == SQLT_UIN)
+ || (colType == SQLT_INT)) {
+ if (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt64)
+ type = QVariant::LongLong;
+ else if (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt32)
+ type = QVariant::Int;
+ }
+
+ if (colType == SQLT_BLOB)
+ colLength = 0;
+
+ // colNameLen is length in bytes
+ ofi.name = QString(reinterpret_cast<const QChar*>(colName), colNameLen / 2);
+ ofi.type = type;
+ ofi.oraType = colType;
+ ofi.oraFieldLength = colFieldLength;
+ ofi.oraLength = colLength;
+ ofi.oraScale = colScale;
+ ofi.oraPrecision = colPrecision;
+ ofi.oraIsNull = colIsNull;
+
+ return ofi;
+}
+
+struct QOCIBatchColumn
+{
+ inline QOCIBatchColumn()
+ : bindh(0), bindAs(0), maxLen(0), recordCount(0),
+ data(0), lengths(0), indicators(0), maxarr_len(0), curelep(0) {}
+
+ OCIBind* bindh;
+ ub2 bindAs;
+ ub4 maxLen;
+ ub4 recordCount;
+ char* data;
+ ub2* lengths;
+ sb2* indicators;
+ ub4 maxarr_len;
+ ub4 curelep;
+};
+
+struct QOCIBatchCleanupHandler
+{
+ inline QOCIBatchCleanupHandler(QVector<QOCIBatchColumn> &columns)
+ : col(columns) {}
+
+ ~QOCIBatchCleanupHandler()
+ {
+ // deleting storage, length and indicator arrays
+ for ( int j = 0; j < col.count(); ++j){
+ delete[] col[j].lengths;
+ delete[] col[j].indicators;
+ delete[] col[j].data;
+ }
+ }
+
+ QVector<QOCIBatchColumn> &col;
+};
+
+bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, bool arrayBind)
+{
+ int columnCount = boundValues.count();
+ if (boundValues.isEmpty() || columnCount == 0)
+ return false;
+
+#ifdef QOCI_DEBUG
+ qDebug() << "columnCount:" << columnCount << boundValues;
+#endif
+
+ int i;
+ sword r;
+
+ QVarLengthArray<QVariant::Type> fieldTypes;
+ for (i = 0; i < columnCount; ++i) {
+ QVariant::Type tp = boundValues.at(i).type();
+ fieldTypes.append(tp == QVariant::List ? boundValues.at(i).toList().value(0).type()
+ : tp);
+ }
+
+ QList<QByteArray> tmpStorage;
+ SizeArray tmpSizes(columnCount);
+ QVector<QOCIBatchColumn> columns(columnCount);
+ QOCIBatchCleanupHandler cleaner(columns);
+
+ // figuring out buffer sizes
+ for (i = 0; i < columnCount; ++i) {
+
+ if (boundValues.at(i).type() != QVariant::List) {
+
+ // not a list - create a deep-copy of the single value
+ QOCIBatchColumn &singleCol = columns[i];
+ singleCol.indicators = new sb2[1];
+ *singleCol.indicators = boundValues.at(i).isNull() ? -1 : 0;
+
+ r = d->bindValue(d->sql, &singleCol.bindh, d->err, i,
+ boundValues.at(i), singleCol.indicators, &tmpSizes[i], tmpStorage);
+
+ if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
+ qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err);
+ d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
+ "Unable to bind column for batch execute"),
+ QSqlError::StatementError, d->err));
+ return false;
+ }
+ continue;
+ }
+
+ QOCIBatchColumn &col = columns[i];
+ col.recordCount = boundValues.at(i).toList().count();
+
+ col.lengths = new ub2[col.recordCount];
+ col.indicators = new sb2[col.recordCount];
+ col.maxarr_len = col.recordCount;
+ col.curelep = col.recordCount;
+
+ switch (fieldTypes[i]) {
+ case QVariant::Time:
+ case QVariant::Date:
+ case QVariant::DateTime:
+ col.bindAs = SQLT_DAT;
+ col.maxLen = 7;
+ break;
+
+ case QVariant::Int:
+ col.bindAs = SQLT_INT;
+ col.maxLen = sizeof(int);
+ break;
+
+ case QVariant::UInt:
+ col.bindAs = SQLT_UIN;
+ col.maxLen = sizeof(uint);
+ break;
+
+ case QVariant::LongLong:
+ col.bindAs = SQLT_VNU;
+ col.maxLen = sizeof(OCINumber);
+ break;
+
+ case QVariant::ULongLong:
+ col.bindAs = SQLT_VNU;
+ col.maxLen = sizeof(OCINumber);
+ break;
+
+ case QVariant::Double:
+ col.bindAs = SQLT_FLT;
+ col.maxLen = sizeof(double);
+ break;
+
+ case QVariant::UserType:
+ col.bindAs = SQLT_RDD;
+ col.maxLen = sizeof(OCIRowid*);
+ break;
+
+ case QVariant::String: {
+ col.bindAs = SQLT_STR;
+ for (uint j = 0; j < col.recordCount; ++j) {
+ uint len;
+ if(d->isOutValue(i))
+ len = boundValues.at(i).toList().at(j).toString().capacity() + 1;
+ else
+ len = boundValues.at(i).toList().at(j).toString().length() + 1;
+ if (len > col.maxLen)
+ col.maxLen = len;
+ }
+ col.maxLen *= sizeof(QChar);
+ break; }
+
+ case QVariant::ByteArray:
+ default: {
+ col.bindAs = SQLT_LBI;
+ for (uint j = 0; j < col.recordCount; ++j) {
+ if(d->isOutValue(i))
+ col.lengths[j] = boundValues.at(i).toList().at(j).toByteArray().capacity();
+ else
+ col.lengths[j] = boundValues.at(i).toList().at(j).toByteArray().size();
+ if (col.lengths[j] > col.maxLen)
+ col.maxLen = col.lengths[j];
+ }
+ break; }
+ }
+
+ col.data = new char[col.maxLen * col.recordCount];
+ memset(col.data, 0, col.maxLen * col.recordCount);
+
+ // we may now populate column with data
+ for (uint row = 0; row < col.recordCount; ++row) {
+ const QVariant &val = boundValues.at(i).toList().at(row);
+
+ if (val.isNull()){
+ columns[i].indicators[row] = -1;
+ columns[i].lengths[row] = 0;
+ } else {
+ columns[i].indicators[row] = 0;
+ char *dataPtr = columns[i].data + (columns[i].maxLen * row);
+ switch (fieldTypes[i]) {
+ case QVariant::Time:
+ case QVariant::Date:
+ case QVariant::DateTime:{
+ columns[i].lengths[row] = columns[i].maxLen;
+ const QByteArray ba = qMakeOraDate(val.toDateTime());
+ Q_ASSERT(ba.size() == int(columns[i].maxLen));
+ memcpy(dataPtr, ba.constData(), columns[i].maxLen);
+ break;
+ }
+ case QVariant::Int:
+ columns[i].lengths[row] = columns[i].maxLen;
+ *reinterpret_cast<int*>(dataPtr) = val.toInt();
+ break;
+
+ case QVariant::UInt:
+ columns[i].lengths[row] = columns[i].maxLen;
+ *reinterpret_cast<uint*>(dataPtr) = val.toUInt();
+ break;
+
+ case QVariant::LongLong:
+ {
+ columns[i].lengths[row] = columns[i].maxLen;
+ const QByteArray ba = qMakeOCINumber(val.toLongLong(), d->err);
+ Q_ASSERT(ba.size() == int(columns[i].maxLen));
+ memcpy(dataPtr, ba.constData(), columns[i].maxLen);
+ break;
+ }
+ case QVariant::ULongLong:
+ {
+ columns[i].lengths[row] = columns[i].maxLen;
+ const QByteArray ba = qMakeOCINumber(val.toULongLong(), d->err);
+ Q_ASSERT(ba.size() == int(columns[i].maxLen));
+ memcpy(dataPtr, ba.constData(), columns[i].maxLen);
+ break;
+ }
+ case QVariant::Double:
+ columns[i].lengths[row] = columns[i].maxLen;
+ *reinterpret_cast<double*>(dataPtr) = val.toDouble();
+ break;
+
+ case QVariant::String: {
+ const QString s = val.toString();
+ columns[i].lengths[row] = (s.length() + 1) * sizeof(QChar);
+ memcpy(dataPtr, s.utf16(), columns[i].lengths[row]);
+ break;
+ }
+ case QVariant::UserType:
+ if (val.canConvert<QOCIRowIdPointer>()) {
+ const QOCIRowIdPointer rptr = qvariant_cast<QOCIRowIdPointer>(val);
+ *reinterpret_cast<OCIRowid**>(dataPtr) = rptr->id;
+ columns[i].lengths[row] = 0;
+ break;
+ }
+ case QVariant::ByteArray:
+ default: {
+ const QByteArray ba = val.toByteArray();
+ columns[i].lengths[row] = ba.size();
+ memcpy(dataPtr, ba.constData(), ba.size());
+ break;
+ }
+ }
+ }
+ }
+
+ QOCIBatchColumn &bindColumn = columns[i];
+
+#ifdef QOCI_DEBUG
+ qDebug("OCIBindByPos(%p, %p, %p, %d, %p, %d, %d, %p, %p, 0, %d, %p, OCI_DEFAULT)",
+ d->sql, &bindColumn.bindh, d->err, i + 1, bindColumn.data,
+ bindColumn.maxLen, bindColumn.bindAs, bindColumn.indicators, bindColumn.lengths,
+ arrayBind ? bindColumn.maxarr_len : 0, arrayBind ? &bindColumn.curelep : 0);
+
+ for (int ii = 0; ii < (int)bindColumn.recordCount; ++ii) {
+ qDebug(" record %d: indicator %d, length %d", ii, bindColumn.indicators[ii],
+ bindColumn.lengths[ii]);
+ }
+#endif
+
+
+ // binding the column
+ r = OCIBindByPos(
+ d->sql, &bindColumn.bindh, d->err, i + 1,
+ bindColumn.data,
+ bindColumn.maxLen,
+ bindColumn.bindAs,
+ bindColumn.indicators,
+ bindColumn.lengths,
+ 0,
+ arrayBind ? bindColumn.maxarr_len : 0,
+ arrayBind ? &bindColumn.curelep : 0,
+ OCI_DEFAULT);
+
+#ifdef QOCI_DEBUG
+ qDebug("After OCIBindByPos: r = %d, bindh = %p", r, bindColumn.bindh);
+#endif
+
+ if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
+ qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err);
+ d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
+ "Unable to bind column for batch execute"),
+ QSqlError::StatementError, d->err));
+ return false;
+ }
+
+ r = OCIBindArrayOfStruct (
+ columns[i].bindh, d->err,
+ columns[i].maxLen,
+ sizeof(columns[i].indicators[0]),
+ sizeof(columns[i].lengths[0]),
+ 0);
+
+ if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
+ qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err);
+ d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
+ "Unable to bind column for batch execute"),
+ QSqlError::StatementError, d->err));
+ return false;
+ }
+ }
+
+ //finaly we can execute
+ r = OCIStmtExecute(d->svc, d->sql, d->err,
+ arrayBind ? 1 : columns[0].recordCount,
+ 0, NULL, NULL,
+ d->transaction ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS);
+
+ if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
+ qOraWarning("QOCIPrivate::execBatch: unable to execute batch statement:", d->err);
+ d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
+ "Unable to execute batch statement"),
+ QSqlError::StatementError, d->err));
+ return false;
+ }
+
+ // for out parameters we copy data back to value vector
+ for (i = 0; i < columnCount; ++i) {
+
+ if (!d->isOutValue(i))
+ continue;
+
+ QVariant::Type tp = boundValues.at(i).type();
+ if (tp != QVariant::List) {
+ qOraOutValue(boundValues[i], tmpStorage, d->err);
+ if (*columns[i].indicators == -1)
+ boundValues[i] = QVariant(tp);
+ continue;
+ }
+
+ QVariantList *list = static_cast<QVariantList *>(const_cast<void*>(boundValues.at(i).data()));
+
+ char* data = columns[i].data;
+ for (uint r = 0; r < columns[i].recordCount; ++r){
+
+ if (columns[i].indicators[r] == -1) {
+ (*list)[r] = QVariant();
+ continue;
+ }
+
+ switch(columns[i].bindAs) {
+
+ case SQLT_DAT:
+ (*list)[r] = qMakeDate(data + r * columns[i].maxLen);
+ break;
+
+ case SQLT_INT:
+ (*list)[r] = *reinterpret_cast<int*>(data + r * columns[i].maxLen);
+ break;
+
+ case SQLT_UIN:
+ (*list)[r] = *reinterpret_cast<uint*>(data + r * columns[i].maxLen);
+ break;
+
+ case SQLT_VNU:
+ {
+ switch (boundValues.at(i).type()) {
+ case QVariant::LongLong:
+ (*list)[r] = qMakeLongLong(data + r * columns[i].maxLen, d->err);
+ break;
+ case QVariant::ULongLong:
+ (*list)[r] = qMakeULongLong(data + r * columns[i].maxLen, d->err);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case SQLT_FLT:
+ (*list)[r] = *reinterpret_cast<double*>(data + r * columns[i].maxLen);
+ break;
+
+ case SQLT_STR:
+ (*list)[r] = QString(reinterpret_cast<const QChar *>(data
+ + r * columns[i].maxLen));
+ break;
+
+ default:
+ (*list)[r] = QByteArray(data + r * columns[i].maxLen, columns[i].maxLen);
+ break;
+ }
+ }
+ }
+
+ d->q_func()->setSelect(false);
+ d->q_func()->setAt(QSql::BeforeFirstRow);
+ d->q_func()->setActive(true);
+
+ return true;
+}
+
+template<class T, int sz>
+int qReadLob(T &buf, const QOCIResultPrivate *d, OCILobLocator *lob)
+{
+ ub1 csfrm;
+ ub4 amount;
+ int r;
+
+ // Read this from the database, don't assume we know what it is set to
+ r = OCILobCharSetForm(d->env, d->err, lob, &csfrm);
+ if (r != OCI_SUCCESS) {
+ qOraWarning("OCIResultPrivate::readLobs: Couldn't get LOB char set form: ", d->err);
+ csfrm = 0;
+ }
+
+ // Get the length of the LOB (this is in characters)
+ r = OCILobGetLength(d->svc, d->err, lob, &amount);
+ if (r == OCI_SUCCESS) {
+ if (amount == 0) {
+ // Short cut for null LOBs
+ buf.resize(0);
+ return OCI_SUCCESS;
+ }
+ } else {
+ qOraWarning("OCIResultPrivate::readLobs: Couldn't get LOB length: ", d->err);
+ return r;
+ }
+
+ // Resize the buffer to hold the LOB contents
+ buf.resize(amount);
+
+ // Read the LOB into the buffer
+ r = OCILobRead(d->svc,
+ d->err,
+ lob,
+ &amount,
+ 1,
+ buf.data(),
+ buf.size() * sz, // this argument is in bytes, not characters
+ 0,
+ 0,
+ // Extract the data from a CLOB in UTF-16 (ie. what QString uses internally)
+ sz == 1 ? ub2(0) : ub2(QOCIEncoding),
+ csfrm);
+
+ if (r != OCI_SUCCESS)
+ qOraWarning("OCIResultPrivate::readLOBs: Cannot read LOB: ", d->err);
+
+ return r;
+}
+
+int QOCICols::readLOBs(QVector<QVariant> &values, int index)
+{
+ OCILobLocator *lob;
+ int r = OCI_SUCCESS;
+
+ for (int i = 0; i < size(); ++i) {
+ const OraFieldInf &fi = fieldInf.at(i);
+ if (fi.ind == -1 || !(lob = fi.lob))
+ continue;
+
+ bool isClob = fi.oraType == SQLT_CLOB;
+ QVariant var;
+
+ if (isClob) {
+ QString str;
+ r = qReadLob<QString, sizeof(QChar)>(str, d, lob);
+ var = str;
+ } else {
+ QByteArray buf;
+ r = qReadLob<QByteArray, sizeof(char)>(buf, d, lob);
+ var = buf;
+ }
+ if (r == OCI_SUCCESS)
+ values[index + i] = var;
+ else
+ break;
+ }
+ return r;
+}
+
+int QOCICols::fieldFromDefine(OCIDefine* d)
+{
+ for (int i = 0; i < fieldInf.count(); ++i) {
+ if (fieldInf.at(i).def == d)
+ return i;
+ }
+ return -1;
+}
+
+void QOCICols::getValues(QVector<QVariant> &v, int index)
+{
+ for (int i = 0; i < fieldInf.size(); ++i) {
+ const OraFieldInf &fld = fieldInf.at(i);
+
+ if (fld.ind == -1) {
+ // got a NULL value
+ v[index + i] = QVariant(fld.typ);
+ continue;
+ }
+
+ if (fld.oraType == SQLT_BIN || fld.oraType == SQLT_LBI || fld.oraType == SQLT_LNG)
+ continue; // already fetched piecewise
+
+ switch (fld.typ) {
+ case QVariant::DateTime:
+ v[index + i] = QVariant(qMakeDate(fld.data));
+ break;
+ case QVariant::Double:
+ case QVariant::Int:
+ case QVariant::LongLong:
+ if (d->q_func()->numericalPrecisionPolicy() != QSql::HighPrecision) {
+ if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionDouble)
+ && (fld.typ == QVariant::Double)) {
+ v[index + i] = *reinterpret_cast<double *>(fld.data);
+ break;
+ } else if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt64)
+ && (fld.typ == QVariant::LongLong)) {
+ qint64 qll = 0;
+ int r = OCINumberToInt(d->err, reinterpret_cast<OCINumber *>(fld.data), sizeof(qint64),
+ OCI_NUMBER_SIGNED, &qll);
+ if(r == OCI_SUCCESS)
+ v[index + i] = qll;
+ else
+ v[index + i] = QVariant();
+ break;
+ } else if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt32)
+ && (fld.typ == QVariant::Int)) {
+ v[index + i] = *reinterpret_cast<int *>(fld.data);
+ break;
+ }
+ }
+ // else fall through
+ case QVariant::String:
+ v[index + i] = QString(reinterpret_cast<const QChar *>(fld.data));
+ break;
+ case QVariant::ByteArray:
+ if (fld.len > 0)
+ v[index + i] = QByteArray(fld.data, fld.len);
+ else
+ v[index + i] = QVariant(QVariant::ByteArray);
+ break;
+ default:
+ qWarning("QOCICols::value: unknown data type");
+ break;
+ }
+ }
+}
+
+QOCIResultPrivate::QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv)
+ : QSqlCachedResultPrivate(q, drv),
+ cols(0),
+ env(drv_d_func()->env),
+ err(0),
+ svc(const_cast<OCISvcCtx*&>(drv_d_func()->svc)),
+ sql(0),
+ transaction(drv_d_func()->transaction),
+ serverVersion(drv_d_func()->serverVersion),
+ prefetchRows(drv_d_func()->prefetchRows),
+ prefetchMem(drv_d_func()->prefetchMem)
+{
+ int r = OCIHandleAlloc(env,
+ reinterpret_cast<void **>(&err),
+ OCI_HTYPE_ERROR,
+ 0,
+ 0);
+ if (r != 0)
+ qWarning("QOCIResult: unable to alloc error handle");
+}
+
+QOCIResultPrivate::~QOCIResultPrivate()
+{
+ delete cols;
+
+ int r = OCIHandleFree(err, OCI_HTYPE_ERROR);
+ if (r != 0)
+ qWarning("~QOCIResult: unable to free statement handle");
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+
+QOCIResult::QOCIResult(const QOCIDriver *db)
+ : QSqlCachedResult(*new QOCIResultPrivate(this, db))
+{
+}
+
+QOCIResult::~QOCIResult()
+{
+ Q_D(QOCIResult);
+ if (d->sql) {
+ int r = OCIHandleFree(d->sql, OCI_HTYPE_STMT);
+ if (r != 0)
+ qWarning("~QOCIResult: unable to free statement handle");
+ }
+}
+
+QVariant QOCIResult::handle() const
+{
+ Q_D(const QOCIResult);
+ return QVariant::fromValue(d->sql);
+}
+
+bool QOCIResult::reset (const QString& query)
+{
+ if (!prepare(query))
+ return false;
+ return exec();
+}
+
+bool QOCIResult::gotoNext(QSqlCachedResult::ValueCache &values, int index)
+{
+ Q_D(QOCIResult);
+ if (at() == QSql::AfterLastRow)
+ return false;
+
+ bool piecewise = false;
+ int r = OCI_SUCCESS;
+ r = OCIStmtFetch(d->sql, d->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
+
+ if (index < 0) //not interested in values
+ return r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO;
+
+ switch (r) {
+ case OCI_SUCCESS:
+ break;
+ case OCI_SUCCESS_WITH_INFO:
+ qOraWarning("QOCIResult::gotoNext: SuccessWithInfo: ", d->err);
+ r = OCI_SUCCESS; //ignore it
+ break;
+ case OCI_NO_DATA:
+ // end of rowset
+ return false;
+ case OCI_NEED_DATA:
+ piecewise = true;
+ r = OCI_SUCCESS;
+ break;
+ case OCI_ERROR:
+ if (qOraErrorNumber(d->err) == 1406) {
+ qWarning("QOCI Warning: data truncated for %s", lastQuery().toLocal8Bit().constData());
+ r = OCI_SUCCESS; /* ignore it */
+ break;
+ }
+ // fall through
+ default:
+ qOraWarning("QOCIResult::gotoNext: ", d->err);
+ setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
+ "Unable to goto next"),
+ QSqlError::StatementError, d->err));
+ break;
+ }
+
+ // need to read piecewise before assigning values
+ if (r == OCI_SUCCESS && piecewise)
+ r = d->cols->readPiecewise(values, index);
+
+ if (r == OCI_SUCCESS)
+ d->cols->getValues(values, index);
+ if (r == OCI_SUCCESS)
+ r = d->cols->readLOBs(values, index);
+ if (r != OCI_SUCCESS)
+ setAt(QSql::AfterLastRow);
+ return r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO;
+}
+
+int QOCIResult::size()
+{
+ return -1;
+}
+
+int QOCIResult::numRowsAffected()
+{
+ Q_D(QOCIResult);
+ int rowCount;
+ OCIAttrGet(d->sql,
+ OCI_HTYPE_STMT,
+ &rowCount,
+ NULL,
+ OCI_ATTR_ROW_COUNT,
+ d->err);
+ return rowCount;
+}
+
+bool QOCIResult::prepare(const QString& query)
+{
+ Q_D(QOCIResult);
+ int r = 0;
+ QSqlResult::prepare(query);
+
+ delete d->cols;
+ d->cols = 0;
+ QSqlCachedResult::cleanup();
+
+ if (d->sql) {
+ r = OCIHandleFree(d->sql, OCI_HTYPE_STMT);
+ if (r != OCI_SUCCESS)
+ qOraWarning("QOCIResult::prepare: unable to free statement handle:", d->err);
+ }
+ if (query.isEmpty())
+ return false;
+ r = OCIHandleAlloc(d->env,
+ reinterpret_cast<void **>(&d->sql),
+ OCI_HTYPE_STMT,
+ 0,
+ 0);
+ if (r != OCI_SUCCESS) {
+ qOraWarning("QOCIResult::prepare: unable to alloc statement:", d->err);
+ setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
+ "Unable to alloc statement"), QSqlError::StatementError, d->err));
+ return false;
+ }
+ d->setStatementAttributes();
+ const OraText *txt = reinterpret_cast<const OraText *>(query.utf16());
+ const int len = query.length() * sizeof(QChar);
+ r = OCIStmtPrepare(d->sql,
+ d->err,
+ txt,
+ len,
+ OCI_NTV_SYNTAX,
+ OCI_DEFAULT);
+ if (r != OCI_SUCCESS) {
+ qOraWarning("QOCIResult::prepare: unable to prepare statement:", d->err);
+ setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
+ "Unable to prepare statement"), QSqlError::StatementError, d->err));
+ return false;
+ }
+ return true;
+}
+
+bool QOCIResult::exec()
+{
+ Q_D(QOCIResult);
+ int r = 0;
+ ub2 stmtType=0;
+ ub4 iters;
+ ub4 mode;
+ QList<QByteArray> tmpStorage;
+ IndicatorArray indicators(boundValueCount());
+ SizeArray tmpSizes(boundValueCount());
+
+ r = OCIAttrGet(d->sql,
+ OCI_HTYPE_STMT,
+ &stmtType,
+ NULL,
+ OCI_ATTR_STMT_TYPE,
+ d->err);
+
+ if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
+ qOraWarning("QOCIResult::exec: Unable to get statement type:", d->err);
+ setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
+ "Unable to get statement type"), QSqlError::StatementError, d->err));
+#ifdef QOCI_DEBUG
+ qDebug() << "lastQuery()" << lastQuery();
+#endif
+ return false;
+ }
+
+ iters = stmtType == OCI_STMT_SELECT ? 0 : 1;
+ mode = d->transaction ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS;
+
+ // bind placeholders
+ if (boundValueCount() > 0
+ && d->bindValues(boundValues(), indicators, tmpSizes, tmpStorage) != OCI_SUCCESS) {
+ qOraWarning("QOCIResult::exec: unable to bind value: ", d->err);
+ setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to bind value"),
+ QSqlError::StatementError, d->err));
+#ifdef QOCI_DEBUG
+ qDebug() << "lastQuery()" << lastQuery();
+#endif
+ return false;
+ }
+
+ // execute
+ r = OCIStmtExecute(d->svc,
+ d->sql,
+ d->err,
+ iters,
+ 0,
+ 0,
+ 0,
+ mode);
+ if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
+ qOraWarning("QOCIResult::exec: unable to execute statement:", d->err);
+ setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
+ "Unable to execute statement"), QSqlError::StatementError, d->err));
+#ifdef QOCI_DEBUG
+ qDebug() << "lastQuery()" << lastQuery();
+#endif
+ return false;
+ }
+
+ if (stmtType == OCI_STMT_SELECT) {
+ ub4 parmCount = 0;
+ int r = OCIAttrGet(d->sql, OCI_HTYPE_STMT, reinterpret_cast<void **>(&parmCount),
+ 0, OCI_ATTR_PARAM_COUNT, d->err);
+ if (r == 0 && !d->cols)
+ d->cols = new QOCICols(parmCount, d);
+ setSelect(true);
+ QSqlCachedResult::init(parmCount);
+ } else { /* non-SELECT */
+ setSelect(false);
+ }
+ setAt(QSql::BeforeFirstRow);
+ setActive(true);
+
+ if (hasOutValues())
+ d->outValues(boundValues(), indicators, tmpStorage);
+
+ return true;
+}
+
+QSqlRecord QOCIResult::record() const
+{
+ Q_D(const QOCIResult);
+ QSqlRecord inf;
+ if (!isActive() || !isSelect() || !d->cols)
+ return inf;
+ return d->cols->rec;
+}
+
+QVariant QOCIResult::lastInsertId() const
+{
+ Q_D(const QOCIResult);
+ if (isActive()) {
+ QOCIRowIdPointer ptr(new QOCIRowId(d->env));
+
+ int r = OCIAttrGet(d->sql, OCI_HTYPE_STMT, ptr.constData()->id,
+ 0, OCI_ATTR_ROWID, d->err);
+ if (r == OCI_SUCCESS)
+ return QVariant::fromValue(ptr);
+ }
+ return QVariant();
+}
+
+bool QOCIResult::execBatch(bool arrayBind)
+{
+ Q_D(QOCIResult);
+ QOCICols::execBatch(d, boundValues(), arrayBind);
+ resetBindCount();
+ return lastError().type() == QSqlError::NoError;
+}
+
+void QOCIResult::virtual_hook(int id, void *data)
+{
+ Q_ASSERT(data);
+
+ QSqlCachedResult::virtual_hook(id, data);
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+
+QOCIDriver::QOCIDriver(QObject* parent)
+ : QSqlDriver(*new QOCIDriverPrivate, parent)
+{
+ Q_D(QOCIDriver);
+#ifdef QOCI_THREADED
+ const ub4 mode = OCI_UTF16 | OCI_OBJECT | OCI_THREADED;
+#else
+ const ub4 mode = OCI_UTF16 | OCI_OBJECT;
+#endif
+ int r = OCIEnvCreate(&d->env,
+ mode,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ NULL);
+ if (r != 0) {
+ qWarning("QOCIDriver: unable to create environment");
+ setLastError(qMakeError(tr("Unable to initialize", "QOCIDriver"),
+ QSqlError::ConnectionError, d->err));
+ return;
+ }
+
+ d->allocErrorHandle();
+}
+
+QOCIDriver::QOCIDriver(OCIEnv* env, OCISvcCtx* ctx, QObject* parent)
+ : QSqlDriver(*new QOCIDriverPrivate, parent)
+{
+ Q_D(QOCIDriver);
+ d->env = env;
+ d->svc = ctx;
+
+ d->allocErrorHandle();
+
+ if (env && ctx) {
+ setOpen(true);
+ setOpenError(false);
+ }
+}
+
+QOCIDriver::~QOCIDriver()
+{
+ Q_D(QOCIDriver);
+ if (isOpen())
+ close();
+ int r = OCIHandleFree(d->err, OCI_HTYPE_ERROR);
+ if (r != OCI_SUCCESS)
+ qWarning("Unable to free Error handle: %d", r);
+ r = OCIHandleFree(d->env, OCI_HTYPE_ENV);
+ if (r != OCI_SUCCESS)
+ qWarning("Unable to free Environment handle: %d", r);
+}
+
+bool QOCIDriver::hasFeature(DriverFeature f) const
+{
+ Q_D(const QOCIDriver);
+ switch (f) {
+ case Transactions:
+ case LastInsertId:
+ case BLOB:
+ case PreparedQueries:
+ case NamedPlaceholders:
+ case BatchOperations:
+ case LowPrecisionNumbers:
+ return true;
+ case QuerySize:
+ case PositionalPlaceholders:
+ case SimpleLocking:
+ case EventNotifications:
+ case FinishQuery:
+ case CancelQuery:
+ case MultipleResultSets:
+ return false;
+ case Unicode:
+ return d->serverVersion >= 9;
+ }
+ return false;
+}
+
+static void qParseOpts(const QString &options, QOCIDriverPrivate *d)
+{
+ const QStringList opts(options.split(QLatin1Char(';'), QString::SkipEmptyParts));
+ for (int i = 0; i < opts.count(); ++i) {
+ const QString tmp(opts.at(i));
+ int idx;
+ if ((idx = tmp.indexOf(QLatin1Char('='))) == -1) {
+ qWarning("QOCIDriver::parseArgs: Invalid parameter: '%s'",
+ tmp.toLocal8Bit().constData());
+ continue;
+ }
+ const QString opt = tmp.left(idx);
+ const QString val = tmp.mid(idx + 1).simplified();
+ bool ok;
+ if (opt == QLatin1String("OCI_ATTR_PREFETCH_ROWS")) {
+ d->prefetchRows = val.toInt(&ok);
+ if (!ok)
+ d->prefetchRows = -1;
+ } else if (opt == QLatin1String("OCI_ATTR_PREFETCH_MEMORY")) {
+ d->prefetchMem = val.toInt(&ok);
+ if (!ok)
+ d->prefetchMem = -1;
+ } else {
+ qWarning ("QOCIDriver::parseArgs: Invalid parameter: '%s'",
+ opt.toLocal8Bit().constData());
+ }
+ }
+}
+
+bool QOCIDriver::open(const QString & db,
+ const QString & user,
+ const QString & password,
+ const QString & hostname,
+ int port,
+ const QString &opts)
+{
+ Q_D(QOCIDriver);
+ int r;
+
+ if (isOpen())
+ close();
+
+ qParseOpts(opts, d);
+
+ // Connect without tnsnames.ora if a hostname is given
+ QString connectionString = db;
+ if (!hostname.isEmpty())
+ connectionString =
+ QString::fromLatin1("(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=%1)(Port=%2))"
+ "(CONNECT_DATA=(SID=%3)))").arg(hostname).arg((port > -1 ? port : 1521)).arg(db);
+
+ r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->srvhp), OCI_HTYPE_SERVER, 0, 0);
+ if (r == OCI_SUCCESS)
+ r = OCIServerAttach(d->srvhp, d->err, reinterpret_cast<const OraText *>(connectionString.utf16()),
+ connectionString.length() * sizeof(QChar), OCI_DEFAULT);
+ if (r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO)
+ r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->svc), OCI_HTYPE_SVCCTX, 0, 0);
+ if (r == OCI_SUCCESS)
+ r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, d->srvhp, 0, OCI_ATTR_SERVER, d->err);
+ if (r == OCI_SUCCESS)
+ r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->authp), OCI_HTYPE_SESSION, 0, 0);
+ if (r == OCI_SUCCESS)
+ r = OCIAttrSet(d->authp, OCI_HTYPE_SESSION, const_cast<ushort *>(user.utf16()),
+ user.length() * sizeof(QChar), OCI_ATTR_USERNAME, d->err);
+ if (r == OCI_SUCCESS)
+ r = OCIAttrSet(d->authp, OCI_HTYPE_SESSION, const_cast<ushort *>(password.utf16()),
+ password.length() * sizeof(QChar), OCI_ATTR_PASSWORD, d->err);
+
+ OCITrans* trans;
+ if (r == OCI_SUCCESS)
+ r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&trans), OCI_HTYPE_TRANS, 0, 0);
+ if (r == OCI_SUCCESS)
+ r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, trans, 0, OCI_ATTR_TRANS, d->err);
+
+ if (r == OCI_SUCCESS) {
+ if (user.isEmpty() && password.isEmpty())
+ r = OCISessionBegin(d->svc, d->err, d->authp, OCI_CRED_EXT, OCI_DEFAULT);
+ else
+ r = OCISessionBegin(d->svc, d->err, d->authp, OCI_CRED_RDBMS, OCI_DEFAULT);
+ }
+ if (r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO)
+ r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, d->authp, 0, OCI_ATTR_SESSION, d->err);
+
+ if (r != OCI_SUCCESS) {
+ setLastError(qMakeError(tr("Unable to logon"), QSqlError::ConnectionError, d->err));
+ setOpenError(true);
+ if (d->authp)
+ OCIHandleFree(d->authp, OCI_HTYPE_SESSION);
+ d->authp = 0;
+ if (d->srvhp)
+ OCIHandleFree(d->srvhp, OCI_HTYPE_SERVER);
+ d->srvhp = 0;
+ return false;
+ }
+
+ // get server version
+ char vertxt[512];
+ r = OCIServerVersion(d->svc,
+ d->err,
+ reinterpret_cast<OraText *>(vertxt),
+ sizeof(vertxt),
+ OCI_HTYPE_SVCCTX);
+ if (r != 0) {
+ qWarning("QOCIDriver::open: could not get Oracle server version.");
+ } else {
+ QString versionStr;
+ versionStr = QString(reinterpret_cast<const QChar *>(vertxt));
+ QRegExp vers(QLatin1String("([0-9]+)\\.[0-9\\.]+[0-9]"));
+ if (vers.indexIn(versionStr) >= 0)
+ d->serverVersion = vers.cap(1).toInt();
+ if (d->serverVersion == 0)
+ d->serverVersion = -1;
+ }
+
+ setOpen(true);
+ setOpenError(false);
+ d->user = user;
+
+ return true;
+}
+
+void QOCIDriver::close()
+{
+ Q_D(QOCIDriver);
+ if (!isOpen())
+ return;
+
+ OCISessionEnd(d->svc, d->err, d->authp, OCI_DEFAULT);
+ OCIServerDetach(d->srvhp, d->err, OCI_DEFAULT);
+ OCIHandleFree(d->authp, OCI_HTYPE_SESSION);
+ d->authp = 0;
+ OCIHandleFree(d->srvhp, OCI_HTYPE_SERVER);
+ d->srvhp = 0;
+ OCIHandleFree(d->svc, OCI_HTYPE_SVCCTX);
+ d->svc = 0;
+ setOpen(false);
+ setOpenError(false);
+}
+
+QSqlResult *QOCIDriver::createResult() const
+{
+ return new QOCIResult(this);
+}
+
+bool QOCIDriver::beginTransaction()
+{
+ Q_D(QOCIDriver);
+ if (!isOpen()) {
+ qWarning("QOCIDriver::beginTransaction: Database not open");
+ return false;
+ }
+ int r = OCITransStart(d->svc,
+ d->err,
+ 2,
+ OCI_TRANS_READWRITE);
+ if (r == OCI_ERROR) {
+ qOraWarning("QOCIDriver::beginTransaction: ", d->err);
+ setLastError(qMakeError(QCoreApplication::translate("QOCIDriver",
+ "Unable to begin transaction"), QSqlError::TransactionError, d->err));
+ return false;
+ }
+ d->transaction = true;
+ return true;
+}
+
+bool QOCIDriver::commitTransaction()
+{
+ Q_D(QOCIDriver);
+ if (!isOpen()) {
+ qWarning("QOCIDriver::commitTransaction: Database not open");
+ return false;
+ }
+ int r = OCITransCommit(d->svc,
+ d->err,
+ 0);
+ if (r == OCI_ERROR) {
+ qOraWarning("QOCIDriver::commitTransaction:", d->err);
+ setLastError(qMakeError(QCoreApplication::translate("QOCIDriver",
+ "Unable to commit transaction"), QSqlError::TransactionError, d->err));
+ return false;
+ }
+ d->transaction = false;
+ return true;
+}
+
+bool QOCIDriver::rollbackTransaction()
+{
+ Q_D(QOCIDriver);
+ if (!isOpen()) {
+ qWarning("QOCIDriver::rollbackTransaction: Database not open");
+ return false;
+ }
+ int r = OCITransRollback(d->svc,
+ d->err,
+ 0);
+ if (r == OCI_ERROR) {
+ qOraWarning("QOCIDriver::rollbackTransaction:", d->err);
+ setLastError(qMakeError(QCoreApplication::translate("QOCIDriver",
+ "Unable to rollback transaction"), QSqlError::TransactionError, d->err));
+ return false;
+ }
+ d->transaction = false;
+ return true;
+}
+
+enum Expression {
+ OrExpression,
+ AndExpression
+};
+
+static QString make_where_clause(const QString &user, Expression e)
+{
+ static const char sysUsers[][8] = {
+ "MDSYS",
+ "LBACSYS",
+ "SYS",
+ "SYSTEM",
+ "WKSYS",
+ "CTXSYS",
+ "WMSYS",
+ };
+ static const char joinC[][4] = { "or" , "and" };
+ static Q_CONSTEXPR QLatin1Char bang[] = { QLatin1Char(' '), QLatin1Char('!') };
+
+ const QLatin1String join(joinC[e], -1); // -1: force strlen call
+
+ QString result;
+ result.reserve(sizeof sysUsers / sizeof *sysUsers *
+ // max-sizeof(owner != <sysuser> and )
+ (9 + sizeof *sysUsers + 5));
+ for (const auto &sysUser : sysUsers) {
+ const QLatin1String l1(sysUser, -1); // -1: force strlen call
+ if (l1 != user)
+ result += QLatin1String("owner ") + bang[e] + QLatin1String("= '") + l1 + QLatin1Char(' ') + join + QLatin1Char(' ');
+ }
+
+ result.chop(join.size() + 2); // remove final " <join> "
+
+ return result;
+}
+
+QStringList QOCIDriver::tables(QSql::TableType type) const
+{
+ Q_D(const QOCIDriver);
+ QStringList tl;
+
+ QString user = d->user;
+ if ( isIdentifierEscaped(user, QSqlDriver::TableName))
+ user = stripDelimiters(user, QSqlDriver::TableName);
+ else
+ user = user.toUpper();
+
+ if (!isOpen())
+ return tl;
+
+ QSqlQuery t(createResult());
+ t.setForwardOnly(true);
+ if (type & QSql::Tables) {
+ const QLatin1String tableQuery("select owner, table_name from all_tables where ");
+ const QString where = make_where_clause(user, AndExpression);
+ t.exec(tableQuery + where);
+ while (t.next()) {
+ if (t.value(0).toString().toUpper() != user.toUpper())
+ tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
+ else
+ tl.append(t.value(1).toString());
+ }
+
+ // list all table synonyms as well
+ const QLatin1String synonymQuery("select owner, synonym_name from all_synonyms where ");
+ t.exec(synonymQuery + where);
+ while (t.next()) {
+ if (t.value(0).toString() != d->user)
+ tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
+ else
+ tl.append(t.value(1).toString());
+ }
+ }
+ if (type & QSql::Views) {
+ const QLatin1String query("select owner, view_name from all_views where ");
+ const QString where = make_where_clause(user, AndExpression);
+ t.exec(query + where);
+ while (t.next()) {
+ if (t.value(0).toString().toUpper() != d->user.toUpper())
+ tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
+ else
+ tl.append(t.value(1).toString());
+ }
+ }
+ if (type & QSql::SystemTables) {
+ t.exec(QLatin1String("select table_name from dictionary"));
+ while (t.next()) {
+ tl.append(t.value(0).toString());
+ }
+ const QLatin1String tableQuery("select owner, table_name from all_tables where ");
+ const QString where = make_where_clause(user, OrExpression);
+ t.exec(tableQuery + where);
+ while (t.next()) {
+ if (t.value(0).toString().toUpper() != user.toUpper())
+ tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
+ else
+ tl.append(t.value(1).toString());
+ }
+
+ // list all table synonyms as well
+ const QLatin1String synonymQuery("select owner, synonym_name from all_synonyms where ");
+ t.exec(synonymQuery + where);
+ while (t.next()) {
+ if (t.value(0).toString() != d->user)
+ tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
+ else
+ tl.append(t.value(1).toString());
+ }
+ }
+ return tl;
+}
+
+void qSplitTableAndOwner(const QString & tname, QString * tbl,
+ QString * owner)
+{
+ int i = tname.indexOf(QLatin1Char('.')); // prefixed with owner?
+ if (i != -1) {
+ *tbl = tname.right(tname.length() - i - 1);
+ *owner = tname.left(i);
+ } else {
+ *tbl = tname;
+ }
+}
+
+QSqlRecord QOCIDriver::record(const QString& tablename) const
+{
+ Q_D(const QOCIDriver);
+ QSqlRecord fil;
+ if (!isOpen())
+ return fil;
+
+ QSqlQuery t(createResult());
+ // using two separate queries for this is A LOT faster than using
+ // eg. a sub-query on the sys.synonyms table
+ QString stmt(QLatin1String("select column_name, data_type, data_length, "
+ "data_precision, data_scale, nullable, data_default%1"
+ "from all_tab_columns a "
+ "where a.table_name=%2"));
+ if (d->serverVersion >= 9)
+ stmt = stmt.arg(QLatin1String(", char_length "));
+ else
+ stmt = stmt.arg(QLatin1String(" "));
+ bool buildRecordInfo = false;
+ QString table, owner, tmpStmt;
+ qSplitTableAndOwner(tablename, &table, &owner);
+
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = table.toUpper();
+
+ tmpStmt = stmt.arg(QLatin1Char('\'') + table + QLatin1Char('\''));
+ if (owner.isEmpty()) {
+ owner = d->user;
+ }
+
+ if (isIdentifierEscaped(owner, QSqlDriver::TableName))
+ owner = stripDelimiters(owner, QSqlDriver::TableName);
+ else
+ owner = owner.toUpper();
+
+ tmpStmt += QLatin1String(" and a.owner='") + owner + QLatin1Char('\'');
+ t.setForwardOnly(true);
+ t.exec(tmpStmt);
+ if (!t.next()) { // try and see if the tablename is a synonym
+ stmt = stmt + QLatin1String(" join all_synonyms b "
+ "on a.owner=b.table_owner and a.table_name=b.table_name "
+ "where b.owner='") + owner +
+ QLatin1String("' and b.synonym_name='") + table +
+ QLatin1Char('\'');
+ t.setForwardOnly(true);
+ t.exec(stmt);
+ if (t.next())
+ buildRecordInfo = true;
+ } else {
+ buildRecordInfo = true;
+ }
+ QStringList keywords = QStringList() << QLatin1String("NUMBER") << QLatin1String("FLOAT") << QLatin1String("BINARY_FLOAT")
+ << QLatin1String("BINARY_DOUBLE");
+ if (buildRecordInfo) {
+ do {
+ QVariant::Type ty = qDecodeOCIType(t.value(1).toString(), t.numericalPrecisionPolicy());
+ QSqlField f(t.value(0).toString(), ty);
+ f.setRequired(t.value(5).toString() == QLatin1String("N"));
+ f.setPrecision(t.value(4).toInt());
+ if (d->serverVersion >= 9 && (ty == QVariant::String) && !t.isNull(3) && !keywords.contains(t.value(1).toString())) {
+ // Oracle9: data_length == size in bytes, char_length == amount of characters
+ f.setLength(t.value(7).toInt());
+ } else {
+ f.setLength(t.value(t.isNull(3) ? 2 : 3).toInt());
+ }
+ f.setDefaultValue(t.value(6));
+ fil.append(f);
+ } while (t.next());
+ }
+ return fil;
+}
+
+QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
+{
+ Q_D(const QOCIDriver);
+ QSqlIndex idx(tablename);
+ if (!isOpen())
+ return idx;
+ QSqlQuery t(createResult());
+ QString stmt(QLatin1String("select b.column_name, b.index_name, a.table_name, a.owner "
+ "from all_constraints a, all_ind_columns b "
+ "where a.constraint_type='P' "
+ "and b.index_name = a.constraint_name "
+ "and b.index_owner = a.owner"));
+
+ bool buildIndex = false;
+ QString table, owner, tmpStmt;
+ qSplitTableAndOwner(tablename, &table, &owner);
+
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = table.toUpper();
+
+ tmpStmt = stmt + QLatin1String(" and a.table_name='") + table + QLatin1Char('\'');
+ if (owner.isEmpty()) {
+ owner = d->user;
+ }
+
+ if (isIdentifierEscaped(owner, QSqlDriver::TableName))
+ owner = stripDelimiters(owner, QSqlDriver::TableName);
+ else
+ owner = owner.toUpper();
+
+ tmpStmt += QLatin1String(" and a.owner='") + owner + QLatin1Char('\'');
+ t.setForwardOnly(true);
+ t.exec(tmpStmt);
+
+ if (!t.next()) {
+ stmt += QLatin1String(" and a.table_name=(select tname from sys.synonyms "
+ "where sname='") + table + QLatin1String("' and creator=a.owner)");
+ t.setForwardOnly(true);
+ t.exec(stmt);
+ if (t.next()) {
+ owner = t.value(3).toString();
+ buildIndex = true;
+ }
+ } else {
+ buildIndex = true;
+ }
+ if (buildIndex) {
+ QSqlQuery tt(createResult());
+ tt.setForwardOnly(true);
+ idx.setName(t.value(1).toString());
+ do {
+ tt.exec(QLatin1String("select data_type from all_tab_columns where table_name='") +
+ t.value(2).toString() + QLatin1String("' and column_name='") +
+ t.value(0).toString() + QLatin1String("' and owner='") +
+ owner + QLatin1Char('\''));
+ if (!tt.next()) {
+ return QSqlIndex();
+ }
+ QSqlField f(t.value(0).toString(), qDecodeOCIType(tt.value(0).toString(), t.numericalPrecisionPolicy()));
+ idx.append(f);
+ } while (t.next());
+ return idx;
+ }
+ return QSqlIndex();
+}
+
+QString QOCIDriver::formatValue(const QSqlField &field, bool trimStrings) const
+{
+ switch (field.type()) {
+ case QVariant::DateTime: {
+ QDateTime datetime = field.value().toDateTime();
+ QString datestring;
+ if (datetime.isValid()) {
+ datestring = QLatin1String("TO_DATE('") + QString::number(datetime.date().year())
+ + QLatin1Char('-')
+ + QString::number(datetime.date().month()) + QLatin1Char('-')
+ + QString::number(datetime.date().day()) + QLatin1Char(' ')
+ + QString::number(datetime.time().hour()) + QLatin1Char(':')
+ + QString::number(datetime.time().minute()) + QLatin1Char(':')
+ + QString::number(datetime.time().second())
+ + QLatin1String("','YYYY-MM-DD HH24:MI:SS')");
+ } else {
+ datestring = QLatin1String("NULL");
+ }
+ return datestring;
+ }
+ case QVariant::Time: {
+ QDateTime datetime = field.value().toDateTime();
+ QString datestring;
+ if (datetime.isValid()) {
+ datestring = QLatin1String("TO_DATE('")
+ + QString::number(datetime.time().hour()) + QLatin1Char(':')
+ + QString::number(datetime.time().minute()) + QLatin1Char(':')
+ + QString::number(datetime.time().second())
+ + QLatin1String("','HH24:MI:SS')");
+ } else {
+ datestring = QLatin1String("NULL");
+ }
+ return datestring;
+ }
+ case QVariant::Date: {
+ QDate date = field.value().toDate();
+ QString datestring;
+ if (date.isValid()) {
+ datestring = QLatin1String("TO_DATE('") + QString::number(date.year()) +
+ QLatin1Char('-') +
+ QString::number(date.month()) + QLatin1Char('-') +
+ QString::number(date.day()) + QLatin1String("','YYYY-MM-DD')");
+ } else {
+ datestring = QLatin1String("NULL");
+ }
+ return datestring;
+ }
+ default:
+ break;
+ }
+ return QSqlDriver::formatValue(field, trimStrings);
+}
+
+QVariant QOCIDriver::handle() const
+{
+ Q_D(const QOCIDriver);
+ return QVariant::fromValue(d->env);
+}
+
+QString QOCIDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
+{
+ QString res = identifier;
+ if(!identifier.isEmpty() && !isIdentifierEscaped(identifier, type)) {
+ res.replace(QLatin1Char('"'), QLatin1String("\"\""));
+ res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
+ res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ }
+ return res;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/oci/qsql_oci_p.h b/src/plugins/sqldrivers/oci/qsql_oci_p.h
new file mode 100644
index 0000000000..69911f4bee
--- /dev/null
+++ b/src/plugins/sqldrivers/oci/qsql_oci_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSQL_OCI_H
+#define QSQL_OCI_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 <QtSql/qsqldriver.h>
+
+#ifdef QT_PLUGIN
+#define Q_EXPORT_SQLDRIVER_OCI
+#else
+#define Q_EXPORT_SQLDRIVER_OCI Q_SQL_EXPORT
+#endif
+
+typedef struct OCIEnv OCIEnv;
+typedef struct OCISvcCtx OCISvcCtx;
+
+QT_BEGIN_NAMESPACE
+
+class QSqlResult;
+class QOCIDriverPrivate;
+
+class Q_EXPORT_SQLDRIVER_OCI QOCIDriver : public QSqlDriver
+{
+ Q_DECLARE_PRIVATE(QOCIDriver)
+ Q_OBJECT
+ friend class QOCICols;
+ friend class QOCIResultPrivate;
+
+public:
+ explicit QOCIDriver(QObject* parent = 0);
+ QOCIDriver(OCIEnv* env, OCISvcCtx* ctx, QObject* parent = 0);
+ ~QOCIDriver();
+ bool hasFeature(DriverFeature f) const;
+ bool open(const QString &db,
+ const QString &user,
+ const QString &password,
+ const QString &host,
+ int port,
+ const QString &connOpts) Q_DECL_OVERRIDE;
+ void close() Q_DECL_OVERRIDE;
+ QSqlResult *createResult() const Q_DECL_OVERRIDE;
+ QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
+ QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE;
+ QSqlIndex primaryIndex(const QString& tablename) const Q_DECL_OVERRIDE;
+ QString formatValue(const QSqlField &field,
+ bool trimStrings) const Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+ QString escapeIdentifier(const QString &identifier, IdentifierType) const Q_DECL_OVERRIDE;
+
+protected:
+ bool beginTransaction() Q_DECL_OVERRIDE;
+ bool commitTransaction() Q_DECL_OVERRIDE;
+ bool rollbackTransaction() Q_DECL_OVERRIDE;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQL_OCI_H
diff --git a/src/plugins/sqldrivers/odbc/main.cpp b/src/plugins/sqldrivers/odbc/main.cpp
index 69ea7b1f8e..ac63941a82 100644
--- a/src/plugins/sqldrivers/odbc/main.cpp
+++ b/src/plugins/sqldrivers/odbc/main.cpp
@@ -39,7 +39,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/odbc/qsql_odbc_p.h"
+#include "qsql_odbc_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/odbc/odbc.pro b/src/plugins/sqldrivers/odbc/odbc.pro
index c0020c065f..0e49f1ac66 100644
--- a/src/plugins/sqldrivers/odbc/odbc.pro
+++ b/src/plugins/sqldrivers/odbc/odbc.pro
@@ -1,8 +1,19 @@
TARGET = qsqlodbc
-SOURCES = main.cpp
+HEADERS += $$PWD/qsql_odbc_p.h
+SOURCES += $$PWD/qsql_odbc.cpp $$PWD/main.cpp
+
+unix {
+ DEFINES += UNICODE
+ !contains(LIBS, .*odbc.*) {
+ osx:LIBS += -liodbc
+ else:LIBS += $$QMAKE_LIBS_ODBC
+ }
+} else {
+ LIBS *= -lodbc32
+}
+
OTHER_FILES += odbc.json
-include(../../../sql/drivers/odbc/qsql_odbc.pri)
PLUGIN_CLASS_NAME = QODBCDriverPlugin
include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
new file mode 100644
index 0000000000..59ef42d609
--- /dev/null
+++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
@@ -0,0 +1,2639 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsql_odbc_p.h"
+#include <qsqlrecord.h>
+
+#if defined (Q_OS_WIN32)
+#include <qt_windows.h>
+#endif
+#include <qcoreapplication.h>
+#include <qvariant.h>
+#include <qdatetime.h>
+#include <qsqlerror.h>
+#include <qsqlfield.h>
+#include <qsqlindex.h>
+#include <qstringlist.h>
+#include <qvarlengtharray.h>
+#include <qvector.h>
+#include <qmath.h>
+#include <QDebug>
+#include <QSqlQuery>
+#include <QtSql/private/qsqldriver_p.h>
+#include <QtSql/private/qsqlresult_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// undefine this to prevent initial check of the ODBC driver
+#define ODBC_CHECK_DRIVER
+
+static const int COLNAMESIZE = 256;
+//Map Qt parameter types to ODBC types
+static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
+
+inline static QString fromSQLTCHAR(const QVarLengthArray<SQLTCHAR>& input, int size=-1)
+{
+ QString result;
+
+ int realsize = qMin(size, input.size());
+ if(realsize > 0 && input[realsize-1] == 0)
+ realsize--;
+ switch(sizeof(SQLTCHAR)) {
+ case 1:
+ result=QString::fromUtf8((const char *)input.constData(), realsize);
+ break;
+ case 2:
+ result=QString::fromUtf16((const ushort *)input.constData(), realsize);
+ break;
+ case 4:
+ result=QString::fromUcs4((const uint *)input.constData(), realsize);
+ break;
+ default:
+ qCritical("sizeof(SQLTCHAR) is %d. Don't know how to handle this.", int(sizeof(SQLTCHAR)));
+ }
+ return result;
+}
+
+inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input)
+{
+ QVarLengthArray<SQLTCHAR> result;
+ result.resize(input.size());
+ switch(sizeof(SQLTCHAR)) {
+ case 1:
+ memcpy(result.data(), input.toUtf8().data(), input.size());
+ break;
+ case 2:
+ memcpy(result.data(), input.unicode(), input.size() * 2);
+ break;
+ case 4:
+ memcpy(result.data(), input.toUcs4().data(), input.size() * 4);
+ break;
+ default:
+ qCritical("sizeof(SQLTCHAR) is %d. Don't know how to handle this.", int(sizeof(SQLTCHAR)));
+ }
+ result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't.
+ return result;
+}
+
+class QODBCDriverPrivate : public QSqlDriverPrivate
+{
+ Q_DECLARE_PUBLIC(QODBCDriver)
+
+public:
+ enum DefaultCase{Lower, Mixed, Upper, Sensitive};
+ QODBCDriverPrivate()
+ : QSqlDriverPrivate(), hEnv(0), hDbc(0), unicode(false), useSchema(false), disconnectCount(0), datetime_precision(19),
+ isFreeTDSDriver(false), hasSQLFetchScroll(true), hasMultiResultSets(false), isQuoteInitialized(false), quote(QLatin1Char('"'))
+ {
+ }
+
+ SQLHANDLE hEnv;
+ SQLHANDLE hDbc;
+
+ bool unicode;
+ bool useSchema;
+ int disconnectCount;
+ int datetime_precision;
+ bool isFreeTDSDriver;
+ bool hasSQLFetchScroll;
+ bool hasMultiResultSets;
+
+ bool checkDriver() const;
+ void checkUnicode();
+ void checkDBMS();
+ void checkHasSQLFetchScroll();
+ void checkHasMultiResults();
+ void checkSchemaUsage();
+ void checkDateTimePrecision();
+ bool setConnectionOptions(const QString& connOpts);
+ void splitTableQualifier(const QString &qualifier, QString &catalog,
+ QString &schema, QString &table);
+ DefaultCase defaultCase() const;
+ QString adjustCase(const QString&) const;
+ QChar quoteChar();
+private:
+ bool isQuoteInitialized;
+ QChar quote;
+};
+
+class QODBCResultPrivate;
+
+class QODBCResult: public QSqlResult
+{
+ Q_DECLARE_PRIVATE(QODBCResult)
+
+public:
+ QODBCResult(const QODBCDriver *db);
+ virtual ~QODBCResult();
+
+ bool prepare(const QString &query) Q_DECL_OVERRIDE;
+ bool exec() Q_DECL_OVERRIDE;
+
+ QVariant lastInsertId() const Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+
+protected:
+ bool fetchNext() Q_DECL_OVERRIDE;
+ bool fetchFirst() Q_DECL_OVERRIDE;
+ bool fetchLast() Q_DECL_OVERRIDE;
+ bool fetchPrevious() Q_DECL_OVERRIDE;
+ bool fetch(int i) Q_DECL_OVERRIDE;
+ bool reset(const QString &query) Q_DECL_OVERRIDE;
+ QVariant data(int field) Q_DECL_OVERRIDE;
+ bool isNull(int field) Q_DECL_OVERRIDE;
+ int size() Q_DECL_OVERRIDE;
+ int numRowsAffected() Q_DECL_OVERRIDE;
+ QSqlRecord record() const Q_DECL_OVERRIDE;
+ void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
+ void detachFromResultSet() Q_DECL_OVERRIDE;
+ bool nextResult() Q_DECL_OVERRIDE;
+};
+
+class QODBCResultPrivate: public QSqlResultPrivate
+{
+ Q_DECLARE_PUBLIC(QODBCResult)
+
+public:
+ Q_DECLARE_SQLDRIVER_PRIVATE(QODBCDriver)
+ QODBCResultPrivate(QODBCResult *q, const QODBCDriver *db)
+ : QSqlResultPrivate(q, db),
+ hStmt(0),
+ useSchema(false),
+ hasSQLFetchScroll(true)
+ {
+ unicode = drv_d_func()->unicode;
+ useSchema = drv_d_func()->useSchema;
+ disconnectCount = drv_d_func()->disconnectCount;
+ hasSQLFetchScroll = drv_d_func()->hasSQLFetchScroll;
+ }
+
+ inline void clearValues()
+ { fieldCache.fill(QVariant()); fieldCacheIdx = 0; }
+
+ SQLHANDLE dpEnv() const { return drv_d_func() ? drv_d_func()->hEnv : 0;}
+ SQLHANDLE dpDbc() const { return drv_d_func() ? drv_d_func()->hDbc : 0;}
+ SQLHANDLE hStmt;
+
+ bool unicode;
+ bool useSchema;
+
+ QSqlRecord rInf;
+ QVector<QVariant> fieldCache;
+ int fieldCacheIdx;
+ int disconnectCount;
+ bool hasSQLFetchScroll;
+
+ bool isStmtHandleValid();
+ void updateStmtHandleState();
+};
+
+bool QODBCResultPrivate::isStmtHandleValid()
+{
+ return disconnectCount == drv_d_func()->disconnectCount;
+}
+
+void QODBCResultPrivate::updateStmtHandleState()
+{
+ disconnectCount = drv_d_func()->disconnectCount;
+}
+
+static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode = 0)
+{
+ SQLINTEGER nativeCode_ = 0;
+ SQLSMALLINT msgLen = 0;
+ SQLRETURN r = SQL_NO_DATA;
+ SQLTCHAR state_[SQL_SQLSTATE_SIZE+1];
+ QVarLengthArray<SQLTCHAR> description_(SQL_MAX_MESSAGE_LENGTH);
+ QString result;
+ int i = 1;
+
+ description_[0] = 0;
+ do {
+ r = SQLGetDiagRec(handleType,
+ handle,
+ i,
+ state_,
+ &nativeCode_,
+ 0,
+ 0,
+ &msgLen);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && msgLen > 0)
+ description_.resize(msgLen+1);
+ r = SQLGetDiagRec(handleType,
+ handle,
+ i,
+ state_,
+ &nativeCode_,
+ description_.data(),
+ description_.size(),
+ &msgLen);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (nativeCode)
+ *nativeCode = nativeCode_;
+ const QString tmpstore = fromSQLTCHAR(description_, msgLen);
+ if(result != tmpstore) {
+ if(!result.isEmpty())
+ result += QLatin1Char(' ');
+ result += tmpstore;
+ }
+ } else if (r == SQL_ERROR || r == SQL_INVALID_HANDLE) {
+ return result;
+ }
+ ++i;
+ } while (r != SQL_NO_DATA);
+ return result;
+}
+
+static QString qODBCWarn(const SQLHANDLE hStmt, const SQLHANDLE envHandle = 0,
+ const SQLHANDLE pDbC = 0, int *nativeCode = 0)
+{
+ QString result;
+ if (envHandle)
+ result += qWarnODBCHandle(SQL_HANDLE_ENV, envHandle, nativeCode);
+ if (pDbC) {
+ const QString dMessage = qWarnODBCHandle(SQL_HANDLE_DBC, pDbC, nativeCode);
+ if (!dMessage.isEmpty()) {
+ if (!result.isEmpty())
+ result += QLatin1Char(' ');
+ result += dMessage;
+ }
+ }
+ if (hStmt) {
+ const QString hMessage = qWarnODBCHandle(SQL_HANDLE_STMT, hStmt, nativeCode);
+ if (!hMessage.isEmpty()) {
+ if (!result.isEmpty())
+ result += QLatin1Char(' ');
+ result += hMessage;
+ }
+ }
+ return result;
+}
+
+static QString qODBCWarn(const QODBCResultPrivate* odbc, int *nativeCode = 0)
+{
+ return qODBCWarn(odbc->hStmt, odbc->dpEnv(), odbc->dpDbc(), nativeCode);
+}
+
+static QString qODBCWarn(const QODBCDriverPrivate* odbc, int *nativeCode = 0)
+{
+ return qODBCWarn(0, odbc->hEnv, odbc->hDbc, nativeCode);
+}
+
+static void qSqlWarning(const QString& message, const QODBCResultPrivate* odbc)
+{
+ qWarning() << message << "\tError:" << qODBCWarn(odbc);
+}
+
+static void qSqlWarning(const QString &message, const QODBCDriverPrivate *odbc)
+{
+ qWarning() << message << "\tError:" << qODBCWarn(odbc);
+}
+
+static void qSqlWarning(const QString &message, const SQLHANDLE hStmt)
+{
+ qWarning() << message << "\tError:" << qODBCWarn(hStmt);
+}
+
+static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, const QODBCResultPrivate* p)
+{
+ int nativeCode = -1;
+ QString message = qODBCWarn(p, &nativeCode);
+ return QSqlError(QLatin1String("QODBC3: ") + err, message, type, nativeCode);
+}
+
+static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
+ const QODBCDriverPrivate* p)
+{
+ int nativeCode = -1;
+ QString message = qODBCWarn(p, &nativeCode);
+ return QSqlError(QLatin1String("QODBC3: ") + err, qODBCWarn(p), type, nativeCode);
+}
+
+static QVariant::Type qDecodeODBCType(SQLSMALLINT sqltype, bool isSigned = true)
+{
+ QVariant::Type type = QVariant::Invalid;
+ switch (sqltype) {
+ case SQL_DECIMAL:
+ case SQL_NUMERIC:
+ case SQL_REAL:
+ case SQL_FLOAT:
+ case SQL_DOUBLE:
+ type = QVariant::Double;
+ break;
+ case SQL_SMALLINT:
+ case SQL_INTEGER:
+ case SQL_BIT:
+ type = isSigned ? QVariant::Int : QVariant::UInt;
+ break;
+ case SQL_TINYINT:
+ type = QVariant::UInt;
+ break;
+ case SQL_BIGINT:
+ type = isSigned ? QVariant::LongLong : QVariant::ULongLong;
+ break;
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ case SQL_LONGVARBINARY:
+ type = QVariant::ByteArray;
+ break;
+ case SQL_DATE:
+ case SQL_TYPE_DATE:
+ type = QVariant::Date;
+ break;
+ case SQL_TIME:
+ case SQL_TYPE_TIME:
+ type = QVariant::Time;
+ break;
+ case SQL_TIMESTAMP:
+ case SQL_TYPE_TIMESTAMP:
+ type = QVariant::DateTime;
+ break;
+ case SQL_WCHAR:
+ case SQL_WVARCHAR:
+ case SQL_WLONGVARCHAR:
+ type = QVariant::String;
+ break;
+ case SQL_CHAR:
+ case SQL_VARCHAR:
+#if (ODBCVER >= 0x0350)
+ case SQL_GUID:
+#endif
+ case SQL_LONGVARCHAR:
+ type = QVariant::String;
+ break;
+ default:
+ type = QVariant::ByteArray;
+ break;
+ }
+ return type;
+}
+
+static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool unicode = false)
+{
+ QString fieldVal;
+ SQLRETURN r = SQL_ERROR;
+ SQLLEN lengthIndicator = 0;
+
+ // NB! colSize must be a multiple of 2 for unicode enabled DBs
+ if (colSize <= 0) {
+ colSize = 256;
+ } else if (colSize > 65536) { // limit buffer size to 64 KB
+ colSize = 65536;
+ } else {
+ colSize++; // make sure there is room for more than the 0 termination
+ }
+ if(unicode) {
+ r = SQLGetData(hStmt,
+ column+1,
+ SQL_C_TCHAR,
+ NULL,
+ 0,
+ &lengthIndicator);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0)
+ colSize = int(lengthIndicator / sizeof(SQLTCHAR) + 1);
+ QVarLengthArray<SQLTCHAR> buf(colSize);
+ memset(buf.data(), 0, colSize*sizeof(SQLTCHAR));
+ while (true) {
+ r = SQLGetData(hStmt,
+ column+1,
+ SQL_C_TCHAR,
+ (SQLPOINTER)buf.data(),
+ colSize*sizeof(SQLTCHAR),
+ &lengthIndicator);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (lengthIndicator == SQL_NULL_DATA) {
+ fieldVal.clear();
+ break;
+ }
+ // starting with ODBC Native Client 2012, SQL_NO_TOTAL is returned
+ // instead of the length (which sometimes was wrong in older versions)
+ // see link for more info: http://msdn.microsoft.com/en-us/library/jj219209.aspx
+ // if length indicator equals SQL_NO_TOTAL, indicating that
+ // more data can be fetched, but size not known, collect data
+ // and fetch next block
+ if (lengthIndicator == SQL_NO_TOTAL) {
+ fieldVal += fromSQLTCHAR(buf, colSize);
+ continue;
+ }
+ // if SQL_SUCCESS_WITH_INFO is returned, indicating that
+ // more data can be fetched, the length indicator does NOT
+ // contain the number of bytes returned - it contains the
+ // total number of bytes that CAN be fetched
+ // colSize-1: remove 0 termination when there is more data to fetch
+ int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : int(lengthIndicator / sizeof(SQLTCHAR));
+ fieldVal += fromSQLTCHAR(buf, rSize);
+ if (lengthIndicator < SQLLEN(colSize*sizeof(SQLTCHAR))) {
+ // workaround for Drivermanagers that don't return SQL_NO_DATA
+ break;
+ }
+ } else if (r == SQL_NO_DATA) {
+ break;
+ } else {
+ qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
+ fieldVal.clear();
+ break;
+ }
+ }
+ } else {
+ r = SQLGetData(hStmt,
+ column+1,
+ SQL_C_CHAR,
+ NULL,
+ 0,
+ &lengthIndicator);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0)
+ colSize = lengthIndicator + 1;
+ QVarLengthArray<SQLCHAR> buf(colSize);
+ while (true) {
+ r = SQLGetData(hStmt,
+ column+1,
+ SQL_C_CHAR,
+ (SQLPOINTER)buf.data(),
+ colSize,
+ &lengthIndicator);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) {
+ fieldVal.clear();
+ break;
+ }
+ // if SQL_SUCCESS_WITH_INFO is returned, indicating that
+ // more data can be fetched, the length indicator does NOT
+ // contain the number of bytes returned - it contains the
+ // total number of bytes that CAN be fetched
+ // colSize-1: remove 0 termination when there is more data to fetch
+ int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : lengthIndicator;
+ fieldVal += QString::fromUtf8((const char *)buf.constData(), rSize);
+ if (lengthIndicator < SQLLEN(colSize)) {
+ // workaround for Drivermanagers that don't return SQL_NO_DATA
+ break;
+ }
+ } else if (r == SQL_NO_DATA) {
+ break;
+ } else {
+ qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
+ fieldVal.clear();
+ break;
+ }
+ }
+ }
+ return fieldVal;
+}
+
+static QVariant qGetBinaryData(SQLHANDLE hStmt, int column)
+{
+ QByteArray fieldVal;
+ SQLSMALLINT colNameLen;
+ SQLSMALLINT colType;
+ SQLULEN colSize;
+ SQLSMALLINT colScale;
+ SQLSMALLINT nullable;
+ SQLLEN lengthIndicator = 0;
+ SQLRETURN r = SQL_ERROR;
+
+ QVarLengthArray<SQLTCHAR> colName(COLNAMESIZE);
+
+ r = SQLDescribeCol(hStmt,
+ column + 1,
+ colName.data(),
+ COLNAMESIZE,
+ &colNameLen,
+ &colType,
+ &colSize,
+ &colScale,
+ &nullable);
+ if (r != SQL_SUCCESS)
+ qWarning() << "qGetBinaryData: Unable to describe column" << column;
+ // SQLDescribeCol may return 0 if size cannot be determined
+ if (!colSize)
+ colSize = 255;
+ else if (colSize > 65536) // read the field in 64 KB chunks
+ colSize = 65536;
+ fieldVal.resize(colSize);
+ ulong read = 0;
+ while (true) {
+ r = SQLGetData(hStmt,
+ column+1,
+ SQL_C_BINARY,
+ const_cast<char *>(fieldVal.constData() + read),
+ colSize,
+ &lengthIndicator);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
+ break;
+ if (lengthIndicator == SQL_NULL_DATA)
+ return QVariant(QVariant::ByteArray);
+ if (lengthIndicator > SQLLEN(colSize) || lengthIndicator == SQL_NO_TOTAL) {
+ read += colSize;
+ colSize = 65536;
+ } else {
+ read += lengthIndicator;
+ }
+ if (r == SQL_SUCCESS) { // the whole field was read in one chunk
+ fieldVal.resize(read);
+ break;
+ }
+ fieldVal.resize(fieldVal.size() + colSize);
+ }
+ return fieldVal;
+}
+
+static QVariant qGetIntData(SQLHANDLE hStmt, int column, bool isSigned = true)
+{
+ SQLINTEGER intbuf = 0;
+ SQLLEN lengthIndicator = 0;
+ SQLRETURN r = SQLGetData(hStmt,
+ column+1,
+ isSigned ? SQL_C_SLONG : SQL_C_ULONG,
+ (SQLPOINTER)&intbuf,
+ sizeof(intbuf),
+ &lengthIndicator);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
+ return QVariant(QVariant::Invalid);
+ if (lengthIndicator == SQL_NULL_DATA)
+ return QVariant(QVariant::Int);
+ if (isSigned)
+ return int(intbuf);
+ else
+ return uint(intbuf);
+}
+
+static QVariant qGetDoubleData(SQLHANDLE hStmt, int column)
+{
+ SQLDOUBLE dblbuf;
+ SQLLEN lengthIndicator = 0;
+ SQLRETURN r = SQLGetData(hStmt,
+ column+1,
+ SQL_C_DOUBLE,
+ (SQLPOINTER) &dblbuf,
+ 0,
+ &lengthIndicator);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ return QVariant(QVariant::Invalid);
+ }
+ if(lengthIndicator == SQL_NULL_DATA)
+ return QVariant(QVariant::Double);
+
+ return (double) dblbuf;
+}
+
+
+static QVariant qGetBigIntData(SQLHANDLE hStmt, int column, bool isSigned = true)
+{
+ SQLBIGINT lngbuf = 0;
+ SQLLEN lengthIndicator = 0;
+ SQLRETURN r = SQLGetData(hStmt,
+ column+1,
+ isSigned ? SQL_C_SBIGINT : SQL_C_UBIGINT,
+ (SQLPOINTER) &lngbuf,
+ sizeof(lngbuf),
+ &lengthIndicator);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
+ return QVariant(QVariant::Invalid);
+ if (lengthIndicator == SQL_NULL_DATA)
+ return QVariant(QVariant::LongLong);
+
+ if (isSigned)
+ return qint64(lngbuf);
+ else
+ return quint64(lngbuf);
+}
+
+static bool isAutoValue(const SQLHANDLE hStmt, int column)
+{
+ SQLLEN nNumericAttribute = 0; // Check for auto-increment
+ const SQLRETURN r = ::SQLColAttribute(hStmt, column + 1, SQL_DESC_AUTO_UNIQUE_VALUE,
+ 0, 0, 0, &nNumericAttribute);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ qSqlWarning(QStringLiteral("qMakeField: Unable to get autovalue attribute for column ")
+ + QString::number(column), hStmt);
+ return false;
+ }
+ return nNumericAttribute != SQL_FALSE;
+}
+
+static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMessage);
+
+// creates a QSqlField from a valid hStmt generated
+// by SQLColumns. The hStmt has to point to a valid position.
+static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, const QODBCDriverPrivate* p)
+{
+ QString fname = qGetStringData(hStmt, 3, -1, p->unicode);
+ int type = qGetIntData(hStmt, 4).toInt(); // column type
+ QSqlField f(fname, qDecodeODBCType(type, p));
+ QVariant var = qGetIntData(hStmt, 6);
+ f.setLength(var.isNull() ? -1 : var.toInt()); // column size
+ var = qGetIntData(hStmt, 8).toInt();
+ f.setPrecision(var.isNull() ? -1 : var.toInt()); // precision
+ f.setSqlType(type);
+ int required = qGetIntData(hStmt, 10).toInt(); // nullable-flag
+ // required can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
+ if (required == SQL_NO_NULLS)
+ f.setRequired(true);
+ else if (required == SQL_NULLABLE)
+ f.setRequired(false);
+ // else we don't know
+ return f;
+}
+
+static QSqlField qMakeFieldInfo(const QODBCResultPrivate* p, int i )
+{
+ QString errorMessage;
+ const QSqlField result = qMakeFieldInfo(p->hStmt, i, &errorMessage);
+ if (!errorMessage.isEmpty())
+ qSqlWarning(errorMessage, p);
+ return result;
+}
+
+static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMessage)
+{
+ SQLSMALLINT colNameLen;
+ SQLSMALLINT colType;
+ SQLULEN colSize;
+ SQLSMALLINT colScale;
+ SQLSMALLINT nullable;
+ SQLRETURN r = SQL_ERROR;
+ QVarLengthArray<SQLTCHAR> colName(COLNAMESIZE);
+ errorMessage->clear();
+ r = SQLDescribeCol(hStmt,
+ i+1,
+ colName.data(),
+ (SQLSMALLINT)COLNAMESIZE,
+ &colNameLen,
+ &colType,
+ &colSize,
+ &colScale,
+ &nullable);
+
+ if (r != SQL_SUCCESS) {
+ *errorMessage = QStringLiteral("qMakeField: Unable to describe column ") + QString::number(i);
+ return QSqlField();
+ }
+
+ SQLLEN unsignedFlag = SQL_FALSE;
+ r = SQLColAttribute (hStmt,
+ i + 1,
+ SQL_DESC_UNSIGNED,
+ 0,
+ 0,
+ 0,
+ &unsignedFlag);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QStringLiteral("qMakeField: Unable to get column attributes for column ")
+ + QString::number(i), hStmt);
+ }
+
+ const QString qColName(fromSQLTCHAR(colName, colNameLen));
+ // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
+ QVariant::Type type = qDecodeODBCType(colType, unsignedFlag == SQL_FALSE);
+ QSqlField f(qColName, type);
+ f.setSqlType(colType);
+ f.setLength(colSize == 0 ? -1 : int(colSize));
+ f.setPrecision(colScale == 0 ? -1 : int(colScale));
+ if (nullable == SQL_NO_NULLS)
+ f.setRequired(true);
+ else if (nullable == SQL_NULLABLE)
+ f.setRequired(false);
+ // else we don't know
+ f.setAutoValue(isAutoValue(hStmt, i));
+ return f;
+}
+
+static size_t qGetODBCVersion(const QString &connOpts)
+{
+ if (connOpts.contains(QLatin1String("SQL_ATTR_ODBC_VERSION=SQL_OV_ODBC3"), Qt::CaseInsensitive))
+ return SQL_OV_ODBC3;
+ return SQL_OV_ODBC2;
+}
+
+QChar QODBCDriverPrivate::quoteChar()
+{
+ if (!isQuoteInitialized) {
+ SQLTCHAR driverResponse[4];
+ SQLSMALLINT length;
+ int r = SQLGetInfo(hDbc,
+ SQL_IDENTIFIER_QUOTE_CHAR,
+ &driverResponse,
+ sizeof(driverResponse),
+ &length);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ quote = QChar(driverResponse[0]);
+ else
+ quote = QLatin1Char('"');
+ isQuoteInitialized = true;
+ }
+ return quote;
+}
+
+
+bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
+{
+ // Set any connection attributes
+ const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
+ SQLRETURN r = SQL_SUCCESS;
+ for (int i = 0; i < opts.count(); ++i) {
+ const QString tmp(opts.at(i));
+ int idx;
+ if ((idx = tmp.indexOf(QLatin1Char('='))) == -1) {
+ qWarning() << "QODBCDriver::open: Illegal connect option value '" << tmp << '\'';
+ continue;
+ }
+ const QString opt(tmp.left(idx));
+ const QString val(tmp.mid(idx + 1).simplified());
+ SQLUINTEGER v = 0;
+
+ r = SQL_SUCCESS;
+ if (opt.toUpper() == QLatin1String("SQL_ATTR_ACCESS_MODE")) {
+ if (val.toUpper() == QLatin1String("SQL_MODE_READ_ONLY")) {
+ v = SQL_MODE_READ_ONLY;
+ } else if (val.toUpper() == QLatin1String("SQL_MODE_READ_WRITE")) {
+ v = SQL_MODE_READ_WRITE;
+ } else {
+ qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ continue;
+ }
+ r = SQLSetConnectAttr(hDbc, SQL_ATTR_ACCESS_MODE, (SQLPOINTER) size_t(v), 0);
+ } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CONNECTION_TIMEOUT")) {
+ v = val.toUInt();
+ r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER) size_t(v), 0);
+ } else if (opt.toUpper() == QLatin1String("SQL_ATTR_LOGIN_TIMEOUT")) {
+ v = val.toUInt();
+ r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) size_t(v), 0);
+ } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) {
+ val.utf16(); // 0 terminate
+ r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG,
+ toSQLTCHAR(val).data(),
+ val.length()*sizeof(SQLTCHAR));
+ } else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) {
+ if (val.toUpper() == QLatin1String("SQL_TRUE")) {
+ v = SQL_TRUE;
+ } else if (val.toUpper() == QLatin1String("SQL_FALSE")) {
+ v = SQL_FALSE;
+ } else {
+ qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ continue;
+ }
+ r = SQLSetConnectAttr(hDbc, SQL_ATTR_METADATA_ID, (SQLPOINTER) size_t(v), 0);
+ } else if (opt.toUpper() == QLatin1String("SQL_ATTR_PACKET_SIZE")) {
+ v = val.toUInt();
+ r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) size_t(v), 0);
+ } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) {
+ val.utf16(); // 0 terminate
+ r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE,
+ toSQLTCHAR(val).data(),
+ val.length()*sizeof(SQLTCHAR));
+ } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) {
+ if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) {
+ v = SQL_OPT_TRACE_OFF;
+ } else if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_ON")) {
+ v = SQL_OPT_TRACE_ON;
+ } else {
+ qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ continue;
+ }
+ r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACE, (SQLPOINTER) size_t(v), 0);
+ } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CONNECTION_POOLING")) {
+ if (val == QLatin1String("SQL_CP_OFF"))
+ v = SQL_CP_OFF;
+ else if (val.toUpper() == QLatin1String("SQL_CP_ONE_PER_DRIVER"))
+ v = SQL_CP_ONE_PER_DRIVER;
+ else if (val.toUpper() == QLatin1String("SQL_CP_ONE_PER_HENV"))
+ v = SQL_CP_ONE_PER_HENV;
+ else if (val.toUpper() == QLatin1String("SQL_CP_DEFAULT"))
+ v = SQL_CP_DEFAULT;
+ else {
+ qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ continue;
+ }
+ r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER) size_t(v), 0);
+ } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CP_MATCH")) {
+ if (val.toUpper() == QLatin1String("SQL_CP_STRICT_MATCH"))
+ v = SQL_CP_STRICT_MATCH;
+ else if (val.toUpper() == QLatin1String("SQL_CP_RELAXED_MATCH"))
+ v = SQL_CP_RELAXED_MATCH;
+ else if (val.toUpper() == QLatin1String("SQL_CP_MATCH_DEFAULT"))
+ v = SQL_CP_MATCH_DEFAULT;
+ else {
+ qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ continue;
+ }
+ r = SQLSetConnectAttr(hDbc, SQL_ATTR_CP_MATCH, (SQLPOINTER) size_t(v), 0);
+ } else if (opt.toUpper() == QLatin1String("SQL_ATTR_ODBC_VERSION")) {
+ // Already handled in QODBCDriver::open()
+ continue;
+ } else {
+ qWarning() << "QODBCDriver::open: Unknown connection attribute '" << opt << '\'';
+ }
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
+ qSqlWarning(QString::fromLatin1("QODBCDriver::open: Unable to set connection attribute'%1'").arg(
+ opt), this);
+ }
+ return true;
+}
+
+void QODBCDriverPrivate::splitTableQualifier(const QString & qualifier, QString &catalog,
+ QString &schema, QString &table)
+{
+ if (!useSchema) {
+ table = qualifier;
+ return;
+ }
+ QStringList l = qualifier.split(QLatin1Char('.'));
+ if (l.count() > 3)
+ return; // can't possibly be a valid table qualifier
+ int i = 0, n = l.count();
+ if (n == 1) {
+ table = qualifier;
+ } else {
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ if (n == 3) {
+ if (i == 0) {
+ catalog = *it;
+ } else if (i == 1) {
+ schema = *it;
+ } else if (i == 2) {
+ table = *it;
+ }
+ } else if (n == 2) {
+ if (i == 0) {
+ schema = *it;
+ } else if (i == 1) {
+ table = *it;
+ }
+ }
+ i++;
+ }
+ }
+}
+
+QODBCDriverPrivate::DefaultCase QODBCDriverPrivate::defaultCase() const
+{
+ DefaultCase ret;
+ SQLUSMALLINT casing;
+ int r = SQLGetInfo(hDbc,
+ SQL_IDENTIFIER_CASE,
+ &casing,
+ sizeof(casing),
+ NULL);
+ if ( r != SQL_SUCCESS)
+ ret = Mixed;//arbitrary case if driver cannot be queried
+ else {
+ switch (casing) {
+ case (SQL_IC_UPPER):
+ ret = Upper;
+ break;
+ case (SQL_IC_LOWER):
+ ret = Lower;
+ break;
+ case (SQL_IC_SENSITIVE):
+ ret = Sensitive;
+ break;
+ case (SQL_IC_MIXED):
+ default:
+ ret = Mixed;
+ break;
+ }
+ }
+ return ret;
+}
+
+/*
+ Adjust the casing of an identifier to match what the
+ database engine would have done to it.
+*/
+QString QODBCDriverPrivate::adjustCase(const QString &identifier) const
+{
+ QString ret = identifier;
+ switch(defaultCase()) {
+ case (Lower):
+ ret = identifier.toLower();
+ break;
+ case (Upper):
+ ret = identifier.toUpper();
+ break;
+ case(Mixed):
+ case(Sensitive):
+ default:
+ ret = identifier;
+ }
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+QODBCResult::QODBCResult(const QODBCDriver *db)
+ : QSqlResult(*new QODBCResultPrivate(this, db))
+{
+}
+
+QODBCResult::~QODBCResult()
+{
+ Q_D(QODBCResult);
+ if (d->hStmt && d->isStmtHandleValid() && driver()->isOpen()) {
+ SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ")
+ + QString::number(r), d);
+ }
+}
+
+bool QODBCResult::reset (const QString& query)
+{
+ Q_D(QODBCResult);
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+ d->rInf.clear();
+ d->fieldCache.clear();
+ d->fieldCacheIdx = 0;
+
+ // Always reallocate the statement handle - the statement attributes
+ // are not reset if SQLFreeStmt() is called which causes some problems.
+ SQLRETURN r;
+ if (d->hStmt && d->isStmtHandleValid()) {
+ r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QODBCResult::reset: Unable to free statement handle"), d);
+ return false;
+ }
+ }
+ r = SQLAllocHandle(SQL_HANDLE_STMT,
+ d->dpDbc(),
+ &d->hStmt);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QODBCResult::reset: Unable to allocate statement handle"), d);
+ return false;
+ }
+
+ d->updateStmtHandleState();
+
+ if (isForwardOnly()) {
+ r = SQLSetStmtAttr(d->hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+ } else {
+ r = SQLSetStmtAttr(d->hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_STATIC,
+ SQL_IS_UINTEGER);
+ }
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. "
+ "Please check your ODBC driver configuration"), QSqlError::StatementError, d));
+ return false;
+ }
+
+ r = SQLExecDirect(d->hStmt,
+ toSQLTCHAR(query).data(),
+ (SQLINTEGER) query.length());
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) {
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to execute statement"), QSqlError::StatementError, d));
+ return false;
+ }
+
+ SQLULEN isScrollable = 0;
+ r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
+ if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ setForwardOnly(isScrollable == SQL_NONSCROLLABLE);
+
+ SQLSMALLINT count = 0;
+ SQLNumResultCols(d->hStmt, &count);
+ if (count) {
+ setSelect(true);
+ for (int i = 0; i < count; ++i) {
+ d->rInf.append(qMakeFieldInfo(d, i));
+ }
+ d->fieldCache.resize(count);
+ } else {
+ setSelect(false);
+ }
+ setActive(true);
+
+ return true;
+}
+
+bool QODBCResult::fetch(int i)
+{
+ Q_D(QODBCResult);
+ if (!driver()->isOpen())
+ return false;
+
+ if (isForwardOnly() && i < at())
+ return false;
+ if (i == at())
+ return true;
+ d->clearValues();
+ int actualIdx = i + 1;
+ if (actualIdx <= 0) {
+ setAt(QSql::BeforeFirstRow);
+ return false;
+ }
+ SQLRETURN r;
+ if (isForwardOnly()) {
+ bool ok = true;
+ while (ok && i > at())
+ ok = fetchNext();
+ return ok;
+ } else {
+ r = SQLFetchScroll(d->hStmt,
+ SQL_FETCH_ABSOLUTE,
+ actualIdx);
+ }
+ if (r != SQL_SUCCESS) {
+ if (r != SQL_NO_DATA)
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to fetch"), QSqlError::ConnectionError, d));
+ return false;
+ }
+ setAt(i);
+ return true;
+}
+
+bool QODBCResult::fetchNext()
+{
+ Q_D(QODBCResult);
+ SQLRETURN r;
+ d->clearValues();
+
+ if (d->hasSQLFetchScroll)
+ r = SQLFetchScroll(d->hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ else
+ r = SQLFetch(d->hStmt);
+
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (r != SQL_NO_DATA)
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to fetch next"), QSqlError::ConnectionError, d));
+ return false;
+ }
+ setAt(at() + 1);
+ return true;
+}
+
+bool QODBCResult::fetchFirst()
+{
+ Q_D(QODBCResult);
+ if (isForwardOnly() && at() != QSql::BeforeFirstRow)
+ return false;
+ SQLRETURN r;
+ d->clearValues();
+ if (isForwardOnly()) {
+ return fetchNext();
+ }
+ r = SQLFetchScroll(d->hStmt,
+ SQL_FETCH_FIRST,
+ 0);
+ if (r != SQL_SUCCESS) {
+ if (r != SQL_NO_DATA)
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to fetch first"), QSqlError::ConnectionError, d));
+ return false;
+ }
+ setAt(0);
+ return true;
+}
+
+bool QODBCResult::fetchPrevious()
+{
+ Q_D(QODBCResult);
+ if (isForwardOnly())
+ return false;
+ SQLRETURN r;
+ d->clearValues();
+ r = SQLFetchScroll(d->hStmt,
+ SQL_FETCH_PRIOR,
+ 0);
+ if (r != SQL_SUCCESS) {
+ if (r != SQL_NO_DATA)
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to fetch previous"), QSqlError::ConnectionError, d));
+ return false;
+ }
+ setAt(at() - 1);
+ return true;
+}
+
+bool QODBCResult::fetchLast()
+{
+ Q_D(QODBCResult);
+ SQLRETURN r;
+ d->clearValues();
+
+ if (isForwardOnly()) {
+ // cannot seek to last row in forwardOnly mode, so we have to use brute force
+ int i = at();
+ if (i == QSql::AfterLastRow)
+ return false;
+ if (i == QSql::BeforeFirstRow)
+ i = 0;
+ while (fetchNext())
+ ++i;
+ setAt(i);
+ return true;
+ }
+
+ r = SQLFetchScroll(d->hStmt,
+ SQL_FETCH_LAST,
+ 0);
+ if (r != SQL_SUCCESS) {
+ if (r != SQL_NO_DATA)
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to fetch last"), QSqlError::ConnectionError, d));
+ return false;
+ }
+ SQLULEN currRow = 0;
+ r = SQLGetStmtAttr(d->hStmt,
+ SQL_ROW_NUMBER,
+ &currRow,
+ SQL_IS_INTEGER,
+ 0);
+ if (r != SQL_SUCCESS)
+ return false;
+ setAt(currRow-1);
+ return true;
+}
+
+QVariant QODBCResult::data(int field)
+{
+ Q_D(QODBCResult);
+ if (field >= d->rInf.count() || field < 0) {
+ qWarning() << "QODBCResult::data: column" << field << "out of range";
+ return QVariant();
+ }
+ if (field < d->fieldCacheIdx)
+ return d->fieldCache.at(field);
+
+ SQLRETURN r(0);
+ SQLLEN lengthIndicator = 0;
+
+ for (int i = d->fieldCacheIdx; i <= field; ++i) {
+ // some servers do not support fetching column n after we already
+ // fetched column n+1, so cache all previous columns here
+ const QSqlField info = d->rInf.field(i);
+ switch (info.type()) {
+ case QVariant::LongLong:
+ d->fieldCache[i] = qGetBigIntData(d->hStmt, i);
+ break;
+ case QVariant::ULongLong:
+ d->fieldCache[i] = qGetBigIntData(d->hStmt, i, false);
+ break;
+ case QVariant::Int:
+ d->fieldCache[i] = qGetIntData(d->hStmt, i);
+ break;
+ case QVariant::UInt:
+ d->fieldCache[i] = qGetIntData(d->hStmt, i, false);
+ break;
+ case QVariant::Date:
+ DATE_STRUCT dbuf;
+ r = SQLGetData(d->hStmt,
+ i + 1,
+ SQL_C_DATE,
+ (SQLPOINTER)&dbuf,
+ 0,
+ &lengthIndicator);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
+ d->fieldCache[i] = QVariant(QDate(dbuf.year, dbuf.month, dbuf.day));
+ else
+ d->fieldCache[i] = QVariant(QVariant::Date);
+ break;
+ case QVariant::Time:
+ TIME_STRUCT tbuf;
+ r = SQLGetData(d->hStmt,
+ i + 1,
+ SQL_C_TIME,
+ (SQLPOINTER)&tbuf,
+ 0,
+ &lengthIndicator);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
+ d->fieldCache[i] = QVariant(QTime(tbuf.hour, tbuf.minute, tbuf.second));
+ else
+ d->fieldCache[i] = QVariant(QVariant::Time);
+ break;
+ case QVariant::DateTime:
+ TIMESTAMP_STRUCT dtbuf;
+ r = SQLGetData(d->hStmt,
+ i + 1,
+ SQL_C_TIMESTAMP,
+ (SQLPOINTER)&dtbuf,
+ 0,
+ &lengthIndicator);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
+ d->fieldCache[i] = QVariant(QDateTime(QDate(dtbuf.year, dtbuf.month, dtbuf.day),
+ QTime(dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000)));
+ else
+ d->fieldCache[i] = QVariant(QVariant::DateTime);
+ break;
+ case QVariant::ByteArray:
+ d->fieldCache[i] = qGetBinaryData(d->hStmt, i);
+ break;
+ case QVariant::String:
+ d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), d->unicode);
+ break;
+ case QVariant::Double:
+ switch(numericalPrecisionPolicy()) {
+ case QSql::LowPrecisionInt32:
+ d->fieldCache[i] = qGetIntData(d->hStmt, i);
+ break;
+ case QSql::LowPrecisionInt64:
+ d->fieldCache[i] = qGetBigIntData(d->hStmt, i);
+ break;
+ case QSql::LowPrecisionDouble:
+ d->fieldCache[i] = qGetDoubleData(d->hStmt, i);
+ break;
+ case QSql::HighPrecision:
+ d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), false);
+ break;
+ }
+ break;
+ default:
+ d->fieldCache[i] = QVariant(qGetStringData(d->hStmt, i, info.length(), false));
+ break;
+ }
+ d->fieldCacheIdx = field + 1;
+ }
+ return d->fieldCache[field];
+}
+
+bool QODBCResult::isNull(int field)
+{
+ Q_D(const QODBCResult);
+ if (field < 0 || field > d->fieldCache.size())
+ return true;
+ if (field <= d->fieldCacheIdx) {
+ // since there is no good way to find out whether the value is NULL
+ // without fetching the field we'll fetch it here.
+ // (data() also sets the NULL flag)
+ data(field);
+ }
+ return d->fieldCache.at(field).isNull();
+}
+
+int QODBCResult::size()
+{
+ return -1;
+}
+
+int QODBCResult::numRowsAffected()
+{
+ Q_D(QODBCResult);
+ SQLLEN affectedRowCount = 0;
+ SQLRETURN r = SQLRowCount(d->hStmt, &affectedRowCount);
+ if (r == SQL_SUCCESS)
+ return affectedRowCount;
+ else
+ qSqlWarning(QLatin1String("QODBCResult::numRowsAffected: Unable to count affected rows"), d);
+ return -1;
+}
+
+bool QODBCResult::prepare(const QString& query)
+{
+ Q_D(QODBCResult);
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+ SQLRETURN r;
+
+ d->rInf.clear();
+ if (d->hStmt && d->isStmtHandleValid()) {
+ r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QODBCResult::prepare: Unable to close statement"), d);
+ return false;
+ }
+ }
+ r = SQLAllocHandle(SQL_HANDLE_STMT,
+ d->dpDbc(),
+ &d->hStmt);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QODBCResult::prepare: Unable to allocate statement handle"), d);
+ return false;
+ }
+
+ d->updateStmtHandleState();
+
+ if (isForwardOnly()) {
+ r = SQLSetStmtAttr(d->hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+ } else {
+ r = SQLSetStmtAttr(d->hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_STATIC,
+ SQL_IS_UINTEGER);
+ }
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. "
+ "Please check your ODBC driver configuration"), QSqlError::StatementError, d));
+ return false;
+ }
+
+ r = SQLPrepare(d->hStmt,
+ toSQLTCHAR(query).data(),
+ (SQLINTEGER) query.length());
+
+ if (r != SQL_SUCCESS) {
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to prepare statement"), QSqlError::StatementError, d));
+ return false;
+ }
+ return true;
+}
+
+bool QODBCResult::exec()
+{
+ Q_D(QODBCResult);
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+ d->rInf.clear();
+ d->fieldCache.clear();
+ d->fieldCacheIdx = 0;
+
+ if (!d->hStmt) {
+ qSqlWarning(QLatin1String("QODBCResult::exec: No statement handle available"), d);
+ return false;
+ }
+
+ if (isSelect())
+ SQLCloseCursor(d->hStmt);
+
+ QVector<QVariant>& values = boundValues();
+ QVector<QByteArray> tmpStorage(values.count(), QByteArray()); // holds temporary buffers
+ QVarLengthArray<SQLLEN, 32> indicators(values.count());
+ memset(indicators.data(), 0, indicators.size() * sizeof(SQLLEN));
+
+ // bind parameters - only positional binding allowed
+ int i;
+ SQLRETURN r;
+ for (i = 0; i < values.count(); ++i) {
+ if (bindValueType(i) & QSql::Out)
+ values[i].detach();
+ const QVariant &val = values.at(i);
+ SQLLEN *ind = &indicators[i];
+ if (val.isNull())
+ *ind = SQL_NULL_DATA;
+ switch (val.type()) {
+ case QVariant::Date: {
+ QByteArray &ba = tmpStorage[i];
+ ba.resize(sizeof(DATE_STRUCT));
+ DATE_STRUCT *dt = (DATE_STRUCT *)const_cast<char *>(ba.constData());
+ QDate qdt = val.toDate();
+ dt->year = qdt.year();
+ dt->month = qdt.month();
+ dt->day = qdt.day();
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_DATE,
+ SQL_DATE,
+ 0,
+ 0,
+ (void *) dt,
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break; }
+ case QVariant::Time: {
+ QByteArray &ba = tmpStorage[i];
+ ba.resize(sizeof(TIME_STRUCT));
+ TIME_STRUCT *dt = (TIME_STRUCT *)const_cast<char *>(ba.constData());
+ QTime qdt = val.toTime();
+ dt->hour = qdt.hour();
+ dt->minute = qdt.minute();
+ dt->second = qdt.second();
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_TIME,
+ SQL_TIME,
+ 0,
+ 0,
+ (void *) dt,
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break; }
+ case QVariant::DateTime: {
+ QByteArray &ba = tmpStorage[i];
+ ba.resize(sizeof(TIMESTAMP_STRUCT));
+ TIMESTAMP_STRUCT * dt = (TIMESTAMP_STRUCT *)const_cast<char *>(ba.constData());
+ QDateTime qdt = val.toDateTime();
+ dt->year = qdt.date().year();
+ dt->month = qdt.date().month();
+ dt->day = qdt.date().day();
+ dt->hour = qdt.time().hour();
+ dt->minute = qdt.time().minute();
+ dt->second = qdt.time().second();
+
+ int precision = d->drv_d_func()->datetime_precision - 20; // (20 includes a separating period)
+ if (precision <= 0) {
+ dt->fraction = 0;
+ } else {
+ dt->fraction = qdt.time().msec() * 1000000;
+
+ // (How many leading digits do we want to keep? With SQL Server 2005, this should be 3: 123000000)
+ int keep = (int)qPow(10.0, 9 - qMin(9, precision));
+ dt->fraction = (dt->fraction / keep) * keep;
+ }
+
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_TIMESTAMP,
+ SQL_TIMESTAMP,
+ d->drv_d_func()->datetime_precision,
+ precision,
+ (void *) dt,
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break; }
+ case QVariant::Int:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_SLONG,
+ SQL_INTEGER,
+ 0,
+ 0,
+ const_cast<void *>(val.constData()),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QVariant::UInt:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_ULONG,
+ SQL_NUMERIC,
+ 15,
+ 0,
+ const_cast<void *>(val.constData()),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QVariant::Double:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_DOUBLE,
+ SQL_DOUBLE,
+ 0,
+ 0,
+ const_cast<void *>(val.constData()),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QVariant::LongLong:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_SBIGINT,
+ SQL_BIGINT,
+ 0,
+ 0,
+ const_cast<void *>(val.constData()),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QVariant::ULongLong:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_UBIGINT,
+ SQL_BIGINT,
+ 0,
+ 0,
+ const_cast<void *>(val.constData()),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QVariant::ByteArray:
+ if (*ind != SQL_NULL_DATA) {
+ *ind = val.toByteArray().size();
+ }
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_BINARY,
+ SQL_LONGVARBINARY,
+ val.toByteArray().size(),
+ 0,
+ const_cast<char *>(val.toByteArray().constData()),
+ val.toByteArray().size(),
+ ind);
+ break;
+ case QVariant::Bool:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_BIT,
+ SQL_BIT,
+ 0,
+ 0,
+ const_cast<void *>(val.constData()),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QVariant::String:
+ if (d->unicode) {
+ QByteArray &ba = tmpStorage[i];
+ QString str = val.toString();
+ if (*ind != SQL_NULL_DATA)
+ *ind = str.length() * sizeof(SQLTCHAR);
+ int strSize = str.length() * sizeof(SQLTCHAR);
+
+ if (bindValueType(i) & QSql::Out) {
+ const QVarLengthArray<SQLTCHAR> a(toSQLTCHAR(str));
+ ba = QByteArray((const char *)a.constData(), a.size() * sizeof(SQLTCHAR));
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_TCHAR,
+ strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
+ 0, // god knows... don't change this!
+ 0,
+ ba.data(),
+ ba.size(),
+ ind);
+ break;
+ }
+ ba = QByteArray ((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR));
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_TCHAR,
+ strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
+ strSize,
+ 0,
+ const_cast<char *>(ba.constData()),
+ ba.size(),
+ ind);
+ break;
+ }
+ else
+ {
+ QByteArray &str = tmpStorage[i];
+ str = val.toString().toUtf8();
+ if (*ind != SQL_NULL_DATA)
+ *ind = str.length();
+ int strSize = str.length();
+
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_CHAR,
+ strSize > 254 ? SQL_LONGVARCHAR : SQL_VARCHAR,
+ strSize,
+ 0,
+ const_cast<char *>(str.constData()),
+ strSize,
+ ind);
+ break;
+ }
+ // fall through
+ default: {
+ QByteArray &ba = tmpStorage[i];
+ if (*ind != SQL_NULL_DATA)
+ *ind = ba.size();
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_BINARY,
+ SQL_VARBINARY,
+ ba.length() + 1,
+ 0,
+ const_cast<char *>(ba.constData()),
+ ba.length() + 1,
+ ind);
+ break; }
+ }
+ if (r != SQL_SUCCESS) {
+ qWarning() << "QODBCResult::exec: unable to bind variable:" << qODBCWarn(d);
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to bind variable"), QSqlError::StatementError, d));
+ return false;
+ }
+ }
+ r = SQLExecute(d->hStmt);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
+ qWarning() << "QODBCResult::exec: Unable to execute statement:" << qODBCWarn(d);
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to execute statement"), QSqlError::StatementError, d));
+ return false;
+ }
+
+ SQLULEN isScrollable = 0;
+ r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
+ if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ setForwardOnly(isScrollable == SQL_NONSCROLLABLE);
+
+ SQLSMALLINT count = 0;
+ SQLNumResultCols(d->hStmt, &count);
+ if (count) {
+ setSelect(true);
+ for (int i = 0; i < count; ++i) {
+ d->rInf.append(qMakeFieldInfo(d, i));
+ }
+ d->fieldCache.resize(count);
+ } else {
+ setSelect(false);
+ }
+ setActive(true);
+
+
+ //get out parameters
+ if (!hasOutValues())
+ return true;
+
+ for (i = 0; i < values.count(); ++i) {
+ switch (values.at(i).type()) {
+ case QVariant::Date: {
+ DATE_STRUCT ds = *((DATE_STRUCT *)const_cast<char *>(tmpStorage.at(i).constData()));
+ values[i] = QVariant(QDate(ds.year, ds.month, ds.day));
+ break; }
+ case QVariant::Time: {
+ TIME_STRUCT dt = *((TIME_STRUCT *)const_cast<char *>(tmpStorage.at(i).constData()));
+ values[i] = QVariant(QTime(dt.hour, dt.minute, dt.second));
+ break; }
+ case QVariant::DateTime: {
+ TIMESTAMP_STRUCT dt = *((TIMESTAMP_STRUCT*)
+ const_cast<char *>(tmpStorage.at(i).constData()));
+ values[i] = QVariant(QDateTime(QDate(dt.year, dt.month, dt.day),
+ QTime(dt.hour, dt.minute, dt.second, dt.fraction / 1000000)));
+ break; }
+ case QVariant::Bool:
+ case QVariant::Int:
+ case QVariant::UInt:
+ case QVariant::Double:
+ case QVariant::ByteArray:
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ //nothing to do
+ break;
+ case QVariant::String:
+ if (d->unicode) {
+ if (bindValueType(i) & QSql::Out) {
+ const QByteArray &first = tmpStorage.at(i);
+ QVarLengthArray<SQLTCHAR> array;
+ array.append((const SQLTCHAR *)first.constData(), first.size());
+ values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR));
+ }
+ break;
+ }
+ // fall through
+ default: {
+ if (bindValueType(i) & QSql::Out)
+ values[i] = tmpStorage.at(i);
+ break; }
+ }
+ if (indicators[i] == SQL_NULL_DATA)
+ values[i] = QVariant(values[i].type());
+ }
+ return true;
+}
+
+QSqlRecord QODBCResult::record() const
+{
+ Q_D(const QODBCResult);
+ if (!isActive() || !isSelect())
+ return QSqlRecord();
+ return d->rInf;
+}
+
+QVariant QODBCResult::lastInsertId() const
+{
+ Q_D(const QODBCResult);
+ QString sql;
+
+ switch (driver()->dbmsType()) {
+ case QSqlDriver::MSSqlServer:
+ case QSqlDriver::Sybase:
+ sql = QLatin1String("SELECT @@IDENTITY;");
+ break;
+ case QSqlDriver::MySqlServer:
+ sql = QLatin1String("SELECT LAST_INSERT_ID();");
+ break;
+ case QSqlDriver::PostgreSQL:
+ sql = QLatin1String("SELECT lastval();");
+ break;
+ default:
+ break;
+ }
+
+ if (!sql.isEmpty()) {
+ QSqlQuery qry(driver()->createResult());
+ if (qry.exec(sql) && qry.next())
+ return qry.value(0);
+
+ qSqlWarning(QLatin1String("QODBCResult::lastInsertId: Unable to get lastInsertId"), d);
+ } else {
+ qSqlWarning(QLatin1String("QODBCResult::lastInsertId: not implemented for this DBMS"), d);
+ }
+
+ return QVariant();
+}
+
+QVariant QODBCResult::handle() const
+{
+ Q_D(const QODBCResult);
+ return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hStmt);
+}
+
+bool QODBCResult::nextResult()
+{
+ Q_D(QODBCResult);
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+ d->rInf.clear();
+ d->fieldCache.clear();
+ d->fieldCacheIdx = 0;
+ setSelect(false);
+
+ SQLRETURN r = SQLMoreResults(d->hStmt);
+ if (r != SQL_SUCCESS) {
+ if (r == SQL_SUCCESS_WITH_INFO) {
+ int nativeCode = -1;
+ QString message = qODBCWarn(d, &nativeCode);
+ qWarning() << "QODBCResult::nextResult():" << message;
+ } else {
+ if (r != SQL_NO_DATA)
+ setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+ "Unable to fetch last"), QSqlError::ConnectionError, d));
+ return false;
+ }
+ }
+
+ SQLSMALLINT count = 0;
+ SQLNumResultCols(d->hStmt, &count);
+ if (count) {
+ setSelect(true);
+ for (int i = 0; i < count; ++i) {
+ d->rInf.append(qMakeFieldInfo(d, i));
+ }
+ d->fieldCache.resize(count);
+ } else {
+ setSelect(false);
+ }
+ setActive(true);
+
+ return true;
+}
+
+void QODBCResult::virtual_hook(int id, void *data)
+{
+ QSqlResult::virtual_hook(id, data);
+}
+
+void QODBCResult::detachFromResultSet()
+{
+ Q_D(QODBCResult);
+ if (d->hStmt)
+ SQLCloseCursor(d->hStmt);
+}
+
+////////////////////////////////////////
+
+
+QODBCDriver::QODBCDriver(QObject *parent)
+ : QSqlDriver(*new QODBCDriverPrivate, parent)
+{
+}
+
+QODBCDriver::QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject *parent)
+ : QSqlDriver(*new QODBCDriverPrivate, parent)
+{
+ Q_D(QODBCDriver);
+ d->hEnv = env;
+ d->hDbc = con;
+ if (env && con) {
+ setOpen(true);
+ setOpenError(false);
+ }
+}
+
+QODBCDriver::~QODBCDriver()
+{
+ cleanup();
+}
+
+bool QODBCDriver::hasFeature(DriverFeature f) const
+{
+ Q_D(const QODBCDriver);
+ switch (f) {
+ case Transactions: {
+ if (!d->hDbc)
+ return false;
+ SQLUSMALLINT txn;
+ SQLSMALLINT t;
+ int r = SQLGetInfo(d->hDbc,
+ (SQLUSMALLINT)SQL_TXN_CAPABLE,
+ &txn,
+ sizeof(txn),
+ &t);
+ if (r != SQL_SUCCESS || txn == SQL_TC_NONE)
+ return false;
+ else
+ return true;
+ }
+ case Unicode:
+ return d->unicode;
+ case PreparedQueries:
+ case PositionalPlaceholders:
+ case FinishQuery:
+ case LowPrecisionNumbers:
+ return true;
+ case QuerySize:
+ case NamedPlaceholders:
+ case BatchOperations:
+ case SimpleLocking:
+ case EventNotifications:
+ case CancelQuery:
+ return false;
+ case LastInsertId:
+ return (d->dbmsType == MSSqlServer)
+ || (d->dbmsType == Sybase)
+ || (d->dbmsType == MySqlServer)
+ || (d->dbmsType == PostgreSQL);
+ case MultipleResultSets:
+ return d->hasMultiResultSets;
+ case BLOB: {
+ if (d->dbmsType == MySqlServer)
+ return true;
+ else
+ return false;
+ }
+ }
+ return false;
+}
+
+bool QODBCDriver::open(const QString & db,
+ const QString & user,
+ const QString & password,
+ const QString &,
+ int,
+ const QString& connOpts)
+{
+ Q_D(QODBCDriver);
+ if (isOpen())
+ close();
+ SQLRETURN r;
+ r = SQLAllocHandle(SQL_HANDLE_ENV,
+ SQL_NULL_HANDLE,
+ &d->hEnv);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ qSqlWarning(QLatin1String("QODBCDriver::open: Unable to allocate environment"), d);
+ setOpenError(true);
+ return false;
+ }
+ r = SQLSetEnvAttr(d->hEnv,
+ SQL_ATTR_ODBC_VERSION,
+ (SQLPOINTER)qGetODBCVersion(connOpts),
+ SQL_IS_UINTEGER);
+ r = SQLAllocHandle(SQL_HANDLE_DBC,
+ d->hEnv,
+ &d->hDbc);
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ qSqlWarning(QLatin1String("QODBCDriver::open: Unable to allocate connection"), d);
+ setOpenError(true);
+ cleanup();
+ return false;
+ }
+
+ if (!d->setConnectionOptions(connOpts)) {
+ cleanup();
+ return false;
+ }
+
+ // Create the connection string
+ QString connQStr;
+ // support the "DRIVER={SQL SERVER};SERVER=blah" syntax
+ if (db.contains(QLatin1String(".dsn"), Qt::CaseInsensitive))
+ connQStr = QLatin1String("FILEDSN=") + db;
+ else if (db.contains(QLatin1String("DRIVER="), Qt::CaseInsensitive)
+ || db.contains(QLatin1String("SERVER="), Qt::CaseInsensitive))
+ connQStr = db;
+ else
+ connQStr = QLatin1String("DSN=") + db;
+
+ if (!user.isEmpty())
+ connQStr += QLatin1String(";UID=") + user;
+ if (!password.isEmpty())
+ connQStr += QLatin1String(";PWD=") + password;
+
+ SQLSMALLINT cb;
+ QVarLengthArray<SQLTCHAR> connOut(1024);
+ memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR));
+ r = SQLDriverConnect(d->hDbc,
+ NULL,
+ toSQLTCHAR(connQStr).data(),
+ (SQLSMALLINT)connQStr.length(),
+ connOut.data(),
+ 1024,
+ &cb,
+ /*SQL_DRIVER_NOPROMPT*/0);
+
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
+ setOpenError(true);
+ cleanup();
+ return false;
+ }
+
+ if (!d->checkDriver()) {
+ setLastError(qMakeError(tr("Unable to connect - Driver doesn't support all "
+ "functionality required"), QSqlError::ConnectionError, d));
+ setOpenError(true);
+ cleanup();
+ return false;
+ }
+
+ d->checkUnicode();
+ d->checkSchemaUsage();
+ d->checkDBMS();
+ d->checkHasSQLFetchScroll();
+ d->checkHasMultiResults();
+ d->checkDateTimePrecision();
+ setOpen(true);
+ setOpenError(false);
+ if (d->dbmsType == MSSqlServer) {
+ QSqlQuery i(createResult());
+ i.exec(QLatin1String("SET QUOTED_IDENTIFIER ON"));
+ }
+ return true;
+}
+
+void QODBCDriver::close()
+{
+ cleanup();
+ setOpen(false);
+ setOpenError(false);
+}
+
+void QODBCDriver::cleanup()
+{
+ Q_D(QODBCDriver);
+ SQLRETURN r;
+
+ if(d->hDbc) {
+ // Open statements/descriptors handles are automatically cleaned up by SQLDisconnect
+ if (isOpen()) {
+ r = SQLDisconnect(d->hDbc);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QODBCDriver::disconnect: Unable to disconnect datasource"), d);
+ else
+ d->disconnectCount++;
+ }
+
+ r = SQLFreeHandle(SQL_HANDLE_DBC, d->hDbc);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QODBCDriver::cleanup: Unable to free connection handle"), d);
+ d->hDbc = 0;
+ }
+
+ if (d->hEnv) {
+ r = SQLFreeHandle(SQL_HANDLE_ENV, d->hEnv);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QODBCDriver::cleanup: Unable to free environment handle"), d);
+ d->hEnv = 0;
+ }
+}
+
+// checks whether the server can return char, varchar and longvarchar
+// as two byte unicode characters
+void QODBCDriverPrivate::checkUnicode()
+{
+ SQLRETURN r;
+ SQLUINTEGER fFunc;
+
+ unicode = false;
+ r = SQLGetInfo(hDbc,
+ SQL_CONVERT_CHAR,
+ (SQLPOINTER)&fFunc,
+ sizeof(fFunc),
+ NULL);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WCHAR)) {
+ unicode = true;
+ return;
+ }
+
+ r = SQLGetInfo(hDbc,
+ SQL_CONVERT_VARCHAR,
+ (SQLPOINTER)&fFunc,
+ sizeof(fFunc),
+ NULL);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WVARCHAR)) {
+ unicode = true;
+ return;
+ }
+
+ r = SQLGetInfo(hDbc,
+ SQL_CONVERT_LONGVARCHAR,
+ (SQLPOINTER)&fFunc,
+ sizeof(fFunc),
+ NULL);
+ if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WLONGVARCHAR)) {
+ unicode = true;
+ return;
+ }
+ SQLHANDLE hStmt;
+ r = SQLAllocHandle(SQL_HANDLE_STMT,
+ hDbc,
+ &hStmt);
+
+ r = SQLExecDirect(hStmt, toSQLTCHAR(QLatin1String("select 'test'")).data(), SQL_NTS);
+ if(r == SQL_SUCCESS) {
+ r = SQLFetch(hStmt);
+ if(r == SQL_SUCCESS) {
+ QVarLengthArray<SQLWCHAR> buffer(10);
+ r = SQLGetData(hStmt, 1, SQL_C_WCHAR, buffer.data(), buffer.size() * sizeof(SQLWCHAR), NULL);
+ if(r == SQL_SUCCESS && fromSQLTCHAR(buffer) == QLatin1String("test")) {
+ unicode = true;
+ }
+ }
+ }
+ r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
+}
+
+bool QODBCDriverPrivate::checkDriver() const
+{
+#ifdef ODBC_CHECK_DRIVER
+ static const SQLUSMALLINT reqFunc[] = {
+ SQL_API_SQLDESCRIBECOL, SQL_API_SQLGETDATA, SQL_API_SQLCOLUMNS,
+ SQL_API_SQLGETSTMTATTR, SQL_API_SQLGETDIAGREC, SQL_API_SQLEXECDIRECT,
+ SQL_API_SQLGETINFO, SQL_API_SQLTABLES, 0
+ };
+
+ // these functions are optional
+ static const SQLUSMALLINT optFunc[] = {
+ SQL_API_SQLNUMRESULTCOLS, SQL_API_SQLROWCOUNT, 0
+ };
+
+ SQLRETURN r;
+ SQLUSMALLINT sup;
+
+ int i;
+ // check the required functions
+ for (i = 0; reqFunc[i] != 0; ++i) {
+
+ r = SQLGetFunctions(hDbc, reqFunc[i], &sup);
+
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QODBCDriver::checkDriver: Cannot get list of supported functions"), this);
+ return false;
+ }
+ if (sup == SQL_FALSE) {
+ qWarning () << "QODBCDriver::open: Warning - Driver doesn't support all needed functionality (" << reqFunc[i] <<
+ ").\nPlease look at the Qt SQL Module Driver documentation for more information.";
+ return false;
+ }
+ }
+
+ // these functions are optional and just generate a warning
+ for (i = 0; optFunc[i] != 0; ++i) {
+
+ r = SQLGetFunctions(hDbc, optFunc[i], &sup);
+
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QODBCDriver::checkDriver: Cannot get list of supported functions"), this);
+ return false;
+ }
+ if (sup == SQL_FALSE) {
+ qWarning() << "QODBCDriver::checkDriver: Warning - Driver doesn't support some non-critical functions (" << optFunc[i] << ')';
+ return true;
+ }
+ }
+#endif //ODBC_CHECK_DRIVER
+
+ return true;
+}
+
+void QODBCDriverPrivate::checkSchemaUsage()
+{
+ SQLRETURN r;
+ SQLUINTEGER val;
+
+ r = SQLGetInfo(hDbc,
+ SQL_SCHEMA_USAGE,
+ (SQLPOINTER) &val,
+ sizeof(val),
+ NULL);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ useSchema = (val != 0);
+}
+
+void QODBCDriverPrivate::checkDBMS()
+{
+ SQLRETURN r;
+ QVarLengthArray<SQLTCHAR> serverString(200);
+ SQLSMALLINT t;
+ memset(serverString.data(), 0, serverString.size() * sizeof(SQLTCHAR));
+
+ r = SQLGetInfo(hDbc,
+ SQL_DBMS_NAME,
+ serverString.data(),
+ SQLSMALLINT(serverString.size() * sizeof(SQLTCHAR)),
+ &t);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ const QString serverType = fromSQLTCHAR(serverString, t / sizeof(SQLTCHAR));
+ if (serverType.contains(QLatin1String("PostgreSQL"), Qt::CaseInsensitive))
+ dbmsType = QSqlDriver::PostgreSQL;
+ else if (serverType.contains(QLatin1String("Oracle"), Qt::CaseInsensitive))
+ dbmsType = QSqlDriver::Oracle;
+ else if (serverType.contains(QLatin1String("MySql"), Qt::CaseInsensitive))
+ dbmsType = QSqlDriver::MySqlServer;
+ else if (serverType.contains(QLatin1String("Microsoft SQL Server"), Qt::CaseInsensitive))
+ dbmsType = QSqlDriver::MSSqlServer;
+ else if (serverType.contains(QLatin1String("Sybase"), Qt::CaseInsensitive))
+ dbmsType = QSqlDriver::Sybase;
+ }
+ r = SQLGetInfo(hDbc,
+ SQL_DRIVER_NAME,
+ serverString.data(),
+ SQLSMALLINT(serverString.size() * sizeof(SQLTCHAR)),
+ &t);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ const QString serverType = fromSQLTCHAR(serverString, t / sizeof(SQLTCHAR));
+ isFreeTDSDriver = serverType.contains(QLatin1String("tdsodbc"), Qt::CaseInsensitive);
+ unicode = unicode && !isFreeTDSDriver;
+ }
+}
+
+void QODBCDriverPrivate::checkHasSQLFetchScroll()
+{
+ SQLUSMALLINT sup;
+ SQLRETURN r = SQLGetFunctions(hDbc, SQL_API_SQLFETCHSCROLL, &sup);
+ if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || sup != SQL_TRUE) {
+ hasSQLFetchScroll = false;
+ qWarning("QODBCDriver::checkHasSQLFetchScroll: Warning - Driver doesn't support scrollable result sets, use forward only mode for queries");
+ }
+}
+
+void QODBCDriverPrivate::checkHasMultiResults()
+{
+ QVarLengthArray<SQLTCHAR> driverResponse(2);
+ SQLSMALLINT length;
+ SQLRETURN r = SQLGetInfo(hDbc,
+ SQL_MULT_RESULT_SETS,
+ driverResponse.data(),
+ SQLSMALLINT(driverResponse.size() * sizeof(SQLTCHAR)),
+ &length);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ hasMultiResultSets = fromSQLTCHAR(driverResponse, length/sizeof(SQLTCHAR)).startsWith(QLatin1Char('Y'));
+}
+
+void QODBCDriverPrivate::checkDateTimePrecision()
+{
+ SQLINTEGER columnSize;
+ SQLHANDLE hStmt;
+
+ SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt);
+ if (r != SQL_SUCCESS) {
+ return;
+ }
+
+ r = SQLGetTypeInfo(hStmt, SQL_TIMESTAMP);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ r = SQLFetch(hStmt);
+ if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO )
+ {
+ if (SQLGetData(hStmt, 3, SQL_INTEGER, &columnSize, sizeof(columnSize), 0) == SQL_SUCCESS) {
+ datetime_precision = (int)columnSize;
+ }
+ }
+ }
+ SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
+}
+
+QSqlResult *QODBCDriver::createResult() const
+{
+ return new QODBCResult(this);
+}
+
+bool QODBCDriver::beginTransaction()
+{
+ Q_D(QODBCDriver);
+ if (!isOpen()) {
+ qWarning("QODBCDriver::beginTransaction: Database not open");
+ return false;
+ }
+ SQLUINTEGER ac(SQL_AUTOCOMMIT_OFF);
+ SQLRETURN r = SQLSetConnectAttr(d->hDbc,
+ SQL_ATTR_AUTOCOMMIT,
+ (SQLPOINTER)size_t(ac),
+ sizeof(ac));
+ if (r != SQL_SUCCESS) {
+ setLastError(qMakeError(tr("Unable to disable autocommit"),
+ QSqlError::TransactionError, d));
+ return false;
+ }
+ return true;
+}
+
+bool QODBCDriver::commitTransaction()
+{
+ Q_D(QODBCDriver);
+ if (!isOpen()) {
+ qWarning("QODBCDriver::commitTransaction: Database not open");
+ return false;
+ }
+ SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
+ d->hDbc,
+ SQL_COMMIT);
+ if (r != SQL_SUCCESS) {
+ setLastError(qMakeError(tr("Unable to commit transaction"),
+ QSqlError::TransactionError, d));
+ return false;
+ }
+ return endTrans();
+}
+
+bool QODBCDriver::rollbackTransaction()
+{
+ Q_D(QODBCDriver);
+ if (!isOpen()) {
+ qWarning("QODBCDriver::rollbackTransaction: Database not open");
+ return false;
+ }
+ SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
+ d->hDbc,
+ SQL_ROLLBACK);
+ if (r != SQL_SUCCESS) {
+ setLastError(qMakeError(tr("Unable to rollback transaction"),
+ QSqlError::TransactionError, d));
+ return false;
+ }
+ return endTrans();
+}
+
+bool QODBCDriver::endTrans()
+{
+ Q_D(QODBCDriver);
+ SQLUINTEGER ac(SQL_AUTOCOMMIT_ON);
+ SQLRETURN r = SQLSetConnectAttr(d->hDbc,
+ SQL_ATTR_AUTOCOMMIT,
+ (SQLPOINTER)size_t(ac),
+ sizeof(ac));
+ if (r != SQL_SUCCESS) {
+ setLastError(qMakeError(tr("Unable to enable autocommit"), QSqlError::TransactionError, d));
+ return false;
+ }
+ return true;
+}
+
+QStringList QODBCDriver::tables(QSql::TableType type) const
+{
+ Q_D(const QODBCDriver);
+ QStringList tl;
+ if (!isOpen())
+ return tl;
+ SQLHANDLE hStmt;
+
+ SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
+ d->hDbc,
+ &hStmt);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QODBCDriver::tables: Unable to allocate handle"), d);
+ return tl;
+ }
+ r = SQLSetStmtAttr(hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+ QStringList tableType;
+ if (type & QSql::Tables)
+ tableType += QLatin1String("TABLE");
+ if (type & QSql::Views)
+ tableType += QLatin1String("VIEW");
+ if (type & QSql::SystemTables)
+ tableType += QLatin1String("SYSTEM TABLE");
+ if (tableType.isEmpty())
+ return tl;
+
+ QString joinedTableTypeString = tableType.join(QLatin1Char(','));
+
+ r = SQLTables(hStmt,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ toSQLTCHAR(joinedTableTypeString).data(),
+ joinedTableTypeString.length() /* characters, not bytes */);
+
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
+
+ if (d->hasSQLFetchScroll)
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ else
+ r = SQLFetch(hStmt);
+
+ if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
+ qWarning() << "QODBCDriver::tables failed to retrieve table/view list: (" << r << "," << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ")";
+ return QStringList();
+ }
+
+ while (r == SQL_SUCCESS) {
+ QString fieldVal = qGetStringData(hStmt, 2, -1, false);
+ tl.append(fieldVal);
+
+ if (d->hasSQLFetchScroll)
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ else
+ r = SQLFetch(hStmt);
+ }
+
+ r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
+ if (r!= SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle") + QString::number(r), d);
+ return tl;
+}
+
+QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const
+{
+ Q_D(const QODBCDriver);
+ QSqlIndex index(tablename);
+ if (!isOpen())
+ return index;
+ bool usingSpecialColumns = false;
+ QSqlRecord rec = record(tablename);
+
+ SQLHANDLE hStmt;
+ SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
+ d->hDbc,
+ &hStmt);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to list primary key"), d);
+ return index;
+ }
+ QString catalog, schema, table;
+ const_cast<QODBCDriverPrivate*>(d)->splitTableQualifier(tablename, catalog, schema, table);
+
+ if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
+ catalog = stripDelimiters(catalog, QSqlDriver::TableName);
+ else
+ catalog = d->adjustCase(catalog);
+
+ if (isIdentifierEscaped(schema, QSqlDriver::TableName))
+ schema = stripDelimiters(schema, QSqlDriver::TableName);
+ else
+ schema = d->adjustCase(schema);
+
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = d->adjustCase(table);
+
+ r = SQLSetStmtAttr(hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+ r = SQLPrimaryKeys(hStmt,
+ catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
+ catalog.length(),
+ schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
+ schema.length(),
+ toSQLTCHAR(table).data(),
+ table.length() /* in characters, not in bytes */);
+
+ // if the SQLPrimaryKeys() call does not succeed (e.g the driver
+ // does not support it) - try an alternative method to get hold of
+ // the primary index (e.g MS Access and FoxPro)
+ if (r != SQL_SUCCESS) {
+ r = SQLSpecialColumns(hStmt,
+ SQL_BEST_ROWID,
+ catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
+ catalog.length(),
+ schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
+ schema.length(),
+ toSQLTCHAR(table).data(),
+ table.length(),
+ SQL_SCOPE_CURROW,
+ SQL_NULLABLE);
+
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to execute primary key list"), d);
+ } else {
+ usingSpecialColumns = true;
+ }
+ }
+
+ if (d->hasSQLFetchScroll)
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ else
+ r = SQLFetch(hStmt);
+
+ int fakeId = 0;
+ QString cName, idxName;
+ // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
+ while (r == SQL_SUCCESS) {
+ if (usingSpecialColumns) {
+ cName = qGetStringData(hStmt, 1, -1, d->unicode); // column name
+ idxName = QString::number(fakeId++); // invent a fake index name
+ } else {
+ cName = qGetStringData(hStmt, 3, -1, d->unicode); // column name
+ idxName = qGetStringData(hStmt, 5, -1, d->unicode); // pk index name
+ }
+ index.append(rec.field(cName));
+ index.setName(idxName);
+
+ if (d->hasSQLFetchScroll)
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ else
+ r = SQLFetch(hStmt);
+
+ }
+ r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
+ if (r!= SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle") + QString::number(r), d);
+ return index;
+}
+
+QSqlRecord QODBCDriver::record(const QString& tablename) const
+{
+ Q_D(const QODBCDriver);
+ QSqlRecord fil;
+ if (!isOpen())
+ return fil;
+
+ SQLHANDLE hStmt;
+ QString catalog, schema, table;
+ const_cast<QODBCDriverPrivate*>(d)->splitTableQualifier(tablename, catalog, schema, table);
+
+ if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
+ catalog = stripDelimiters(catalog, QSqlDriver::TableName);
+ else
+ catalog = d->adjustCase(catalog);
+
+ if (isIdentifierEscaped(schema, QSqlDriver::TableName))
+ schema = stripDelimiters(schema, QSqlDriver::TableName);
+ else
+ schema = d->adjustCase(schema);
+
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = d->adjustCase(table);
+
+ SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
+ d->hDbc,
+ &hStmt);
+ if (r != SQL_SUCCESS) {
+ qSqlWarning(QLatin1String("QODBCDriver::record: Unable to allocate handle"), d);
+ return fil;
+ }
+ r = SQLSetStmtAttr(hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+ r = SQLColumns(hStmt,
+ catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
+ catalog.length(),
+ schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
+ schema.length(),
+ toSQLTCHAR(table).data(),
+ table.length(),
+ NULL,
+ 0);
+ if (r != SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QODBCDriver::record: Unable to execute column list"), d);
+
+ if (d->hasSQLFetchScroll)
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ else
+ r = SQLFetch(hStmt);
+
+ // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
+ while (r == SQL_SUCCESS) {
+
+ fil.append(qMakeFieldInfo(hStmt, d));
+
+ if (d->hasSQLFetchScroll)
+ r = SQLFetchScroll(hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ else
+ r = SQLFetch(hStmt);
+ }
+
+ r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
+ if (r!= SQL_SUCCESS)
+ qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ") + QString::number(r), d);
+
+ return fil;
+}
+
+QString QODBCDriver::formatValue(const QSqlField &field,
+ bool trimStrings) const
+{
+ QString r;
+ if (field.isNull()) {
+ r = QLatin1String("NULL");
+ } else if (field.type() == QVariant::DateTime) {
+ // Use an escape sequence for the datetime fields
+ if (field.value().toDateTime().isValid()){
+ QDate dt = field.value().toDateTime().date();
+ QTime tm = field.value().toDateTime().time();
+ // Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10
+ r = QLatin1String("{ ts '") +
+ QString::number(dt.year()) + QLatin1Char('-') +
+ QString::number(dt.month()).rightJustified(2, QLatin1Char('0'), true) +
+ QLatin1Char('-') +
+ QString::number(dt.day()).rightJustified(2, QLatin1Char('0'), true) +
+ QLatin1Char(' ') +
+ tm.toString() +
+ QLatin1String("' }");
+ } else
+ r = QLatin1String("NULL");
+ } else if (field.type() == QVariant::ByteArray) {
+ QByteArray ba = field.value().toByteArray();
+ QString res;
+ static const char hexchars[] = "0123456789abcdef";
+ for (int i = 0; i < ba.size(); ++i) {
+ uchar s = (uchar) ba[i];
+ res += QLatin1Char(hexchars[s >> 4]);
+ res += QLatin1Char(hexchars[s & 0x0f]);
+ }
+ r = QLatin1String("0x") + res;
+ } else {
+ r = QSqlDriver::formatValue(field, trimStrings);
+ }
+ return r;
+}
+
+QVariant QODBCDriver::handle() const
+{
+ Q_D(const QODBCDriver);
+ return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hDbc);
+}
+
+QString QODBCDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
+{
+ Q_D(const QODBCDriver);
+ QChar quote = const_cast<QODBCDriverPrivate*>(d)->quoteChar();
+ QString res = identifier;
+ if(!identifier.isEmpty() && !identifier.startsWith(quote) && !identifier.endsWith(quote) ) {
+ res.replace(quote, QString(quote)+QString(quote));
+ res.prepend(quote).append(quote);
+ res.replace(QLatin1Char('.'), QString(quote)+QLatin1Char('.')+QString(quote));
+ }
+ return res;
+}
+
+bool QODBCDriver::isIdentifierEscaped(const QString &identifier, IdentifierType) const
+{
+ Q_D(const QODBCDriver);
+ QChar quote = const_cast<QODBCDriverPrivate*>(d)->quoteChar();
+ return identifier.size() > 2
+ && identifier.startsWith(quote) //left delimited
+ && identifier.endsWith(quote); //right delimited
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc_p.h b/src/plugins/sqldrivers/odbc/qsql_odbc_p.h
new file mode 100644
index 0000000000..f4ce8bc243
--- /dev/null
+++ b/src/plugins/sqldrivers/odbc/qsql_odbc_p.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSQL_ODBC_H
+#define QSQL_ODBC_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 <QtSql/qsqldriver.h>
+
+#if defined (Q_OS_WIN32)
+#include <QtCore/qt_windows.h>
+#endif
+
+#ifdef QT_PLUGIN
+#define Q_EXPORT_SQLDRIVER_ODBC
+#else
+#define Q_EXPORT_SQLDRIVER_ODBC Q_SQL_EXPORT
+#endif
+
+#ifdef Q_OS_UNIX
+#define HAVE_LONG_LONG 1 // force UnixODBC NOT to fall back to a struct for BIGINTs
+#endif
+
+#if defined(Q_CC_BOR)
+// workaround for Borland to make sure that SQLBIGINT is defined
+# define _MSC_VER 900
+#endif
+#include <sql.h>
+#if defined(Q_CC_BOR)
+# undef _MSC_VER
+#endif
+
+#include <sqlext.h>
+
+QT_BEGIN_NAMESPACE
+
+class QODBCDriverPrivate;
+
+class Q_EXPORT_SQLDRIVER_ODBC QODBCDriver : public QSqlDriver
+{
+ Q_DECLARE_PRIVATE(QODBCDriver)
+ Q_OBJECT
+ friend class QODBCResultPrivate;
+
+public:
+ explicit QODBCDriver(QObject *parent=0);
+ QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject * parent=0);
+ virtual ~QODBCDriver();
+ bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
+ void close() Q_DECL_OVERRIDE;
+ QSqlResult *createResult() const Q_DECL_OVERRIDE;
+ QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
+ QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE;
+ QSqlIndex primaryIndex(const QString &tablename) const Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+ QString formatValue(const QSqlField &field,
+ bool trimStrings) const Q_DECL_OVERRIDE;
+ bool open(const QString &db,
+ const QString &user,
+ const QString &password,
+ const QString &host,
+ int port,
+ const QString &connOpts) Q_DECL_OVERRIDE;
+
+ QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
+
+ bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
+
+protected:
+ bool beginTransaction() Q_DECL_OVERRIDE;
+ bool commitTransaction() Q_DECL_OVERRIDE;
+ bool rollbackTransaction() Q_DECL_OVERRIDE;
+
+private:
+ bool endTrans();
+ void cleanup();
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQL_ODBC_H
diff --git a/src/plugins/sqldrivers/psql/main.cpp b/src/plugins/sqldrivers/psql/main.cpp
index eae1c1c554..7657fcbfdf 100644
--- a/src/plugins/sqldrivers/psql/main.cpp
+++ b/src/plugins/sqldrivers/psql/main.cpp
@@ -39,7 +39,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/psql/qsql_psql_p.h"
+#include "qsql_psql_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/psql/psql.pro b/src/plugins/sqldrivers/psql/psql.pro
index 0fabe0e616..4a05266120 100644
--- a/src/plugins/sqldrivers/psql/psql.pro
+++ b/src/plugins/sqldrivers/psql/psql.pro
@@ -1,8 +1,17 @@
TARGET = qsqlpsql
-SOURCES = main.cpp
+HEADERS += $$PWD/qsql_psql_p.h
+SOURCES += $$PWD/qsql_psql.cpp $$PWD/main.cpp
+
+unix|mingw {
+ LIBS += $$QMAKE_LIBS_PSQL
+ !contains(LIBS, .*pq.*):LIBS += -lpq
+ QMAKE_CXXFLAGS *= $$QMAKE_CFLAGS_PSQL
+} else {
+ !contains(LIBS, .*pq.*):LIBS += -llibpq -lws2_32 -ladvapi32
+}
+
OTHER_FILES += psql.json
-include(../../../sql/drivers/psql/qsql_psql.pri)
PLUGIN_CLASS_NAME = QPSQLDriverPlugin
include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp
new file mode 100644
index 0000000000..fcf75af298
--- /dev/null
+++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp
@@ -0,0 +1,1508 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsql_psql_p.h"
+
+#include <qcoreapplication.h>
+#include <qvariant.h>
+#include <qdatetime.h>
+#include <qregexp.h>
+#include <qsqlerror.h>
+#include <qsqlfield.h>
+#include <qsqlindex.h>
+#include <qsqlrecord.h>
+#include <qsqlquery.h>
+#include <qsocketnotifier.h>
+#include <qstringlist.h>
+#include <qmutex.h>
+#include <QtSql/private/qsqlresult_p.h>
+#include <QtSql/private/qsqldriver_p.h>
+
+#include <libpq-fe.h>
+#include <pg_config.h>
+
+#include <stdlib.h>
+#include <math.h>
+// below code taken from an example at http://www.gnu.org/software/hello/manual/autoconf/Function-Portability.html
+#ifndef isnan
+ # define isnan(x) \
+ (sizeof (x) == sizeof (long double) ? isnan_ld (x) \
+ : sizeof (x) == sizeof (double) ? isnan_d (x) \
+ : isnan_f (x))
+ static inline int isnan_f (float x) { return x != x; }
+ static inline int isnan_d (double x) { return x != x; }
+ static inline int isnan_ld (long double x) { return x != x; }
+#endif
+
+#ifndef isinf
+ # define isinf(x) \
+ (sizeof (x) == sizeof (long double) ? isinf_ld (x) \
+ : sizeof (x) == sizeof (double) ? isinf_d (x) \
+ : isinf_f (x))
+ static inline int isinf_f (float x) { return isnan (x - x); }
+ static inline int isinf_d (double x) { return isnan (x - x); }
+ static inline int isinf_ld (long double x) { return isnan (x - x); }
+#endif
+
+
+// workaround for postgres defining their OIDs in a private header file
+#define QBOOLOID 16
+#define QINT8OID 20
+#define QINT2OID 21
+#define QINT4OID 23
+#define QNUMERICOID 1700
+#define QFLOAT4OID 700
+#define QFLOAT8OID 701
+#define QABSTIMEOID 702
+#define QRELTIMEOID 703
+#define QDATEOID 1082
+#define QTIMEOID 1083
+#define QTIMETZOID 1266
+#define QTIMESTAMPOID 1114
+#define QTIMESTAMPTZOID 1184
+#define QOIDOID 2278
+#define QBYTEAOID 17
+#define QREGPROCOID 24
+#define QXIDOID 28
+#define QCIDOID 29
+
+#define QBITOID 1560
+#define QVARBITOID 1562
+
+#define VARHDRSZ 4
+
+/* This is a compile time switch - if PQfreemem is declared, the compiler will use that one,
+ otherwise it'll run in this template */
+template <typename T>
+inline void PQfreemem(T *t, int = 0) { free(t); }
+
+Q_DECLARE_OPAQUE_POINTER(PGconn*)
+Q_DECLARE_METATYPE(PGconn*)
+
+Q_DECLARE_OPAQUE_POINTER(PGresult*)
+Q_DECLARE_METATYPE(PGresult*)
+
+QT_BEGIN_NAMESPACE
+
+inline void qPQfreemem(void *buffer)
+{
+ PQfreemem(buffer);
+}
+
+class QPSQLResultPrivate;
+
+class QPSQLResult: public QSqlResult
+{
+ Q_DECLARE_PRIVATE(QPSQLResult)
+
+public:
+ QPSQLResult(const QPSQLDriver *db);
+ ~QPSQLResult();
+
+ QVariant handle() const Q_DECL_OVERRIDE;
+ void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
+
+protected:
+ void cleanup();
+ bool fetch(int i) Q_DECL_OVERRIDE;
+ bool fetchFirst() Q_DECL_OVERRIDE;
+ bool fetchLast() Q_DECL_OVERRIDE;
+ QVariant data(int i) Q_DECL_OVERRIDE;
+ bool isNull(int field) Q_DECL_OVERRIDE;
+ bool reset (const QString &query) Q_DECL_OVERRIDE;
+ int size() Q_DECL_OVERRIDE;
+ int numRowsAffected() Q_DECL_OVERRIDE;
+ QSqlRecord record() const Q_DECL_OVERRIDE;
+ QVariant lastInsertId() const Q_DECL_OVERRIDE;
+ bool prepare(const QString &query) Q_DECL_OVERRIDE;
+ bool exec() Q_DECL_OVERRIDE;
+};
+
+class QPSQLDriverPrivate : public QSqlDriverPrivate
+{
+ Q_DECLARE_PUBLIC(QPSQLDriver)
+public:
+ QPSQLDriverPrivate() : QSqlDriverPrivate(),
+ connection(0),
+ isUtf8(false),
+ pro(QPSQLDriver::Version6),
+ sn(0),
+ pendingNotifyCheck(false),
+ hasBackslashEscape(false)
+ { dbmsType = QSqlDriver::PostgreSQL; }
+
+ PGconn *connection;
+ bool isUtf8;
+ QPSQLDriver::Protocol pro;
+ QSocketNotifier *sn;
+ QStringList seid;
+ mutable bool pendingNotifyCheck;
+ bool hasBackslashEscape;
+
+ void appendTables(QStringList &tl, QSqlQuery &t, QChar type);
+ PGresult * exec(const char * stmt) const;
+ PGresult * exec(const QString & stmt) const;
+ QPSQLDriver::Protocol getPSQLVersion();
+ bool setEncodingUtf8();
+ void setDatestyle();
+ void detectBackslashEscape();
+};
+
+void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type)
+{
+ QString query;
+ if (pro >= QPSQLDriver::Version73) {
+ query = QString::fromLatin1("select pg_class.relname, pg_namespace.nspname from pg_class "
+ "left join pg_namespace on (pg_class.relnamespace = pg_namespace.oid) "
+ "where (pg_class.relkind = '%1') and (pg_class.relname !~ '^Inv') "
+ "and (pg_class.relname !~ '^pg_') "
+ "and (pg_namespace.nspname != 'information_schema') ").arg(type);
+ } else {
+ query = QString::fromLatin1("select relname, null from pg_class where (relkind = '%1') "
+ "and (relname !~ '^Inv') "
+ "and (relname !~ '^pg_') ").arg(type);
+ }
+ t.exec(query);
+ while (t.next()) {
+ QString schema = t.value(1).toString();
+ if (schema.isEmpty() || schema == QLatin1String("public"))
+ tl.append(t.value(0).toString());
+ else
+ tl.append(t.value(0).toString().prepend(QLatin1Char('.')).prepend(schema));
+ }
+}
+
+PGresult * QPSQLDriverPrivate::exec(const char * stmt) const
+{
+ Q_Q(const QPSQLDriver);
+ PGresult *result = PQexec(connection, stmt);
+ if (seid.size() && !pendingNotifyCheck) {
+ pendingNotifyCheck = true;
+ QMetaObject::invokeMethod(const_cast<QPSQLDriver*>(q), "_q_handleNotification", Qt::QueuedConnection, Q_ARG(int,0));
+ }
+ return result;
+}
+
+PGresult * QPSQLDriverPrivate::exec(const QString & stmt) const
+{
+ return exec(isUtf8 ? stmt.toUtf8().constData() : stmt.toLocal8Bit().constData());
+}
+
+class QPSQLResultPrivate : public QSqlResultPrivate
+{
+ Q_DECLARE_PUBLIC(QPSQLResult)
+public:
+ Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver);
+ QPSQLResultPrivate(QPSQLResult *q, const QPSQLDriver *drv)
+ : QSqlResultPrivate(q, drv),
+ result(0),
+ currentSize(-1),
+ preparedQueriesEnabled(false)
+ { }
+
+ QString fieldSerial(int i) const Q_DECL_OVERRIDE { return QLatin1Char('$') + QString::number(i + 1); }
+ void deallocatePreparedStmt();
+
+ PGresult *result;
+ int currentSize;
+ bool preparedQueriesEnabled;
+ QString preparedStmtId;
+
+ bool processResults();
+};
+
+static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
+ const QPSQLDriverPrivate *p, PGresult* result = 0)
+{
+ const char *s = PQerrorMessage(p->connection);
+ QString msg = p->isUtf8 ? QString::fromUtf8(s) : QString::fromLocal8Bit(s);
+ QString errorCode;
+ if (result) {
+ errorCode = QString::fromLatin1(PQresultErrorField(result, PG_DIAG_SQLSTATE));
+ msg += QString::fromLatin1("(%1)").arg(errorCode);
+ }
+ return QSqlError(QLatin1String("QPSQL: ") + err, msg, type, errorCode);
+}
+
+bool QPSQLResultPrivate::processResults()
+{
+ Q_Q(QPSQLResult);
+ if (!result)
+ return false;
+
+ int status = PQresultStatus(result);
+ if (status == PGRES_TUPLES_OK) {
+ q->setSelect(true);
+ q->setActive(true);
+ currentSize = PQntuples(result);
+ return true;
+ } else if (status == PGRES_COMMAND_OK) {
+ q->setSelect(false);
+ q->setActive(true);
+ currentSize = -1;
+ return true;
+ }
+ q->setLastError(qMakeError(QCoreApplication::translate("QPSQLResult",
+ "Unable to create query"), QSqlError::StatementError, drv_d_func(), result));
+ return false;
+}
+
+static QVariant::Type qDecodePSQLType(int t)
+{
+ QVariant::Type type = QVariant::Invalid;
+ switch (t) {
+ case QBOOLOID:
+ type = QVariant::Bool;
+ break;
+ case QINT8OID:
+ type = QVariant::LongLong;
+ break;
+ case QINT2OID:
+ case QINT4OID:
+ case QOIDOID:
+ case QREGPROCOID:
+ case QXIDOID:
+ case QCIDOID:
+ type = QVariant::Int;
+ break;
+ case QNUMERICOID:
+ case QFLOAT4OID:
+ case QFLOAT8OID:
+ type = QVariant::Double;
+ break;
+ case QABSTIMEOID:
+ case QRELTIMEOID:
+ case QDATEOID:
+ type = QVariant::Date;
+ break;
+ case QTIMEOID:
+ case QTIMETZOID:
+ type = QVariant::Time;
+ break;
+ case QTIMESTAMPOID:
+ case QTIMESTAMPTZOID:
+ type = QVariant::DateTime;
+ break;
+ case QBYTEAOID:
+ type = QVariant::ByteArray;
+ break;
+ default:
+ type = QVariant::String;
+ break;
+ }
+ return type;
+}
+
+void QPSQLResultPrivate::deallocatePreparedStmt()
+{
+ const QString stmt = QLatin1String("DEALLOCATE ") + preparedStmtId;
+ PGresult *result = drv_d_func()->exec(stmt);
+
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ qWarning("Unable to free statement: %s", PQerrorMessage(drv_d_func()->connection));
+ PQclear(result);
+ preparedStmtId.clear();
+}
+
+QPSQLResult::QPSQLResult(const QPSQLDriver* db)
+ : QSqlResult(*new QPSQLResultPrivate(this, db))
+{
+ Q_D(QPSQLResult);
+ d->preparedQueriesEnabled = db->hasFeature(QSqlDriver::PreparedQueries);
+}
+
+QPSQLResult::~QPSQLResult()
+{
+ Q_D(QPSQLResult);
+ cleanup();
+
+ if (d->preparedQueriesEnabled && !d->preparedStmtId.isNull())
+ d->deallocatePreparedStmt();
+}
+
+QVariant QPSQLResult::handle() const
+{
+ Q_D(const QPSQLResult);
+ return QVariant::fromValue(d->result);
+}
+
+void QPSQLResult::cleanup()
+{
+ Q_D(QPSQLResult);
+ if (d->result)
+ PQclear(d->result);
+ d->result = 0;
+ setAt(QSql::BeforeFirstRow);
+ d->currentSize = -1;
+ setActive(false);
+}
+
+bool QPSQLResult::fetch(int i)
+{
+ Q_D(const QPSQLResult);
+ if (!isActive())
+ return false;
+ if (i < 0)
+ return false;
+ if (i >= d->currentSize)
+ return false;
+ if (at() == i)
+ return true;
+ setAt(i);
+ return true;
+}
+
+bool QPSQLResult::fetchFirst()
+{
+ return fetch(0);
+}
+
+bool QPSQLResult::fetchLast()
+{
+ Q_D(const QPSQLResult);
+ return fetch(PQntuples(d->result) - 1);
+}
+
+QVariant QPSQLResult::data(int i)
+{
+ Q_D(const QPSQLResult);
+ if (i >= PQnfields(d->result)) {
+ qWarning("QPSQLResult::data: column %d out of range", i);
+ return QVariant();
+ }
+ int ptype = PQftype(d->result, i);
+ QVariant::Type type = qDecodePSQLType(ptype);
+ const char *val = PQgetvalue(d->result, at(), i);
+ if (PQgetisnull(d->result, at(), i))
+ return QVariant(type);
+ switch (type) {
+ case QVariant::Bool:
+ return QVariant((bool)(val[0] == 't'));
+ case QVariant::String:
+ return d->drv_d_func()->isUtf8 ? QString::fromUtf8(val) : QString::fromLatin1(val);
+ case QVariant::LongLong:
+ if (val[0] == '-')
+ return QString::fromLatin1(val).toLongLong();
+ else
+ return QString::fromLatin1(val).toULongLong();
+ case QVariant::Int:
+ return atoi(val);
+ case QVariant::Double:
+ if (ptype == QNUMERICOID) {
+ if (numericalPrecisionPolicy() != QSql::HighPrecision) {
+ QVariant retval;
+ bool convert;
+ double dbl=QString::fromLatin1(val).toDouble(&convert);
+ if (numericalPrecisionPolicy() == QSql::LowPrecisionInt64)
+ retval = (qlonglong)dbl;
+ else if (numericalPrecisionPolicy() == QSql::LowPrecisionInt32)
+ retval = (int)dbl;
+ else if (numericalPrecisionPolicy() == QSql::LowPrecisionDouble)
+ retval = dbl;
+ if (!convert)
+ return QVariant();
+ return retval;
+ }
+ return QString::fromLatin1(val);
+ }
+ return QString::fromLatin1(val).toDouble();
+ case QVariant::Date:
+ if (val[0] == '\0') {
+ return QVariant(QDate());
+ } else {
+#ifndef QT_NO_DATESTRING
+ return QVariant(QDate::fromString(QString::fromLatin1(val), Qt::ISODate));
+#else
+ return QVariant(QString::fromLatin1(val));
+#endif
+ }
+ case QVariant::Time: {
+ const QString str = QString::fromLatin1(val);
+#ifndef QT_NO_DATESTRING
+ if (str.isEmpty())
+ return QVariant(QTime());
+ else
+ return QVariant(QTime::fromString(str, Qt::ISODate));
+#else
+ return QVariant(str);
+#endif
+ }
+ case QVariant::DateTime: {
+ QString dtval = QString::fromLatin1(val);
+#ifndef QT_NO_DATESTRING
+ if (dtval.length() < 10) {
+ return QVariant(QDateTime());
+ } else {
+ QChar sign = dtval[dtval.size() - 3];
+ if (sign == QLatin1Char('-') || sign == QLatin1Char('+')) dtval += QLatin1String(":00");
+ return QVariant(QDateTime::fromString(dtval, Qt::ISODate).toLocalTime());
+ }
+#else
+ return QVariant(dtval);
+#endif
+ }
+ case QVariant::ByteArray: {
+ size_t len;
+ unsigned char *data = PQunescapeBytea((const unsigned char*)val, &len);
+ QByteArray ba(reinterpret_cast<const char *>(data), int(len));
+ qPQfreemem(data);
+ return QVariant(ba);
+ }
+ default:
+ case QVariant::Invalid:
+ qWarning("QPSQLResult::data: unknown data type");
+ }
+ return QVariant();
+}
+
+bool QPSQLResult::isNull(int field)
+{
+ Q_D(const QPSQLResult);
+ PQgetvalue(d->result, at(), field);
+ return PQgetisnull(d->result, at(), field);
+}
+
+bool QPSQLResult::reset (const QString& query)
+{
+ Q_D(QPSQLResult);
+ cleanup();
+ if (!driver())
+ return false;
+ if (!driver()->isOpen() || driver()->isOpenError())
+ return false;
+ d->result = d->drv_d_func()->exec(query);
+ return d->processResults();
+}
+
+int QPSQLResult::size()
+{
+ Q_D(const QPSQLResult);
+ return d->currentSize;
+}
+
+int QPSQLResult::numRowsAffected()
+{
+ Q_D(const QPSQLResult);
+ return QString::fromLatin1(PQcmdTuples(d->result)).toInt();
+}
+
+QVariant QPSQLResult::lastInsertId() const
+{
+ Q_D(const QPSQLResult);
+ if (d->drv_d_func()->pro >= QPSQLDriver::Version81) {
+ QSqlQuery qry(driver()->createResult());
+ // Most recent sequence value obtained from nextval
+ if (qry.exec(QLatin1String("SELECT lastval();")) && qry.next())
+ return qry.value(0);
+ } else if (isActive()) {
+ Oid id = PQoidValue(d->result);
+ if (id != InvalidOid)
+ return QVariant(id);
+ }
+ return QVariant();
+}
+
+QSqlRecord QPSQLResult::record() const
+{
+ Q_D(const QPSQLResult);
+ QSqlRecord info;
+ if (!isActive() || !isSelect())
+ return info;
+
+ int count = PQnfields(d->result);
+ for (int i = 0; i < count; ++i) {
+ QSqlField f;
+ if (d->drv_d_func()->isUtf8)
+ f.setName(QString::fromUtf8(PQfname(d->result, i)));
+ else
+ f.setName(QString::fromLocal8Bit(PQfname(d->result, i)));
+ int ptype = PQftype(d->result, i);
+ f.setType(qDecodePSQLType(ptype));
+ int len = PQfsize(d->result, i);
+ int precision = PQfmod(d->result, i);
+
+ switch (ptype) {
+ case QTIMESTAMPOID:
+ case QTIMESTAMPTZOID:
+ precision = 3;
+ break;
+
+ case QNUMERICOID:
+ if (precision != -1) {
+ len = (precision >> 16);
+ precision = ((precision - VARHDRSZ) & 0xffff);
+ }
+ break;
+ case QBITOID:
+ case QVARBITOID:
+ len = precision;
+ precision = -1;
+ break;
+ default:
+ if (len == -1 && precision >= VARHDRSZ) {
+ len = precision - VARHDRSZ;
+ precision = -1;
+ }
+ }
+
+ f.setLength(len);
+ f.setPrecision(precision);
+ f.setSqlType(ptype);
+ info.append(f);
+ }
+ return info;
+}
+
+void QPSQLResult::virtual_hook(int id, void *data)
+{
+ Q_ASSERT(data);
+
+ QSqlResult::virtual_hook(id, data);
+}
+
+static QString qCreateParamString(const QVector<QVariant> &boundValues, const QSqlDriver *driver)
+{
+ if (boundValues.isEmpty())
+ return QString();
+
+ QString params;
+ QSqlField f;
+ for (int i = 0; i < boundValues.count(); ++i) {
+ const QVariant &val = boundValues.at(i);
+
+ f.setType(val.type());
+ if (val.isNull())
+ f.clear();
+ else
+ f.setValue(val);
+ if(!params.isNull())
+ params.append(QLatin1String(", "));
+ params.append(driver->formatValue(f));
+ }
+ return params;
+}
+
+Q_GLOBAL_STATIC(QMutex, qMutex)
+QString qMakePreparedStmtId()
+{
+ qMutex()->lock();
+ static unsigned int qPreparedStmtCount = 0;
+ QString id = QLatin1String("qpsqlpstmt_") + QString::number(++qPreparedStmtCount, 16);
+ qMutex()->unlock();
+ return id;
+}
+
+bool QPSQLResult::prepare(const QString &query)
+{
+ Q_D(QPSQLResult);
+ if (!d->preparedQueriesEnabled)
+ return QSqlResult::prepare(query);
+
+ cleanup();
+
+ if (!d->preparedStmtId.isEmpty())
+ d->deallocatePreparedStmt();
+
+ const QString stmtId = qMakePreparedStmtId();
+ const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(d->positionalToNamedBinding(query));
+
+ PGresult *result = d->drv_d_func()->exec(stmt);
+
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ setLastError(qMakeError(QCoreApplication::translate("QPSQLResult",
+ "Unable to prepare statement"), QSqlError::StatementError, d->drv_d_func(), result));
+ PQclear(result);
+ d->preparedStmtId.clear();
+ return false;
+ }
+
+ PQclear(result);
+ d->preparedStmtId = stmtId;
+ return true;
+}
+
+bool QPSQLResult::exec()
+{
+ Q_D(QPSQLResult);
+ if (!d->preparedQueriesEnabled)
+ return QSqlResult::exec();
+
+ cleanup();
+
+ QString stmt;
+ const QString params = qCreateParamString(boundValues(), driver());
+ if (params.isEmpty())
+ stmt = QString::fromLatin1("EXECUTE %1").arg(d->preparedStmtId);
+ else
+ stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId).arg(params);
+
+ d->result = d->drv_d_func()->exec(stmt);
+
+ return d->processResults();
+}
+
+///////////////////////////////////////////////////////////////////
+
+bool QPSQLDriverPrivate::setEncodingUtf8()
+{
+ PGresult* result = exec("SET CLIENT_ENCODING TO 'UNICODE'");
+ int status = PQresultStatus(result);
+ PQclear(result);
+ return status == PGRES_COMMAND_OK;
+}
+
+void QPSQLDriverPrivate::setDatestyle()
+{
+ PGresult* result = exec("SET DATESTYLE TO 'ISO'");
+ int status = PQresultStatus(result);
+ if (status != PGRES_COMMAND_OK)
+ qWarning("%s", PQerrorMessage(connection));
+ PQclear(result);
+}
+
+void QPSQLDriverPrivate::detectBackslashEscape()
+{
+ // standard_conforming_strings option introduced in 8.2
+ // http://www.postgresql.org/docs/8.2/static/runtime-config-compatible.html
+ if (pro < QPSQLDriver::Version82) {
+ hasBackslashEscape = true;
+ } else {
+ hasBackslashEscape = false;
+ PGresult* result = exec(QLatin1Literal("SELECT '\\\\' x"));
+ int status = PQresultStatus(result);
+ if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK)
+ if (QString::fromLatin1(PQgetvalue(result, 0, 0)) == QLatin1Literal("\\"))
+ hasBackslashEscape = true;
+ PQclear(result);
+ }
+}
+
+static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin)
+{
+ switch (vMaj) {
+ case 6:
+ return QPSQLDriver::Version6;
+ case 7:
+ {
+ switch (vMin) {
+ case 1:
+ return QPSQLDriver::Version71;
+ case 3:
+ return QPSQLDriver::Version73;
+ case 4:
+ return QPSQLDriver::Version74;
+ default:
+ return QPSQLDriver::Version7;
+ }
+ break;
+ }
+ case 8:
+ {
+ switch (vMin) {
+ case 1:
+ return QPSQLDriver::Version81;
+ case 2:
+ return QPSQLDriver::Version82;
+ case 3:
+ return QPSQLDriver::Version83;
+ case 4:
+ return QPSQLDriver::Version84;
+ default:
+ return QPSQLDriver::Version8;
+ }
+ break;
+ }
+ case 9:
+ return QPSQLDriver::Version9;
+ break;
+ default:
+ break;
+ }
+ return QPSQLDriver::VersionUnknown;
+}
+
+QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion()
+{
+ QPSQLDriver::Protocol serverVersion = QPSQLDriver::Version6;
+ PGresult* result = exec("select version()");
+ int status = PQresultStatus(result);
+ if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) {
+ QString val = QString::fromLatin1(PQgetvalue(result, 0, 0));
+
+ QRegExp rx(QLatin1String("(\\d+)\\.(\\d+)"));
+ rx.setMinimal(true); // enforce non-greedy RegExp
+
+ if (rx.indexIn(val) != -1) {
+ int vMaj = rx.cap(1).toInt();
+ int vMin = rx.cap(2).toInt();
+ serverVersion = qMakePSQLVersion(vMaj, vMin);
+#if defined(PG_MAJORVERSION)
+ if (rx.indexIn(QLatin1String(PG_MAJORVERSION)) != -1)
+#elif defined(PG_VERSION)
+ if (rx.indexIn(QLatin1String(PG_VERSION)) != -1)
+#else
+ if (0)
+#endif
+ {
+ vMaj = rx.cap(1).toInt();
+ vMin = rx.cap(2).toInt();
+ QPSQLDriver::Protocol clientVersion = qMakePSQLVersion(vMaj, vMin);
+
+ if (serverVersion >= QPSQLDriver::Version9 && clientVersion < QPSQLDriver::Version9) {
+ //Client version before QPSQLDriver::Version9 only supports escape mode for bytea type,
+ //but bytea format is set to hex by default in PSQL 9 and above. So need to force the
+ //server use the old escape mode when connects to the new server with old client library.
+ PQclear(result);
+ result = exec("SET bytea_output=escape; ");
+ status = PQresultStatus(result);
+ } else if (serverVersion == QPSQLDriver::VersionUnknown) {
+ serverVersion = clientVersion;
+ if (serverVersion != QPSQLDriver::VersionUnknown)
+ qWarning("The server version of this PostgreSQL is unknown, falling back to the client version.");
+ }
+ }
+ }
+ }
+ PQclear(result);
+
+ //keep the old behavior unchanged
+ if (serverVersion == QPSQLDriver::VersionUnknown)
+ serverVersion = QPSQLDriver::Version6;
+
+ if (serverVersion < QPSQLDriver::Version71) {
+ qWarning("This version of PostgreSQL is not supported and may not work.");
+ }
+
+ return serverVersion;
+}
+
+QPSQLDriver::QPSQLDriver(QObject *parent)
+ : QSqlDriver(*new QPSQLDriverPrivate, parent)
+{
+}
+
+QPSQLDriver::QPSQLDriver(PGconn *conn, QObject *parent)
+ : QSqlDriver(*new QPSQLDriverPrivate, parent)
+{
+ Q_D(QPSQLDriver);
+ d->connection = conn;
+ if (conn) {
+ d->pro = d->getPSQLVersion();
+ d->detectBackslashEscape();
+ setOpen(true);
+ setOpenError(false);
+ }
+}
+
+QPSQLDriver::~QPSQLDriver()
+{
+ Q_D(QPSQLDriver);
+ if (d->connection)
+ PQfinish(d->connection);
+}
+
+QVariant QPSQLDriver::handle() const
+{
+ Q_D(const QPSQLDriver);
+ return QVariant::fromValue(d->connection);
+}
+
+bool QPSQLDriver::hasFeature(DriverFeature f) const
+{
+ Q_D(const QPSQLDriver);
+ switch (f) {
+ case Transactions:
+ case QuerySize:
+ case LastInsertId:
+ case LowPrecisionNumbers:
+ case EventNotifications:
+ return true;
+ case PreparedQueries:
+ case PositionalPlaceholders:
+ return d->pro >= QPSQLDriver::Version82;
+ case BatchOperations:
+ case NamedPlaceholders:
+ case SimpleLocking:
+ case FinishQuery:
+ case MultipleResultSets:
+ case CancelQuery:
+ return false;
+ case BLOB:
+ return d->pro >= QPSQLDriver::Version71;
+ case Unicode:
+ return d->isUtf8;
+ }
+ return false;
+}
+
+/*
+ Quote a string for inclusion into the connection string
+ \ -> \\
+ ' -> \'
+ surround string by single quotes
+ */
+static QString qQuote(QString s)
+{
+ s.replace(QLatin1Char('\\'), QLatin1String("\\\\"));
+ s.replace(QLatin1Char('\''), QLatin1String("\\'"));
+ s.append(QLatin1Char('\'')).prepend(QLatin1Char('\''));
+ return s;
+}
+
+bool QPSQLDriver::open(const QString & db,
+ const QString & user,
+ const QString & password,
+ const QString & host,
+ int port,
+ const QString& connOpts)
+{
+ Q_D(QPSQLDriver);
+ if (isOpen())
+ close();
+ QString connectString;
+ if (!host.isEmpty())
+ connectString.append(QLatin1String("host=")).append(qQuote(host));
+ if (!db.isEmpty())
+ connectString.append(QLatin1String(" dbname=")).append(qQuote(db));
+ if (!user.isEmpty())
+ connectString.append(QLatin1String(" user=")).append(qQuote(user));
+ if (!password.isEmpty())
+ connectString.append(QLatin1String(" password=")).append(qQuote(password));
+ if (port != -1)
+ connectString.append(QLatin1String(" port=")).append(qQuote(QString::number(port)));
+
+ // add any connect options - the server will handle error detection
+ if (!connOpts.isEmpty()) {
+ QString opt = connOpts;
+ opt.replace(QLatin1Char(';'), QLatin1Char(' '), Qt::CaseInsensitive);
+ connectString.append(QLatin1Char(' ')).append(opt);
+ }
+
+ d->connection = PQconnectdb(connectString.toLocal8Bit().constData());
+ if (PQstatus(d->connection) == CONNECTION_BAD) {
+ setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
+ setOpenError(true);
+ PQfinish(d->connection);
+ d->connection = 0;
+ return false;
+ }
+
+ d->pro = d->getPSQLVersion();
+ d->detectBackslashEscape();
+ d->isUtf8 = d->setEncodingUtf8();
+ d->setDatestyle();
+
+ setOpen(true);
+ setOpenError(false);
+ return true;
+}
+
+void QPSQLDriver::close()
+{
+ Q_D(QPSQLDriver);
+ if (isOpen()) {
+
+ d->seid.clear();
+ if (d->sn) {
+ disconnect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int)));
+ delete d->sn;
+ d->sn = 0;
+ }
+
+ if (d->connection)
+ PQfinish(d->connection);
+ d->connection = 0;
+ setOpen(false);
+ setOpenError(false);
+ }
+}
+
+QSqlResult *QPSQLDriver::createResult() const
+{
+ return new QPSQLResult(this);
+}
+
+bool QPSQLDriver::beginTransaction()
+{
+ Q_D(const QPSQLDriver);
+ if (!isOpen()) {
+ qWarning("QPSQLDriver::beginTransaction: Database not open");
+ return false;
+ }
+ PGresult* res = d->exec("BEGIN");
+ if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
+ setLastError(qMakeError(tr("Could not begin transaction"),
+ QSqlError::TransactionError, d, res));
+ PQclear(res);
+ return false;
+ }
+ PQclear(res);
+ return true;
+}
+
+bool QPSQLDriver::commitTransaction()
+{
+ Q_D(QPSQLDriver);
+ if (!isOpen()) {
+ qWarning("QPSQLDriver::commitTransaction: Database not open");
+ return false;
+ }
+ PGresult* res = d->exec("COMMIT");
+
+ bool transaction_failed = false;
+
+ // XXX
+ // This hack is used to tell if the transaction has succeeded for the protocol versions of
+ // PostgreSQL below. For 7.x and other protocol versions we are left in the dark.
+ // This hack can dissapear once there is an API to query this sort of information.
+ if (d->pro == QPSQLDriver::Version8 ||
+ d->pro == QPSQLDriver::Version81 ||
+ d->pro == QPSQLDriver::Version82 ||
+ d->pro == QPSQLDriver::Version83 ||
+ d->pro == QPSQLDriver::Version84 ||
+ d->pro == QPSQLDriver::Version9) {
+ transaction_failed = qstrcmp(PQcmdStatus(res), "ROLLBACK") == 0;
+ }
+
+ if (!res || PQresultStatus(res) != PGRES_COMMAND_OK || transaction_failed) {
+ setLastError(qMakeError(tr("Could not commit transaction"),
+ QSqlError::TransactionError, d, res));
+ PQclear(res);
+ return false;
+ }
+ PQclear(res);
+ return true;
+}
+
+bool QPSQLDriver::rollbackTransaction()
+{
+ Q_D(QPSQLDriver);
+ if (!isOpen()) {
+ qWarning("QPSQLDriver::rollbackTransaction: Database not open");
+ return false;
+ }
+ PGresult* res = d->exec("ROLLBACK");
+ if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
+ setLastError(qMakeError(tr("Could not rollback transaction"),
+ QSqlError::TransactionError, d, res));
+ PQclear(res);
+ return false;
+ }
+ PQclear(res);
+ return true;
+}
+
+QStringList QPSQLDriver::tables(QSql::TableType type) const
+{
+ Q_D(const QPSQLDriver);
+ QStringList tl;
+ if (!isOpen())
+ return tl;
+ QSqlQuery t(createResult());
+ t.setForwardOnly(true);
+
+ if (type & QSql::Tables)
+ const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, QLatin1Char('r'));
+ if (type & QSql::Views)
+ const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, QLatin1Char('v'));
+ if (type & QSql::SystemTables) {
+ t.exec(QLatin1String("select relname from pg_class where (relkind = 'r') "
+ "and (relname like 'pg_%') "));
+ while (t.next())
+ tl.append(t.value(0).toString());
+ }
+
+ return tl;
+}
+
+static void qSplitTableName(QString &tablename, QString &schema)
+{
+ int dot = tablename.indexOf(QLatin1Char('.'));
+ if (dot == -1)
+ return;
+ schema = tablename.left(dot);
+ tablename = tablename.mid(dot + 1);
+}
+
+QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
+{
+ Q_D(const QPSQLDriver);
+ QSqlIndex idx(tablename);
+ if (!isOpen())
+ return idx;
+ QSqlQuery i(createResult());
+ QString stmt;
+
+ QString tbl = tablename;
+ QString schema;
+ qSplitTableName(tbl, schema);
+
+ if (isIdentifierEscaped(tbl, QSqlDriver::TableName))
+ tbl = stripDelimiters(tbl, QSqlDriver::TableName);
+ else
+ tbl = tbl.toLower();
+
+ if (isIdentifierEscaped(schema, QSqlDriver::TableName))
+ schema = stripDelimiters(schema, QSqlDriver::TableName);
+ else
+ schema = schema.toLower();
+
+ switch(d->pro) {
+ case QPSQLDriver::Version6:
+ stmt = QLatin1String("select pg_att1.attname, int(pg_att1.atttypid), pg_cl.relname "
+ "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind "
+ "where pg_cl.relname = '%1_pkey' "
+ "and pg_cl.oid = pg_ind.indexrelid "
+ "and pg_att2.attrelid = pg_ind.indexrelid "
+ "and pg_att1.attrelid = pg_ind.indrelid "
+ "and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] "
+ "order by pg_att2.attnum");
+ break;
+ case QPSQLDriver::Version7:
+ case QPSQLDriver::Version71:
+ stmt = QLatin1String("select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname "
+ "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind "
+ "where pg_cl.relname = '%1_pkey' "
+ "and pg_cl.oid = pg_ind.indexrelid "
+ "and pg_att2.attrelid = pg_ind.indexrelid "
+ "and pg_att1.attrelid = pg_ind.indrelid "
+ "and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] "
+ "order by pg_att2.attnum");
+ break;
+ case QPSQLDriver::Version73:
+ case QPSQLDriver::Version74:
+ case QPSQLDriver::Version8:
+ case QPSQLDriver::Version81:
+ case QPSQLDriver::Version82:
+ case QPSQLDriver::Version83:
+ case QPSQLDriver::Version84:
+ case QPSQLDriver::Version9:
+ stmt = QLatin1String("SELECT pg_attribute.attname, pg_attribute.atttypid::int, "
+ "pg_class.relname "
+ "FROM pg_attribute, pg_class "
+ "WHERE %1 pg_class.oid IN "
+ "(SELECT indexrelid FROM pg_index WHERE indisprimary = true AND indrelid IN "
+ " (SELECT oid FROM pg_class WHERE relname = '%2')) "
+ "AND pg_attribute.attrelid = pg_class.oid "
+ "AND pg_attribute.attisdropped = false "
+ "ORDER BY pg_attribute.attnum");
+ if (schema.isEmpty())
+ stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid) AND"));
+ else
+ stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from "
+ "pg_namespace where pg_namespace.nspname = '%1') AND ").arg(schema));
+ break;
+ case QPSQLDriver::VersionUnknown:
+ qFatal("PSQL version is unknown");
+ break;
+ }
+
+ i.exec(stmt.arg(tbl));
+ while (i.isActive() && i.next()) {
+ QSqlField f(i.value(0).toString(), qDecodePSQLType(i.value(1).toInt()));
+ idx.append(f);
+ idx.setName(i.value(2).toString());
+ }
+ return idx;
+}
+
+QSqlRecord QPSQLDriver::record(const QString& tablename) const
+{
+ Q_D(const QPSQLDriver);
+ QSqlRecord info;
+ if (!isOpen())
+ return info;
+
+ QString tbl = tablename;
+ QString schema;
+ qSplitTableName(tbl, schema);
+
+ if (isIdentifierEscaped(tbl, QSqlDriver::TableName))
+ tbl = stripDelimiters(tbl, QSqlDriver::TableName);
+ else
+ tbl = tbl.toLower();
+
+ if (isIdentifierEscaped(schema, QSqlDriver::TableName))
+ schema = stripDelimiters(schema, QSqlDriver::TableName);
+ else
+ schema = schema.toLower();
+
+ QString stmt;
+ switch(d->pro) {
+ case QPSQLDriver::Version6:
+ stmt = QLatin1String("select pg_attribute.attname, int(pg_attribute.atttypid), "
+ "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
+ "int(pg_attribute.attrelid), pg_attribute.attnum "
+ "from pg_class, pg_attribute "
+ "where pg_class.relname = '%1' "
+ "and pg_attribute.attnum > 0 "
+ "and pg_attribute.attrelid = pg_class.oid ");
+ break;
+ case QPSQLDriver::Version7:
+ stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
+ "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
+ "pg_attribute.attrelid::int, pg_attribute.attnum "
+ "from pg_class, pg_attribute "
+ "where pg_class.relname = '%1' "
+ "and pg_attribute.attnum > 0 "
+ "and pg_attribute.attrelid = pg_class.oid ");
+ break;
+ case QPSQLDriver::Version71:
+ stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
+ "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
+ "pg_attrdef.adsrc "
+ "from pg_class, pg_attribute "
+ "left join pg_attrdef on (pg_attrdef.adrelid = "
+ "pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) "
+ "where pg_class.relname = '%1' "
+ "and pg_attribute.attnum > 0 "
+ "and pg_attribute.attrelid = pg_class.oid "
+ "order by pg_attribute.attnum ");
+ break;
+ case QPSQLDriver::Version73:
+ case QPSQLDriver::Version74:
+ case QPSQLDriver::Version8:
+ case QPSQLDriver::Version81:
+ case QPSQLDriver::Version82:
+ case QPSQLDriver::Version83:
+ case QPSQLDriver::Version84:
+ case QPSQLDriver::Version9:
+ stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
+ "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
+ "pg_attrdef.adsrc "
+ "from pg_class, pg_attribute "
+ "left join pg_attrdef on (pg_attrdef.adrelid = "
+ "pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) "
+ "where %1 "
+ "and pg_class.relname = '%2' "
+ "and pg_attribute.attnum > 0 "
+ "and pg_attribute.attrelid = pg_class.oid "
+ "and pg_attribute.attisdropped = false "
+ "order by pg_attribute.attnum ");
+ if (schema.isEmpty())
+ stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid)"));
+ else
+ stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from "
+ "pg_namespace where pg_namespace.nspname = '%1')").arg(schema));
+ break;
+ case QPSQLDriver::VersionUnknown:
+ qFatal("PSQL version is unknown");
+ break;
+ }
+
+ QSqlQuery query(createResult());
+ query.exec(stmt.arg(tbl));
+ if (d->pro >= QPSQLDriver::Version71) {
+ while (query.next()) {
+ int len = query.value(3).toInt();
+ int precision = query.value(4).toInt();
+ // swap length and precision if length == -1
+ if (len == -1 && precision > -1) {
+ len = precision - 4;
+ precision = -1;
+ }
+ QString defVal = query.value(5).toString();
+ if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\''))
+ defVal = defVal.mid(1, defVal.length() - 2);
+ QSqlField f(query.value(0).toString(), qDecodePSQLType(query.value(1).toInt()));
+ f.setRequired(query.value(2).toBool());
+ f.setLength(len);
+ f.setPrecision(precision);
+ f.setDefaultValue(defVal);
+ f.setSqlType(query.value(1).toInt());
+ info.append(f);
+ }
+ } else {
+ // Postgres < 7.1 cannot handle outer joins
+ while (query.next()) {
+ QString defVal;
+ QString stmt2 = QLatin1String("select pg_attrdef.adsrc from pg_attrdef where "
+ "pg_attrdef.adrelid = %1 and pg_attrdef.adnum = %2 ");
+ QSqlQuery query2(createResult());
+ query2.exec(stmt2.arg(query.value(5).toInt()).arg(query.value(6).toInt()));
+ if (query2.isActive() && query2.next())
+ defVal = query2.value(0).toString();
+ if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\''))
+ defVal = defVal.mid(1, defVal.length() - 2);
+ int len = query.value(3).toInt();
+ int precision = query.value(4).toInt();
+ // swap length and precision if length == -1
+ if (len == -1 && precision > -1) {
+ len = precision - 4;
+ precision = -1;
+ }
+ QSqlField f(query.value(0).toString(), qDecodePSQLType(query.value(1).toInt()));
+ f.setRequired(query.value(2).toBool());
+ f.setLength(len);
+ f.setPrecision(precision);
+ f.setDefaultValue(defVal);
+ f.setSqlType(query.value(1).toInt());
+ info.append(f);
+ }
+ }
+
+ return info;
+}
+
+template <class FloatType>
+inline void assignSpecialPsqlFloatValue(FloatType val, QString *target)
+{
+ if (isnan(val)) {
+ *target = QLatin1String("'NaN'");
+ } else {
+ switch (isinf(val)) {
+ case 1:
+ *target = QLatin1String("'Infinity'");
+ break;
+ case -1:
+ *target = QLatin1String("'-Infinity'");
+ break;
+ }
+ }
+}
+
+QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
+{
+ Q_D(const QPSQLDriver);
+ QString r;
+ if (field.isNull()) {
+ r = QLatin1String("NULL");
+ } else {
+ switch (int(field.type())) {
+ case QVariant::DateTime:
+#ifndef QT_NO_DATESTRING
+ if (field.value().toDateTime().isValid()) {
+ // we force the value to be considered with a timezone information, and we force it to be UTC
+ // this is safe since postgresql stores only the UTC value and not the timezone offset (only used
+ // while parsing), so we have correct behavior in both case of with timezone and without tz
+ r = QLatin1String("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') + field.value().toDateTime().toUTC().toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz")) + QLatin1Char('Z') + QLatin1Char('\'');
+ } else {
+ r = QLatin1String("NULL");
+ }
+#else
+ r = QLatin1String("NULL");
+#endif // QT_NO_DATESTRING
+ break;
+ case QVariant::Time:
+#ifndef QT_NO_DATESTRING
+ if (field.value().toTime().isValid()) {
+ r = QLatin1Char('\'') + field.value().toTime().toString(QLatin1String("hh:mm:ss.zzz")) + QLatin1Char('\'');
+ } else
+#endif
+ {
+ r = QLatin1String("NULL");
+ }
+ break;
+ case QVariant::String:
+ r = QSqlDriver::formatValue(field, trimStrings);
+ if (d->hasBackslashEscape)
+ r.replace(QLatin1String("\\"), QLatin1String("\\\\"));
+ break;
+ case QVariant::Bool:
+ if (field.value().toBool())
+ r = QLatin1String("TRUE");
+ else
+ r = QLatin1String("FALSE");
+ break;
+ case QVariant::ByteArray: {
+ QByteArray ba(field.value().toByteArray());
+ size_t len;
+#if defined PG_VERSION_NUM && PG_VERSION_NUM-0 >= 80200
+ unsigned char *data = PQescapeByteaConn(d->connection, (const unsigned char*)ba.constData(), ba.size(), &len);
+#else
+ unsigned char *data = PQescapeBytea((const unsigned char*)ba.constData(), ba.size(), &len);
+#endif
+ r += QLatin1Char('\'');
+ r += QLatin1String((const char*)data);
+ r += QLatin1Char('\'');
+ qPQfreemem(data);
+ break;
+ }
+ case QMetaType::Float:
+ assignSpecialPsqlFloatValue(field.value().toFloat(), &r);
+ if (r.isEmpty())
+ r = QSqlDriver::formatValue(field, trimStrings);
+ break;
+ case QVariant::Double:
+ assignSpecialPsqlFloatValue(field.value().toDouble(), &r);
+ if (r.isEmpty())
+ r = QSqlDriver::formatValue(field, trimStrings);
+ break;
+ case QVariant::Uuid:
+ r = QLatin1Char('\'') + field.value().toString() + QLatin1Char('\'');
+ break;
+ default:
+ r = QSqlDriver::formatValue(field, trimStrings);
+ break;
+ }
+ }
+ return r;
+}
+
+QString QPSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
+{
+ QString res = identifier;
+ if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
+ res.replace(QLatin1Char('"'), QLatin1String("\"\""));
+ res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
+ res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ }
+ return res;
+}
+
+bool QPSQLDriver::isOpen() const
+{
+ Q_D(const QPSQLDriver);
+ return PQstatus(d->connection) == CONNECTION_OK;
+}
+
+QPSQLDriver::Protocol QPSQLDriver::protocol() const
+{
+ Q_D(const QPSQLDriver);
+ return d->pro;
+}
+
+bool QPSQLDriver::subscribeToNotification(const QString &name)
+{
+ Q_D(QPSQLDriver);
+ if (!isOpen()) {
+ qWarning("QPSQLDriver::subscribeToNotificationImplementation: database not open.");
+ return false;
+ }
+
+ if (d->seid.contains(name)) {
+ qWarning("QPSQLDriver::subscribeToNotificationImplementation: already subscribing to '%s'.",
+ qPrintable(name));
+ return false;
+ }
+
+ int socket = PQsocket(d->connection);
+ if (socket) {
+ // Add the name to the list of subscriptions here so that QSQLDriverPrivate::exec knows
+ // to check for notifications immediately after executing the LISTEN
+ d->seid << name;
+ QString query = QLatin1String("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
+ PGresult *result = d->exec(query);
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ setLastError(qMakeError(tr("Unable to subscribe"), QSqlError::StatementError, d, result));
+ PQclear(result);
+ return false;
+ }
+ PQclear(result);
+
+ if (!d->sn) {
+ d->sn = new QSocketNotifier(socket, QSocketNotifier::Read);
+ connect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int)));
+ }
+ } else {
+ qWarning("QPSQLDriver::subscribeToNotificationImplementation: PQsocket didn't return a valid socket to listen on");
+ return false;
+ }
+
+ return true;
+}
+
+bool QPSQLDriver::unsubscribeFromNotification(const QString &name)
+{
+ Q_D(QPSQLDriver);
+ if (!isOpen()) {
+ qWarning("QPSQLDriver::unsubscribeFromNotificationImplementation: database not open.");
+ return false;
+ }
+
+ if (!d->seid.contains(name)) {
+ qWarning("QPSQLDriver::unsubscribeFromNotificationImplementation: not subscribed to '%s'.",
+ qPrintable(name));
+ return false;
+ }
+
+ QString query = QLatin1String("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
+ PGresult *result = d->exec(query);
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ setLastError(qMakeError(tr("Unable to unsubscribe"), QSqlError::StatementError, d, result));
+ PQclear(result);
+ return false;
+ }
+ PQclear(result);
+
+ d->seid.removeAll(name);
+
+ if (d->seid.isEmpty()) {
+ disconnect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int)));
+ delete d->sn;
+ d->sn = 0;
+ }
+
+ return true;
+}
+
+QStringList QPSQLDriver::subscribedToNotifications() const
+{
+ Q_D(const QPSQLDriver);
+ return d->seid;
+}
+
+void QPSQLDriver::_q_handleNotification(int)
+{
+ Q_D(QPSQLDriver);
+ d->pendingNotifyCheck = false;
+ PQconsumeInput(d->connection);
+
+ PGnotify *notify = 0;
+ while((notify = PQnotifies(d->connection)) != 0) {
+ QString name(QLatin1String(notify->relname));
+ if (d->seid.contains(name)) {
+ QString payload;
+#if defined PG_VERSION_NUM && PG_VERSION_NUM-0 >= 70400
+ if (notify->extra)
+ payload = d->isUtf8 ? QString::fromUtf8(notify->extra) : QString::fromLatin1(notify->extra);
+#endif
+ emit notification(name);
+ QSqlDriver::NotificationSource source = (notify->be_pid == PQbackendPID(d->connection)) ? QSqlDriver::SelfSource : QSqlDriver::OtherSource;
+ emit notification(name, source, payload);
+ }
+ else
+ qWarning("QPSQLDriver: received notification for '%s' which isn't subscribed to.",
+ qPrintable(name));
+
+ qPQfreemem(notify);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/psql/qsql_psql_p.h b/src/plugins/sqldrivers/psql/qsql_psql_p.h
new file mode 100644
index 0000000000..8468b9af93
--- /dev/null
+++ b/src/plugins/sqldrivers/psql/qsql_psql_p.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSQL_PSQL_H
+#define QSQL_PSQL_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 <QtSql/qsqldriver.h>
+
+#ifdef QT_PLUGIN
+#define Q_EXPORT_SQLDRIVER_PSQL
+#else
+#define Q_EXPORT_SQLDRIVER_PSQL Q_SQL_EXPORT
+#endif
+
+typedef struct pg_conn PGconn;
+typedef struct pg_result PGresult;
+
+QT_BEGIN_NAMESPACE
+
+class QPSQLDriverPrivate;
+
+class Q_EXPORT_SQLDRIVER_PSQL QPSQLDriver : public QSqlDriver
+{
+ friend class QPSQLResultPrivate;
+ Q_DECLARE_PRIVATE(QPSQLDriver)
+ Q_OBJECT
+public:
+ enum Protocol {
+ VersionUnknown = -1,
+ Version6 = 6,
+ Version7 = 7,
+ Version71 = 8,
+ Version73 = 9,
+ Version74 = 10,
+ Version8 = 11,
+ Version81 = 12,
+ Version82 = 13,
+ Version83 = 14,
+ Version84 = 15,
+ Version9 = 16
+ };
+
+ explicit QPSQLDriver(QObject *parent=0);
+ explicit QPSQLDriver(PGconn *conn, QObject *parent=0);
+ ~QPSQLDriver();
+ bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
+ bool open(const QString & db,
+ const QString & user,
+ const QString & password,
+ const QString & host,
+ int port,
+ const QString& connOpts) Q_DECL_OVERRIDE;
+ bool isOpen() const Q_DECL_OVERRIDE;
+ void close() Q_DECL_OVERRIDE;
+ QSqlResult *createResult() const Q_DECL_OVERRIDE;
+ QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
+ QSqlIndex primaryIndex(const QString& tablename) const Q_DECL_OVERRIDE;
+ QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE;
+
+ Protocol protocol() const;
+ QVariant handle() const Q_DECL_OVERRIDE;
+
+ QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
+ QString formatValue(const QSqlField &field, bool trimStrings) const Q_DECL_OVERRIDE;
+
+ bool subscribeToNotification(const QString &name) Q_DECL_OVERRIDE;
+ bool unsubscribeFromNotification(const QString &name) Q_DECL_OVERRIDE;
+ QStringList subscribedToNotifications() const Q_DECL_OVERRIDE;
+
+protected:
+ bool beginTransaction() Q_DECL_OVERRIDE;
+ bool commitTransaction() Q_DECL_OVERRIDE;
+ bool rollbackTransaction() Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ void _q_handleNotification(int);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQL_PSQL_H
diff --git a/src/plugins/sqldrivers/sqldrivers.pro b/src/plugins/sqldrivers/sqldrivers.pro
index 39c58d4f2b..37dbd2394e 100644
--- a/src/plugins/sqldrivers/sqldrivers.pro
+++ b/src/plugins/sqldrivers/sqldrivers.pro
@@ -1,11 +1,11 @@
TEMPLATE = subdirs
-contains(sql-plugins, psql) : SUBDIRS += psql
-contains(sql-plugins, mysql) : SUBDIRS += mysql
-contains(sql-plugins, odbc) : SUBDIRS += odbc
-contains(sql-plugins, tds) : SUBDIRS += tds
-contains(sql-plugins, oci) : SUBDIRS += oci
-contains(sql-plugins, db2) : SUBDIRS += db2
-contains(sql-plugins, sqlite) : SUBDIRS += sqlite
-contains(sql-plugins, sqlite2) : SUBDIRS += sqlite2
-contains(sql-plugins, ibase) : SUBDIRS += ibase
+contains(sql-drivers, psql) : SUBDIRS += psql
+contains(sql-drivers, mysql) : SUBDIRS += mysql
+contains(sql-drivers, odbc) : SUBDIRS += odbc
+contains(sql-drivers, tds) : SUBDIRS += tds
+contains(sql-drivers, oci) : SUBDIRS += oci
+contains(sql-drivers, db2) : SUBDIRS += db2
+contains(sql-drivers, sqlite) : SUBDIRS += sqlite
+contains(sql-drivers, sqlite2) : SUBDIRS += sqlite2
+contains(sql-drivers, ibase) : SUBDIRS += ibase
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
new file mode 100644
index 0000000000..ef4ef2e93c
--- /dev/null
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
@@ -0,0 +1,903 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsql_sqlite_p.h"
+
+#include <qcoreapplication.h>
+#include <qdatetime.h>
+#include <qvariant.h>
+#include <qsqlerror.h>
+#include <qsqlfield.h>
+#include <qsqlindex.h>
+#include <qsqlquery.h>
+#include <QtSql/private/qsqlcachedresult_p.h>
+#include <QtSql/private/qsqldriver_p.h>
+#include <qstringlist.h>
+#include <qvector.h>
+#include <qdebug.h>
+
+#if defined Q_OS_WIN
+# include <qt_windows.h>
+#else
+# include <unistd.h>
+#endif
+
+#include <sqlite3.h>
+#include <functional>
+
+Q_DECLARE_OPAQUE_POINTER(sqlite3*)
+Q_DECLARE_METATYPE(sqlite3*)
+
+Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt*)
+Q_DECLARE_METATYPE(sqlite3_stmt*)
+
+QT_BEGIN_NAMESPACE
+
+static QString _q_escapeIdentifier(const QString &identifier)
+{
+ QString res = identifier;
+ if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) {
+ res.replace(QLatin1Char('"'), QLatin1String("\"\""));
+ res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
+ res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ }
+ return res;
+}
+
+static QVariant::Type qGetColumnType(const QString &tpName)
+{
+ const QString typeName = tpName.toLower();
+
+ if (typeName == QLatin1String("integer")
+ || typeName == QLatin1String("int"))
+ return QVariant::Int;
+ if (typeName == QLatin1String("double")
+ || typeName == QLatin1String("float")
+ || typeName == QLatin1String("real")
+ || typeName.startsWith(QLatin1String("numeric")))
+ return QVariant::Double;
+ if (typeName == QLatin1String("blob"))
+ return QVariant::ByteArray;
+ if (typeName == QLatin1String("boolean")
+ || typeName == QLatin1String("bool"))
+ return QVariant::Bool;
+ return QVariant::String;
+}
+
+static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type,
+ int errorCode = -1)
+{
+ return QSqlError(descr,
+ QString(reinterpret_cast<const QChar *>(sqlite3_errmsg16(access))),
+ type, QString::number(errorCode));
+}
+
+class QSQLiteResultPrivate;
+
+class QSQLiteResult : public QSqlCachedResult
+{
+ Q_DECLARE_PRIVATE(QSQLiteResult)
+ friend class QSQLiteDriver;
+
+public:
+ explicit QSQLiteResult(const QSQLiteDriver* db);
+ ~QSQLiteResult();
+ QVariant handle() const Q_DECL_OVERRIDE;
+
+protected:
+ bool gotoNext(QSqlCachedResult::ValueCache& row, int idx) Q_DECL_OVERRIDE;
+ bool reset(const QString &query) Q_DECL_OVERRIDE;
+ bool prepare(const QString &query) Q_DECL_OVERRIDE;
+ bool exec() Q_DECL_OVERRIDE;
+ int size() Q_DECL_OVERRIDE;
+ int numRowsAffected() Q_DECL_OVERRIDE;
+ QVariant lastInsertId() const Q_DECL_OVERRIDE;
+ QSqlRecord record() const Q_DECL_OVERRIDE;
+ void detachFromResultSet() Q_DECL_OVERRIDE;
+ void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
+};
+
+class QSQLiteDriverPrivate : public QSqlDriverPrivate
+{
+ Q_DECLARE_PUBLIC(QSQLiteDriver)
+
+public:
+ inline QSQLiteDriverPrivate() : QSqlDriverPrivate(), access(0) { dbmsType = QSqlDriver::SQLite; }
+ sqlite3 *access;
+ QList <QSQLiteResult *> results;
+ QStringList notificationid;
+};
+
+
+class QSQLiteResultPrivate: public QSqlCachedResultPrivate
+{
+ Q_DECLARE_PUBLIC(QSQLiteResult)
+
+public:
+ Q_DECLARE_SQLDRIVER_PRIVATE(QSQLiteDriver)
+ QSQLiteResultPrivate(QSQLiteResult *q, const QSQLiteDriver *drv);
+ void cleanup();
+ bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch);
+ // initializes the recordInfo and the cache
+ void initColumns(bool emptyResultset);
+ void finalize();
+
+ sqlite3_stmt *stmt;
+
+ bool skippedStatus; // the status of the fetchNext() that's skipped
+ bool skipRow; // skip the next fetchNext()?
+ QSqlRecord rInf;
+ QVector<QVariant> firstRow;
+};
+
+QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult *q, const QSQLiteDriver *drv)
+ : QSqlCachedResultPrivate(q, drv),
+ stmt(0),
+ skippedStatus(false),
+ skipRow(false)
+{
+}
+
+void QSQLiteResultPrivate::cleanup()
+{
+ Q_Q(QSQLiteResult);
+ finalize();
+ rInf.clear();
+ skippedStatus = false;
+ skipRow = false;
+ q->setAt(QSql::BeforeFirstRow);
+ q->setActive(false);
+ q->cleanup();
+}
+
+void QSQLiteResultPrivate::finalize()
+{
+ if (!stmt)
+ return;
+
+ sqlite3_finalize(stmt);
+ stmt = 0;
+}
+
+void QSQLiteResultPrivate::initColumns(bool emptyResultset)
+{
+ Q_Q(QSQLiteResult);
+ int nCols = sqlite3_column_count(stmt);
+ if (nCols <= 0)
+ return;
+
+ q->init(nCols);
+
+ for (int i = 0; i < nCols; ++i) {
+ QString colName = QString(reinterpret_cast<const QChar *>(
+ sqlite3_column_name16(stmt, i))
+ ).remove(QLatin1Char('"'));
+
+ // must use typeName for resolving the type to match QSqliteDriver::record
+ QString typeName = QString(reinterpret_cast<const QChar *>(
+ sqlite3_column_decltype16(stmt, i)));
+ // sqlite3_column_type is documented to have undefined behavior if the result set is empty
+ int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i);
+
+ QVariant::Type fieldType;
+
+ if (!typeName.isEmpty()) {
+ fieldType = qGetColumnType(typeName);
+ } else {
+ // Get the proper type for the field based on stp value
+ switch (stp) {
+ case SQLITE_INTEGER:
+ fieldType = QVariant::Int;
+ break;
+ case SQLITE_FLOAT:
+ fieldType = QVariant::Double;
+ break;
+ case SQLITE_BLOB:
+ fieldType = QVariant::ByteArray;
+ break;
+ case SQLITE_TEXT:
+ fieldType = QVariant::String;
+ break;
+ case SQLITE_NULL:
+ default:
+ fieldType = QVariant::Invalid;
+ break;
+ }
+ }
+
+ QSqlField fld(colName, fieldType);
+ fld.setSqlType(stp);
+ rInf.append(fld);
+ }
+}
+
+bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
+{
+ Q_Q(QSQLiteResult);
+ int res;
+ int i;
+
+ if (skipRow) {
+ // already fetched
+ Q_ASSERT(!initialFetch);
+ skipRow = false;
+ for(int i=0;i<firstRow.count();i++)
+ values[i]=firstRow[i];
+ return skippedStatus;
+ }
+ skipRow = initialFetch;
+
+ if(initialFetch) {
+ firstRow.clear();
+ firstRow.resize(sqlite3_column_count(stmt));
+ }
+
+ if (!stmt) {
+ q->setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"),
+ QCoreApplication::translate("QSQLiteResult", "No query"), QSqlError::ConnectionError));
+ q->setAt(QSql::AfterLastRow);
+ return false;
+ }
+ res = sqlite3_step(stmt);
+
+ switch(res) {
+ case SQLITE_ROW:
+ // check to see if should fill out columns
+ if (rInf.isEmpty())
+ // must be first call.
+ initColumns(false);
+ if (idx < 0 && !initialFetch)
+ return true;
+ for (i = 0; i < rInf.count(); ++i) {
+ switch (sqlite3_column_type(stmt, i)) {
+ case SQLITE_BLOB:
+ values[i + idx] = QByteArray(static_cast<const char *>(
+ sqlite3_column_blob(stmt, i)),
+ sqlite3_column_bytes(stmt, i));
+ break;
+ case SQLITE_INTEGER:
+ values[i + idx] = sqlite3_column_int64(stmt, i);
+ break;
+ case SQLITE_FLOAT:
+ switch(q->numericalPrecisionPolicy()) {
+ case QSql::LowPrecisionInt32:
+ values[i + idx] = sqlite3_column_int(stmt, i);
+ break;
+ case QSql::LowPrecisionInt64:
+ values[i + idx] = sqlite3_column_int64(stmt, i);
+ break;
+ case QSql::LowPrecisionDouble:
+ case QSql::HighPrecision:
+ default:
+ values[i + idx] = sqlite3_column_double(stmt, i);
+ break;
+ };
+ break;
+ case SQLITE_NULL:
+ values[i + idx] = QVariant(QVariant::String);
+ break;
+ default:
+ values[i + idx] = QString(reinterpret_cast<const QChar *>(
+ sqlite3_column_text16(stmt, i)),
+ sqlite3_column_bytes16(stmt, i) / sizeof(QChar));
+ break;
+ }
+ }
+ return true;
+ case SQLITE_DONE:
+ if (rInf.isEmpty())
+ // must be first call.
+ initColumns(true);
+ q->setAt(QSql::AfterLastRow);
+ sqlite3_reset(stmt);
+ return false;
+ case SQLITE_CONSTRAINT:
+ case SQLITE_ERROR:
+ // SQLITE_ERROR is a generic error code and we must call sqlite3_reset()
+ // to get the specific error message.
+ res = sqlite3_reset(stmt);
+ q->setLastError(qMakeError(drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
+ "Unable to fetch row"), QSqlError::ConnectionError, res));
+ q->setAt(QSql::AfterLastRow);
+ return false;
+ case SQLITE_MISUSE:
+ case SQLITE_BUSY:
+ default:
+ // something wrong, don't get col info, but still return false
+ q->setLastError(qMakeError(drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
+ "Unable to fetch row"), QSqlError::ConnectionError, res));
+ sqlite3_reset(stmt);
+ q->setAt(QSql::AfterLastRow);
+ return false;
+ }
+ return false;
+}
+
+QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db)
+ : QSqlCachedResult(*new QSQLiteResultPrivate(this, db))
+{
+ Q_D(QSQLiteResult);
+ const_cast<QSQLiteDriverPrivate*>(d->drv_d_func())->results.append(this);
+}
+
+QSQLiteResult::~QSQLiteResult()
+{
+ Q_D(QSQLiteResult);
+ if (d->drv_d_func())
+ const_cast<QSQLiteDriverPrivate*>(d->drv_d_func())->results.removeOne(this);
+ d->cleanup();
+}
+
+void QSQLiteResult::virtual_hook(int id, void *data)
+{
+ QSqlCachedResult::virtual_hook(id, data);
+}
+
+bool QSQLiteResult::reset(const QString &query)
+{
+ if (!prepare(query))
+ return false;
+ return exec();
+}
+
+bool QSQLiteResult::prepare(const QString &query)
+{
+ Q_D(QSQLiteResult);
+ if (!driver() || !driver()->isOpen() || driver()->isOpenError())
+ return false;
+
+ d->cleanup();
+
+ setSelect(false);
+
+ const void *pzTail = NULL;
+
+#if (SQLITE_VERSION_NUMBER >= 3003011)
+ int res = sqlite3_prepare16_v2(d->drv_d_func()->access, query.constData(), (query.size() + 1) * sizeof(QChar),
+ &d->stmt, &pzTail);
+#else
+ int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
+ &d->stmt, &pzTail);
+#endif
+
+ if (res != SQLITE_OK) {
+ setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
+ "Unable to execute statement"), QSqlError::StatementError, res));
+ d->finalize();
+ return false;
+ } else if (pzTail && !QString(reinterpret_cast<const QChar *>(pzTail)).trimmed().isEmpty()) {
+ setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
+ "Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE));
+ d->finalize();
+ return false;
+ }
+ return true;
+}
+
+bool QSQLiteResult::exec()
+{
+ Q_D(QSQLiteResult);
+ const QVector<QVariant> values = boundValues();
+
+ d->skippedStatus = false;
+ d->skipRow = false;
+ d->rInf.clear();
+ clearValues();
+ setLastError(QSqlError());
+
+ int res = sqlite3_reset(d->stmt);
+ if (res != SQLITE_OK) {
+ setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
+ "Unable to reset statement"), QSqlError::StatementError, res));
+ d->finalize();
+ return false;
+ }
+ int paramCount = sqlite3_bind_parameter_count(d->stmt);
+ if (paramCount == values.count()) {
+ for (int i = 0; i < paramCount; ++i) {
+ res = SQLITE_OK;
+ const QVariant value = values.at(i);
+
+ if (value.isNull()) {
+ res = sqlite3_bind_null(d->stmt, i + 1);
+ } else {
+ switch (value.type()) {
+ case QVariant::ByteArray: {
+ const QByteArray *ba = static_cast<const QByteArray*>(value.constData());
+ res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(),
+ ba->size(), SQLITE_STATIC);
+ break; }
+ case QVariant::Int:
+ case QVariant::Bool:
+ res = sqlite3_bind_int(d->stmt, i + 1, value.toInt());
+ break;
+ case QVariant::Double:
+ res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
+ break;
+ case QVariant::UInt:
+ case QVariant::LongLong:
+ res = sqlite3_bind_int64(d->stmt, i + 1, value.toLongLong());
+ break;
+ case QVariant::DateTime: {
+ const QDateTime dateTime = value.toDateTime();
+ const QString str = dateTime.toString(QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz"));
+ res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
+ str.size() * sizeof(ushort), SQLITE_TRANSIENT);
+ break;
+ }
+ case QVariant::Time: {
+ const QTime time = value.toTime();
+ const QString str = time.toString(QStringLiteral("hh:mm:ss.zzz"));
+ res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
+ str.size() * sizeof(ushort), SQLITE_TRANSIENT);
+ break;
+ }
+ case QVariant::String: {
+ // lifetime of string == lifetime of its qvariant
+ const QString *str = static_cast<const QString*>(value.constData());
+ res = sqlite3_bind_text16(d->stmt, i + 1, str->utf16(),
+ (str->size()) * sizeof(QChar), SQLITE_STATIC);
+ break; }
+ default: {
+ QString str = value.toString();
+ // SQLITE_TRANSIENT makes sure that sqlite buffers the data
+ res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
+ (str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
+ break; }
+ }
+ }
+ if (res != SQLITE_OK) {
+ setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
+ "Unable to bind parameters"), QSqlError::StatementError, res));
+ d->finalize();
+ return false;
+ }
+ }
+ } else {
+ setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult",
+ "Parameter count mismatch"), QString(), QSqlError::StatementError));
+ return false;
+ }
+ d->skippedStatus = d->fetchNext(d->firstRow, 0, true);
+ if (lastError().isValid()) {
+ setSelect(false);
+ setActive(false);
+ return false;
+ }
+ setSelect(!d->rInf.isEmpty());
+ setActive(true);
+ return true;
+}
+
+bool QSQLiteResult::gotoNext(QSqlCachedResult::ValueCache& row, int idx)
+{
+ Q_D(QSQLiteResult);
+ return d->fetchNext(row, idx, false);
+}
+
+int QSQLiteResult::size()
+{
+ return -1;
+}
+
+int QSQLiteResult::numRowsAffected()
+{
+ Q_D(const QSQLiteResult);
+ return sqlite3_changes(d->drv_d_func()->access);
+}
+
+QVariant QSQLiteResult::lastInsertId() const
+{
+ Q_D(const QSQLiteResult);
+ if (isActive()) {
+ qint64 id = sqlite3_last_insert_rowid(d->drv_d_func()->access);
+ if (id)
+ return id;
+ }
+ return QVariant();
+}
+
+QSqlRecord QSQLiteResult::record() const
+{
+ Q_D(const QSQLiteResult);
+ if (!isActive() || !isSelect())
+ return QSqlRecord();
+ return d->rInf;
+}
+
+void QSQLiteResult::detachFromResultSet()
+{
+ Q_D(QSQLiteResult);
+ if (d->stmt)
+ sqlite3_reset(d->stmt);
+}
+
+QVariant QSQLiteResult::handle() const
+{
+ Q_D(const QSQLiteResult);
+ return QVariant::fromValue(d->stmt);
+}
+
+/////////////////////////////////////////////////////////
+
+QSQLiteDriver::QSQLiteDriver(QObject * parent)
+ : QSqlDriver(*new QSQLiteDriverPrivate, parent)
+{
+}
+
+QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent)
+ : QSqlDriver(*new QSQLiteDriverPrivate, parent)
+{
+ Q_D(QSQLiteDriver);
+ d->access = connection;
+ setOpen(true);
+ setOpenError(false);
+}
+
+
+QSQLiteDriver::~QSQLiteDriver()
+{
+ close();
+}
+
+bool QSQLiteDriver::hasFeature(DriverFeature f) const
+{
+ switch (f) {
+ case BLOB:
+ case Transactions:
+ case Unicode:
+ case LastInsertId:
+ case PreparedQueries:
+ case PositionalPlaceholders:
+ case SimpleLocking:
+ case FinishQuery:
+ case LowPrecisionNumbers:
+ case EventNotifications:
+ return true;
+ case QuerySize:
+ case NamedPlaceholders:
+ case BatchOperations:
+ case MultipleResultSets:
+ case CancelQuery:
+ return false;
+ }
+ return false;
+}
+
+/*
+ SQLite dbs have no user name, passwords, hosts or ports.
+ just file names.
+*/
+bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &conOpts)
+{
+ Q_D(QSQLiteDriver);
+ if (isOpen())
+ close();
+
+
+ int timeOut = 5000;
+ bool sharedCache = false;
+ bool openReadOnlyOption = false;
+ bool openUriOption = false;
+
+ const auto opts = conOpts.splitRef(QLatin1Char(';'));
+ for (auto option : opts) {
+ option = option.trimmed();
+ if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT"))) {
+ option = option.mid(20).trimmed();
+ if (option.startsWith(QLatin1Char('='))) {
+ bool ok;
+ const int nt = option.mid(1).trimmed().toInt(&ok);
+ if (ok)
+ timeOut = nt;
+ }
+ } else if (option == QLatin1String("QSQLITE_OPEN_READONLY")) {
+ openReadOnlyOption = true;
+ } else if (option == QLatin1String("QSQLITE_OPEN_URI")) {
+ openUriOption = true;
+ } else if (option == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE")) {
+ sharedCache = true;
+ }
+ }
+
+ int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
+ if (openUriOption)
+ openMode |= SQLITE_OPEN_URI;
+
+ sqlite3_enable_shared_cache(sharedCache);
+
+ if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, NULL) == SQLITE_OK) {
+ sqlite3_busy_timeout(d->access, timeOut);
+ setOpen(true);
+ setOpenError(false);
+ return true;
+ } else {
+ if (d->access) {
+ sqlite3_close(d->access);
+ d->access = 0;
+ }
+
+ setLastError(qMakeError(d->access, tr("Error opening database"),
+ QSqlError::ConnectionError));
+ setOpenError(true);
+ return false;
+ }
+}
+
+void QSQLiteDriver::close()
+{
+ Q_D(QSQLiteDriver);
+ if (isOpen()) {
+ for (QSQLiteResult *result : qAsConst(d->results))
+ result->d_func()->finalize();
+
+ if (d->access && (d->notificationid.count() > 0)) {
+ d->notificationid.clear();
+ sqlite3_update_hook(d->access, NULL, NULL);
+ }
+
+ if (sqlite3_close(d->access) != SQLITE_OK)
+ setLastError(qMakeError(d->access, tr("Error closing database"), QSqlError::ConnectionError));
+ d->access = 0;
+ setOpen(false);
+ setOpenError(false);
+ }
+}
+
+QSqlResult *QSQLiteDriver::createResult() const
+{
+ return new QSQLiteResult(this);
+}
+
+bool QSQLiteDriver::beginTransaction()
+{
+ if (!isOpen() || isOpenError())
+ return false;
+
+ QSqlQuery q(createResult());
+ if (!q.exec(QLatin1String("BEGIN"))) {
+ setLastError(QSqlError(tr("Unable to begin transaction"),
+ q.lastError().databaseText(), QSqlError::TransactionError));
+ return false;
+ }
+
+ return true;
+}
+
+bool QSQLiteDriver::commitTransaction()
+{
+ if (!isOpen() || isOpenError())
+ return false;
+
+ QSqlQuery q(createResult());
+ if (!q.exec(QLatin1String("COMMIT"))) {
+ setLastError(QSqlError(tr("Unable to commit transaction"),
+ q.lastError().databaseText(), QSqlError::TransactionError));
+ return false;
+ }
+
+ return true;
+}
+
+bool QSQLiteDriver::rollbackTransaction()
+{
+ if (!isOpen() || isOpenError())
+ return false;
+
+ QSqlQuery q(createResult());
+ if (!q.exec(QLatin1String("ROLLBACK"))) {
+ setLastError(QSqlError(tr("Unable to rollback transaction"),
+ q.lastError().databaseText(), QSqlError::TransactionError));
+ return false;
+ }
+
+ return true;
+}
+
+QStringList QSQLiteDriver::tables(QSql::TableType type) const
+{
+ QStringList res;
+ if (!isOpen())
+ return res;
+
+ QSqlQuery q(createResult());
+ q.setForwardOnly(true);
+
+ QString sql = QLatin1String("SELECT name FROM sqlite_master WHERE %1 "
+ "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1");
+ if ((type & QSql::Tables) && (type & QSql::Views))
+ sql = sql.arg(QLatin1String("type='table' OR type='view'"));
+ else if (type & QSql::Tables)
+ sql = sql.arg(QLatin1String("type='table'"));
+ else if (type & QSql::Views)
+ sql = sql.arg(QLatin1String("type='view'"));
+ else
+ sql.clear();
+
+ if (!sql.isEmpty() && q.exec(sql)) {
+ while(q.next())
+ res.append(q.value(0).toString());
+ }
+
+ if (type & QSql::SystemTables) {
+ // there are no internal tables beside this one:
+ res.append(QLatin1String("sqlite_master"));
+ }
+
+ return res;
+}
+
+static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
+{
+ QString schema;
+ QString table(tableName);
+ int indexOfSeparator = tableName.indexOf(QLatin1Char('.'));
+ if (indexOfSeparator > -1) {
+ schema = tableName.left(indexOfSeparator).append(QLatin1Char('.'));
+ table = tableName.mid(indexOfSeparator + 1);
+ }
+ q.exec(QLatin1String("PRAGMA ") + schema + QLatin1String("table_info (") + _q_escapeIdentifier(table) + QLatin1Char(')'));
+
+ QSqlIndex ind;
+ while (q.next()) {
+ bool isPk = q.value(5).toInt();
+ if (onlyPIndex && !isPk)
+ continue;
+ QString typeName = q.value(2).toString().toLower();
+ QSqlField fld(q.value(1).toString(), qGetColumnType(typeName));
+ if (isPk && (typeName == QLatin1String("integer")))
+ // INTEGER PRIMARY KEY fields are auto-generated in sqlite
+ // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
+ fld.setAutoValue(true);
+ fld.setRequired(q.value(3).toInt() != 0);
+ fld.setDefaultValue(q.value(4));
+ ind.append(fld);
+ }
+ return ind;
+}
+
+QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
+{
+ if (!isOpen())
+ return QSqlIndex();
+
+ QString table = tblname;
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+
+ QSqlQuery q(createResult());
+ q.setForwardOnly(true);
+ return qGetTableInfo(q, table, true);
+}
+
+QSqlRecord QSQLiteDriver::record(const QString &tbl) const
+{
+ if (!isOpen())
+ return QSqlRecord();
+
+ QString table = tbl;
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+
+ QSqlQuery q(createResult());
+ q.setForwardOnly(true);
+ return qGetTableInfo(q, table);
+}
+
+QVariant QSQLiteDriver::handle() const
+{
+ Q_D(const QSQLiteDriver);
+ return QVariant::fromValue(d->access);
+}
+
+QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
+{
+ Q_UNUSED(type);
+ return _q_escapeIdentifier(identifier);
+}
+
+static void handle_sqlite_callback(void *qobj,int aoperation, char const *adbname, char const *atablename,
+ sqlite3_int64 arowid)
+{
+ Q_UNUSED(aoperation);
+ Q_UNUSED(adbname);
+ QSQLiteDriver *driver = static_cast<QSQLiteDriver *>(qobj);
+ if (driver) {
+ QMetaObject::invokeMethod(driver, "handleNotification", Qt::QueuedConnection,
+ Q_ARG(QString, QString::fromUtf8(atablename)), Q_ARG(qint64, arowid));
+ }
+}
+
+bool QSQLiteDriver::subscribeToNotification(const QString &name)
+{
+ Q_D(QSQLiteDriver);
+ if (!isOpen()) {
+ qWarning("Database not open.");
+ return false;
+ }
+
+ if (d->notificationid.contains(name)) {
+ qWarning("Already subscribing to '%s'.", qPrintable(name));
+ return false;
+ }
+
+ //sqlite supports only one notification callback, so only the first is registered
+ d->notificationid << name;
+ if (d->notificationid.count() == 1)
+ sqlite3_update_hook(d->access, &handle_sqlite_callback, reinterpret_cast<void *> (this));
+
+ return true;
+}
+
+bool QSQLiteDriver::unsubscribeFromNotification(const QString &name)
+{
+ Q_D(QSQLiteDriver);
+ if (!isOpen()) {
+ qWarning("Database not open.");
+ return false;
+ }
+
+ if (!d->notificationid.contains(name)) {
+ qWarning("Not subscribed to '%s'.", qPrintable(name));
+ return false;
+ }
+
+ d->notificationid.removeAll(name);
+ if (d->notificationid.isEmpty())
+ sqlite3_update_hook(d->access, NULL, NULL);
+
+ return true;
+}
+
+QStringList QSQLiteDriver::subscribedToNotifications() const
+{
+ Q_D(const QSQLiteDriver);
+ return d->notificationid;
+}
+
+void QSQLiteDriver::handleNotification(const QString &tableName, qint64 rowid)
+{
+ Q_D(const QSQLiteDriver);
+ if (d->notificationid.contains(tableName)) {
+ emit notification(tableName);
+ emit notification(tableName, QSqlDriver::UnknownSource, QVariant(rowid));
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h b/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h
new file mode 100644
index 0000000000..ca969a4b53
--- /dev/null
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSQL_SQLITE_H
+#define QSQL_SQLITE_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 <QtSql/qsqldriver.h>
+
+struct sqlite3;
+
+#ifdef QT_PLUGIN
+#define Q_EXPORT_SQLDRIVER_SQLITE
+#else
+#define Q_EXPORT_SQLDRIVER_SQLITE Q_SQL_EXPORT
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QSqlResult;
+class QSQLiteDriverPrivate;
+
+class Q_EXPORT_SQLDRIVER_SQLITE QSQLiteDriver : public QSqlDriver
+{
+ Q_DECLARE_PRIVATE(QSQLiteDriver)
+ Q_OBJECT
+ friend class QSQLiteResultPrivate;
+public:
+ explicit QSQLiteDriver(QObject *parent = 0);
+ explicit QSQLiteDriver(sqlite3 *connection, QObject *parent = 0);
+ ~QSQLiteDriver();
+ bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
+ bool open(const QString & db,
+ const QString & user,
+ const QString & password,
+ const QString & host,
+ int port,
+ const QString & connOpts) Q_DECL_OVERRIDE;
+ void close() Q_DECL_OVERRIDE;
+ QSqlResult *createResult() const Q_DECL_OVERRIDE;
+ bool beginTransaction() Q_DECL_OVERRIDE;
+ bool commitTransaction() Q_DECL_OVERRIDE;
+ bool rollbackTransaction() Q_DECL_OVERRIDE;
+ QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
+
+ QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE;
+ QSqlIndex primaryIndex(const QString &table) const Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+ QString escapeIdentifier(const QString &identifier, IdentifierType) const Q_DECL_OVERRIDE;
+
+ bool subscribeToNotification(const QString &name) Q_DECL_OVERRIDE;
+ bool unsubscribeFromNotification(const QString &name) Q_DECL_OVERRIDE;
+ QStringList subscribedToNotifications() const Q_DECL_OVERRIDE;
+private Q_SLOTS:
+ void handleNotification(const QString &tableName, qint64 rowid);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQL_SQLITE_H
diff --git a/src/plugins/sqldrivers/sqlite/smain.cpp b/src/plugins/sqldrivers/sqlite/smain.cpp
index 94b41c9878..2ad466a61e 100644
--- a/src/plugins/sqldrivers/sqlite/smain.cpp
+++ b/src/plugins/sqldrivers/sqlite/smain.cpp
@@ -39,7 +39,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../../src/sql/drivers/sqlite/qsql_sqlite_p.h"
+#include "qsql_sqlite_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/sqlite/sqlite.pro b/src/plugins/sqldrivers/sqlite/sqlite.pro
index cc6d02cbe8..c98655f85c 100644
--- a/src/plugins/sqldrivers/sqlite/sqlite.pro
+++ b/src/plugins/sqldrivers/sqlite/sqlite.pro
@@ -1,8 +1,16 @@
TARGET = qsqlite
-SOURCES = smain.cpp
+HEADERS += $$PWD/qsql_sqlite_p.h
+SOURCES += $$PWD/qsql_sqlite.cpp $$PWD/smain.cpp
+
+!system-sqlite:!contains(LIBS, .*sqlite3.*) {
+ include($$PWD/../../../3rdparty/sqlite.pri)
+} else {
+ LIBS += $$QMAKE_LIBS_SQLITE
+ QMAKE_CXXFLAGS *= $$QMAKE_CFLAGS_SQLITE
+}
+
OTHER_FILES += sqlite.json
-include(../../../sql/drivers/sqlite/qsql_sqlite.pri)
PLUGIN_CLASS_NAME = QSQLiteDriverPlugin
include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp
new file mode 100644
index 0000000000..67c24e4168
--- /dev/null
+++ b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp
@@ -0,0 +1,615 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsql_sqlite2_p.h"
+
+#include <qcoreapplication.h>
+#include <qvariant.h>
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qsqlerror.h>
+#include <qsqlfield.h>
+#include <qsqlindex.h>
+#include <qsqlquery.h>
+#include <QtSql/private/qsqlcachedresult_p.h>
+#include <QtSql/private/qsqldriver_p.h>
+#include <qstringlist.h>
+#include <qvector.h>
+
+#if !defined Q_OS_WIN
+# include <unistd.h>
+#endif
+#include <sqlite.h>
+
+typedef struct sqlite_vm sqlite_vm;
+
+Q_DECLARE_OPAQUE_POINTER(sqlite_vm*)
+Q_DECLARE_METATYPE(sqlite_vm*)
+
+Q_DECLARE_OPAQUE_POINTER(sqlite*)
+Q_DECLARE_METATYPE(sqlite*)
+
+QT_BEGIN_NAMESPACE
+
+static QVariant::Type nameToType(const QString& typeName)
+{
+ QString tName = typeName.toUpper();
+ if (tName.startsWith(QLatin1String("INT")))
+ return QVariant::Int;
+ if (tName.startsWith(QLatin1String("FLOAT")) || tName.startsWith(QLatin1String("NUMERIC")))
+ return QVariant::Double;
+ if (tName.startsWith(QLatin1String("BOOL")))
+ return QVariant::Bool;
+ // SQLite is typeless - consider everything else as string
+ return QVariant::String;
+}
+
+class QSQLite2DriverPrivate : public QSqlDriverPrivate
+{
+ Q_DECLARE_PUBLIC(QSQLite2Driver)
+
+public:
+ QSQLite2DriverPrivate();
+ sqlite *access;
+ bool utf8;
+};
+
+QSQLite2DriverPrivate::QSQLite2DriverPrivate() : QSqlDriverPrivate(), access(0)
+{
+ utf8 = (qstrcmp(sqlite_encoding, "UTF-8") == 0);
+ dbmsType = QSqlDriver::SQLite;
+}
+
+class QSQLite2ResultPrivate;
+
+class QSQLite2Result : public QSqlCachedResult
+{
+ Q_DECLARE_PRIVATE(QSQLite2Result)
+ friend class QSQLite2Driver;
+
+public:
+ explicit QSQLite2Result(const QSQLite2Driver* db);
+ ~QSQLite2Result();
+ QVariant handle() const Q_DECL_OVERRIDE;
+
+protected:
+ bool gotoNext(QSqlCachedResult::ValueCache &row, int idx) Q_DECL_OVERRIDE;
+ bool reset(const QString &query) Q_DECL_OVERRIDE;
+ int size() Q_DECL_OVERRIDE;
+ int numRowsAffected() Q_DECL_OVERRIDE;
+ QSqlRecord record() const Q_DECL_OVERRIDE;
+ void detachFromResultSet() Q_DECL_OVERRIDE;
+ void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
+};
+
+class QSQLite2ResultPrivate: public QSqlCachedResultPrivate
+{
+ Q_DECLARE_PUBLIC(QSQLite2Result)
+
+public:
+ Q_DECLARE_SQLDRIVER_PRIVATE(QSQLite2Driver);
+ QSQLite2ResultPrivate(QSQLite2Result *q, const QSQLite2Driver *drv);
+ void cleanup();
+ bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch);
+ bool isSelect();
+ // initializes the recordInfo and the cache
+ void init(const char **cnames, int numCols);
+ void finalize();
+
+ // and we have too keep our own struct for the data (sqlite works via
+ // callback.
+ const char *currentTail;
+ sqlite_vm *currentMachine;
+
+ bool skippedStatus; // the status of the fetchNext() that's skipped
+ bool skipRow; // skip the next fetchNext()?
+ QSqlRecord rInf;
+ QVector<QVariant> firstRow;
+};
+
+QSQLite2ResultPrivate::QSQLite2ResultPrivate(QSQLite2Result *q, const QSQLite2Driver *drv)
+ : QSqlCachedResultPrivate(q, drv),
+ currentTail(0),
+ currentMachine(0),
+ skippedStatus(false),
+ skipRow(false)
+{
+}
+
+void QSQLite2ResultPrivate::cleanup()
+{
+ Q_Q(QSQLite2Result);
+ finalize();
+ rInf.clear();
+ currentTail = 0;
+ currentMachine = 0;
+ skippedStatus = false;
+ skipRow = false;
+ q->setAt(QSql::BeforeFirstRow);
+ q->setActive(false);
+ q->cleanup();
+}
+
+void QSQLite2ResultPrivate::finalize()
+{
+ Q_Q(QSQLite2Result);
+ if (!currentMachine)
+ return;
+
+ char* err = 0;
+ int res = sqlite_finalize(currentMachine, &err);
+ if (err) {
+ q->setLastError(QSqlError(QCoreApplication::translate("QSQLite2Result",
+ "Unable to fetch results"), QString::fromLatin1(err),
+ QSqlError::StatementError, res));
+ sqlite_freemem(err);
+ }
+ currentMachine = 0;
+}
+
+// called on first fetch
+void QSQLite2ResultPrivate::init(const char **cnames, int numCols)
+{
+ Q_Q(QSQLite2Result);
+ if (!cnames)
+ return;
+
+ rInf.clear();
+ if (numCols <= 0)
+ return;
+ q->init(numCols);
+
+ for (int i = 0; i < numCols; ++i) {
+ const char* lastDot = strrchr(cnames[i], '.');
+ const char* fieldName = lastDot ? lastDot + 1 : cnames[i];
+
+ //remove quotations around the field name if any
+ QString fieldStr = QString::fromLatin1(fieldName);
+ QLatin1Char quote('\"');
+ if ( fieldStr.length() > 2 && fieldStr.startsWith(quote) && fieldStr.endsWith(quote)) {
+ fieldStr = fieldStr.mid(1);
+ fieldStr.chop(1);
+ }
+ rInf.append(QSqlField(fieldStr,
+ nameToType(QString::fromLatin1(cnames[i+numCols]))));
+ }
+}
+
+bool QSQLite2ResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
+{
+ Q_Q(QSQLite2Result);
+ // may be caching.
+ const char **fvals;
+ const char **cnames;
+ int colNum;
+ int res;
+ int i;
+
+ if (skipRow) {
+ // already fetched
+ Q_ASSERT(!initialFetch);
+ skipRow = false;
+ for(int i=0;i<firstRow.count(); i++)
+ values[i] = firstRow[i];
+ return skippedStatus;
+ }
+ skipRow = initialFetch;
+
+ if (!currentMachine)
+ return false;
+
+ // keep trying while busy, wish I could implement this better.
+ while ((res = sqlite_step(currentMachine, &colNum, &fvals, &cnames)) == SQLITE_BUSY) {
+ // sleep instead requesting result again immidiately.
+#if defined Q_OS_WIN
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+ }
+
+ if(initialFetch) {
+ firstRow.clear();
+ firstRow.resize(colNum);
+ }
+
+ switch(res) {
+ case SQLITE_ROW:
+ // check to see if should fill out columns
+ if (rInf.isEmpty())
+ // must be first call.
+ init(cnames, colNum);
+ if (!fvals)
+ return false;
+ if (idx < 0 && !initialFetch)
+ return true;
+ for (i = 0; i < colNum; ++i)
+ values[i + idx] = drv_d_func()->utf8 ? QString::fromUtf8(fvals[i]) : QString::fromLatin1(fvals[i]);
+ return true;
+ case SQLITE_DONE:
+ if (rInf.isEmpty())
+ // must be first call.
+ init(cnames, colNum);
+ q->setAt(QSql::AfterLastRow);
+ return false;
+ case SQLITE_ERROR:
+ case SQLITE_MISUSE:
+ default:
+ // something wrong, don't get col info, but still return false
+ finalize(); // finalize to get the error message.
+ q->setAt(QSql::AfterLastRow);
+ return false;
+ }
+ return false;
+}
+
+QSQLite2Result::QSQLite2Result(const QSQLite2Driver* db)
+ : QSqlCachedResult(*new QSQLite2ResultPrivate(this, db))
+{
+}
+
+QSQLite2Result::~QSQLite2Result()
+{
+ Q_D(QSQLite2Result);
+ d->cleanup();
+}
+
+void QSQLite2Result::virtual_hook(int id, void *data)
+{
+ QSqlCachedResult::virtual_hook(id, data);
+}
+
+/*
+ Execute \a query.
+*/
+bool QSQLite2Result::reset (const QString& query)
+{
+ Q_D(QSQLite2Result);
+ // this is where we build a query.
+ if (!driver())
+ return false;
+ if (!driver()-> isOpen() || driver()->isOpenError())
+ return false;
+
+ d->cleanup();
+
+ // Um, ok. callback based so.... pass private static function for this.
+ setSelect(false);
+ char *err = 0;
+ int res = sqlite_compile(d->drv_d_func()->access,
+ d->drv_d_func()->utf8 ? query.toUtf8().constData()
+ : query.toLatin1().constData(),
+ &(d->currentTail),
+ &(d->currentMachine),
+ &err);
+ if (res != SQLITE_OK || err) {
+ setLastError(QSqlError(QCoreApplication::translate("QSQLite2Result",
+ "Unable to execute statement"), QString::fromLatin1(err),
+ QSqlError::StatementError, res));
+ sqlite_freemem(err);
+ }
+ //if (*d->currentTail != '\000' then there is more sql to eval
+ if (!d->currentMachine) {
+ setActive(false);
+ return false;
+ }
+ // we have to fetch one row to find out about
+ // the structure of the result set
+ d->skippedStatus = d->fetchNext(d->firstRow, 0, true);
+ if (lastError().isValid()) {
+ setSelect(false);
+ setActive(false);
+ return false;
+ }
+ setSelect(!d->rInf.isEmpty());
+ setActive(true);
+ return true;
+}
+
+bool QSQLite2Result::gotoNext(QSqlCachedResult::ValueCache& row, int idx)
+{
+ Q_D(QSQLite2Result);
+ return d->fetchNext(row, idx, false);
+}
+
+int QSQLite2Result::size()
+{
+ return -1;
+}
+
+int QSQLite2Result::numRowsAffected()
+{
+ Q_D(QSQLite2Result);
+ return sqlite_changes(d->drv_d_func()->access);
+}
+
+QSqlRecord QSQLite2Result::record() const
+{
+ Q_D(const QSQLite2Result);
+ if (!isActive() || !isSelect())
+ return QSqlRecord();
+ return d->rInf;
+}
+
+void QSQLite2Result::detachFromResultSet()
+{
+ Q_D(QSQLite2Result);
+ d->finalize();
+}
+
+QVariant QSQLite2Result::handle() const
+{
+ Q_D(const QSQLite2Result);
+ return QVariant::fromValue(d->currentMachine);
+}
+
+/////////////////////////////////////////////////////////
+
+QSQLite2Driver::QSQLite2Driver(QObject *parent)
+ : QSqlDriver(*new QSQLite2DriverPrivate, parent)
+{
+}
+
+QSQLite2Driver::QSQLite2Driver(sqlite *connection, QObject *parent)
+ : QSqlDriver(*new QSQLite2DriverPrivate, parent)
+{
+ Q_D(QSQLite2Driver);
+ d->access = connection;
+ setOpen(true);
+ setOpenError(false);
+}
+
+
+QSQLite2Driver::~QSQLite2Driver()
+{
+}
+
+bool QSQLite2Driver::hasFeature(DriverFeature f) const
+{
+ Q_D(const QSQLite2Driver);
+ switch (f) {
+ case Transactions:
+ case SimpleLocking:
+ return true;
+ case Unicode:
+ return d->utf8;
+ default:
+ return false;
+ }
+}
+
+/*
+ SQLite dbs have no user name, passwords, hosts or ports.
+ just file names.
+*/
+bool QSQLite2Driver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &)
+{
+ Q_D(QSQLite2Driver);
+ if (isOpen())
+ close();
+
+ if (db.isEmpty())
+ return false;
+
+ char* err = 0;
+ d->access = sqlite_open(QFile::encodeName(db), 0, &err);
+ if (err) {
+ setLastError(QSqlError(tr("Error opening database"), QString::fromLatin1(err),
+ QSqlError::ConnectionError));
+ sqlite_freemem(err);
+ err = 0;
+ }
+
+ if (d->access) {
+ setOpen(true);
+ setOpenError(false);
+ return true;
+ }
+ setOpenError(true);
+ return false;
+}
+
+void QSQLite2Driver::close()
+{
+ Q_D(QSQLite2Driver);
+ if (isOpen()) {
+ sqlite_close(d->access);
+ d->access = 0;
+ setOpen(false);
+ setOpenError(false);
+ }
+}
+
+QSqlResult *QSQLite2Driver::createResult() const
+{
+ return new QSQLite2Result(this);
+}
+
+bool QSQLite2Driver::beginTransaction()
+{
+ Q_D(QSQLite2Driver);
+ if (!isOpen() || isOpenError())
+ return false;
+
+ char* err;
+ int res = sqlite_exec(d->access, "BEGIN", 0, this, &err);
+
+ if (res == SQLITE_OK)
+ return true;
+
+ setLastError(QSqlError(tr("Unable to begin transaction"),
+ QString::fromLatin1(err), QSqlError::TransactionError, res));
+ sqlite_freemem(err);
+ return false;
+}
+
+bool QSQLite2Driver::commitTransaction()
+{
+ Q_D(QSQLite2Driver);
+ if (!isOpen() || isOpenError())
+ return false;
+
+ char* err;
+ int res = sqlite_exec(d->access, "COMMIT", 0, this, &err);
+
+ if (res == SQLITE_OK)
+ return true;
+
+ setLastError(QSqlError(tr("Unable to commit transaction"),
+ QString::fromLatin1(err), QSqlError::TransactionError, res));
+ sqlite_freemem(err);
+ return false;
+}
+
+bool QSQLite2Driver::rollbackTransaction()
+{
+ Q_D(QSQLite2Driver);
+ if (!isOpen() || isOpenError())
+ return false;
+
+ char* err;
+ int res = sqlite_exec(d->access, "ROLLBACK", 0, this, &err);
+
+ if (res == SQLITE_OK)
+ return true;
+
+ setLastError(QSqlError(tr("Unable to rollback transaction"),
+ QString::fromLatin1(err), QSqlError::TransactionError, res));
+ sqlite_freemem(err);
+ return false;
+}
+
+QStringList QSQLite2Driver::tables(QSql::TableType type) const
+{
+ QStringList res;
+ if (!isOpen())
+ return res;
+
+ QSqlQuery q(createResult());
+ q.setForwardOnly(true);
+ if ((type & QSql::Tables) && (type & QSql::Views))
+ q.exec(QLatin1String("SELECT name FROM sqlite_master WHERE type='table' OR type='view'"));
+ else if (type & QSql::Tables)
+ q.exec(QLatin1String("SELECT name FROM sqlite_master WHERE type='table'"));
+ else if (type & QSql::Views)
+ q.exec(QLatin1String("SELECT name FROM sqlite_master WHERE type='view'"));
+
+ if (q.isActive()) {
+ while(q.next())
+ res.append(q.value(0).toString());
+ }
+
+ if (type & QSql::SystemTables) {
+ // there are no internal tables beside this one:
+ res.append(QLatin1String("sqlite_master"));
+ }
+
+ return res;
+}
+
+QSqlIndex QSQLite2Driver::primaryIndex(const QString &tblname) const
+{
+ QSqlRecord rec(record(tblname)); // expensive :(
+
+ if (!isOpen())
+ return QSqlIndex();
+
+ QSqlQuery q(createResult());
+ q.setForwardOnly(true);
+ QString table = tblname;
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ // finrst find a UNIQUE INDEX
+ q.exec(QLatin1String("PRAGMA index_list('") + table + QLatin1String("');"));
+ QString indexname;
+ while(q.next()) {
+ if (q.value(2).toInt()==1) {
+ indexname = q.value(1).toString();
+ break;
+ }
+ }
+ if (indexname.isEmpty())
+ return QSqlIndex();
+
+ q.exec(QLatin1String("PRAGMA index_info('") + indexname + QLatin1String("');"));
+
+ QSqlIndex index(table, indexname);
+ while(q.next()) {
+ QString name = q.value(2).toString();
+ QVariant::Type type = QVariant::Invalid;
+ if (rec.contains(name))
+ type = rec.field(name).type();
+ index.append(QSqlField(name, type));
+ }
+ return index;
+}
+
+QSqlRecord QSQLite2Driver::record(const QString &tbl) const
+{
+ if (!isOpen())
+ return QSqlRecord();
+ QString table = tbl;
+ if (isIdentifierEscaped(tbl, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+
+ QSqlQuery q(createResult());
+ q.setForwardOnly(true);
+ q.exec(QLatin1String("SELECT * FROM ") + tbl + QLatin1String(" LIMIT 1"));
+ return q.record();
+}
+
+QVariant QSQLite2Driver::handle() const
+{
+ Q_D(const QSQLite2Driver);
+ return QVariant::fromValue(d->access);
+}
+
+QString QSQLite2Driver::escapeIdentifier(const QString &identifier, IdentifierType /*type*/) const
+{
+ QString res = identifier;
+ if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
+ res.replace(QLatin1Char('"'), QLatin1String("\"\""));
+ res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
+ res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ }
+ return res;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/sqlite2/qsql_sqlite2_p.h b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2_p.h
new file mode 100644
index 0000000000..83b248ec6a
--- /dev/null
+++ b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSQL_SQLITE2_H
+#define QSQL_SQLITE2_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 <QtSql/qsqldriver.h>
+
+#if defined (Q_OS_WIN32)
+# include <QtCore/qt_windows.h>
+#endif
+
+struct sqlite;
+
+#ifdef QT_PLUGIN
+#define Q_EXPORT_SQLDRIVER_SQLITE2
+#else
+#define Q_EXPORT_SQLDRIVER_SQLITE2 Q_SQL_EXPORT
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QSqlResult;
+class QSQLite2DriverPrivate;
+
+class Q_EXPORT_SQLDRIVER_SQLITE2 QSQLite2Driver : public QSqlDriver
+{
+ friend class QSQLite2ResultPrivate;
+ Q_DECLARE_PRIVATE(QSQLite2Driver)
+ Q_OBJECT
+public:
+ explicit QSQLite2Driver(QObject *parent = 0);
+ explicit QSQLite2Driver(sqlite *connection, QObject *parent = 0);
+ ~QSQLite2Driver();
+ bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
+ bool open(const QString &db,
+ const QString &user,
+ const QString &password,
+ const QString &host,
+ int port,
+ const QString &connOpts) Q_DECL_OVERRIDE;
+ bool open(const QString &db,
+ const QString &user,
+ const QString &password,
+ const QString &host,
+ int port) { return open(db, user, password, host, port, QString()); }
+ void close() Q_DECL_OVERRIDE;
+ QSqlResult *createResult() const Q_DECL_OVERRIDE;
+ bool beginTransaction() Q_DECL_OVERRIDE;
+ bool commitTransaction() Q_DECL_OVERRIDE;
+ bool rollbackTransaction() Q_DECL_OVERRIDE;
+ QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
+
+ QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE;
+ QSqlIndex primaryIndex(const QString &table) const Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+ QString escapeIdentifier(const QString &identifier, IdentifierType) const Q_DECL_OVERRIDE;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQL_SQLITE2_H
diff --git a/src/plugins/sqldrivers/sqlite2/smain.cpp b/src/plugins/sqldrivers/sqlite2/smain.cpp
index 06b428c8ef..3a5734f8c9 100644
--- a/src/plugins/sqldrivers/sqlite2/smain.cpp
+++ b/src/plugins/sqldrivers/sqlite2/smain.cpp
@@ -39,7 +39,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../../src/sql/drivers/sqlite2/qsql_sqlite2_p.h"
+#include "qsql_sqlite2_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/sqlite2/sqlite2.pro b/src/plugins/sqldrivers/sqlite2/sqlite2.pro
index d69afc119f..d0ab0eef41 100644
--- a/src/plugins/sqldrivers/sqlite2/sqlite2.pro
+++ b/src/plugins/sqldrivers/sqlite2/sqlite2.pro
@@ -1,8 +1,11 @@
TARGET = qsqlite2
-SOURCES = smain.cpp
+HEADERS += $$PWD/qsql_sqlite2_p.h
+SOURCES += $$PWD/qsql_sqlite2.cpp $$PWD/smain.cpp
+
+!contains(LIBS, .*sqlite.*):LIBS += -lsqlite
+
OTHER_FILES += sqlite2.json
-include(../../../sql/drivers/sqlite2/qsql_sqlite2.pri)
PLUGIN_CLASS_NAME = QSQLite2DriverPlugin
include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/tds/main.cpp b/src/plugins/sqldrivers/tds/main.cpp
index ffb31ae179..4aa1444608 100644
--- a/src/plugins/sqldrivers/tds/main.cpp
+++ b/src/plugins/sqldrivers/tds/main.cpp
@@ -45,7 +45,7 @@
#define _WINSCARD_H_
#include <windows.h>
#endif
-#include "../../../sql/drivers/tds/qsql_tds_p.h"
+#include "qsql_tds_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/tds/qsql_tds.cpp b/src/plugins/sqldrivers/tds/qsql_tds.cpp
new file mode 100644
index 0000000000..940fd05c74
--- /dev/null
+++ b/src/plugins/sqldrivers/tds/qsql_tds.cpp
@@ -0,0 +1,881 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsql_tds_p.h"
+
+#include <qglobal.h>
+#ifdef Q_OS_WIN32 // We assume that MS SQL Server is used. Set Q_USE_SYBASE to force Sybase.
+// Conflicting declarations of LPCBYTE in sqlfront.h and winscard.h
+#define _WINSCARD_H_
+#include <windows.h>
+#else
+#define Q_USE_SYBASE
+#endif
+
+#include <qvariant.h>
+#include <qdatetime.h>
+#include <qhash.h>
+#include <qregexp.h>
+#include <qsqlerror.h>
+#include <qsqlfield.h>
+#include <qsqlindex.h>
+#include <qsqlquery.h>
+#include <QtSql/private/qsqlcachedresult_p.h>
+#include <QtSql/private/qsqldriver_p.h>
+#include <qstringlist.h>
+#include <qvector.h>
+
+#include <stdlib.h>
+
+Q_DECLARE_OPAQUE_POINTER(LOGINREC*)
+Q_DECLARE_OPAQUE_POINTER(DBPROCESS*)
+
+QT_BEGIN_NAMESPACE
+
+#ifdef DBNTWIN32
+#define QMSGHANDLE DBMSGHANDLE_PROC
+#define QERRHANDLE DBERRHANDLE_PROC
+#define QTDSCHAR SQLCHAR
+#define QTDSDATETIME4 SQLDATETIM4
+#define QTDSDATETIME SQLDATETIME
+#define QTDSDATETIME_N SQLDATETIMN
+#define QTDSDECIMAL SQLDECIMAL
+#define QTDSFLT4 SQLFLT4
+#define QTDSFLT8 SQLFLT8
+#define QTDSFLT8_N SQLFLTN
+#define QTDSINT1 SQLINT1
+#define QTDSINT2 SQLINT2
+#define QTDSINT4 SQLINT4
+#define QTDSINT4_N SQLINTN
+#define QTDSMONEY4 SQLMONEY4
+#define QTDSMONEY SQLMONEY
+#define QTDSMONEY_N SQLMONEYN
+#define QTDSNUMERIC SQLNUMERIC
+#define QTDSTEXT SQLTEXT
+#define QTDSVARCHAR SQLVARCHAR
+#define QTDSBIT SQLBIT
+#define QTDSBINARY SQLBINARY
+#define QTDSVARBINARY SQLVARBINARY
+#define QTDSIMAGE SQLIMAGE
+#else
+#define QMSGHANDLE MHANDLEFUNC
+#define QERRHANDLE EHANDLEFUNC
+#define QTDSCHAR SYBCHAR
+#define QTDSDATETIME4 SYBDATETIME4
+#define QTDSDATETIME SYBDATETIME
+#define QTDSDATETIME_N SYBDATETIMN
+#define QTDSDECIMAL SYBDECIMAL
+#define QTDSFLT8 SYBFLT8
+#define QTDSFLT8_N SYBFLTN
+#define QTDSFLT4 SYBREAL
+#define QTDSINT1 SYBINT1
+#define QTDSINT2 SYBINT2
+#define QTDSINT4 SYBINT4
+#define QTDSINT4_N SYBINTN
+#define QTDSMONEY4 SYBMONEY4
+#define QTDSMONEY SYBMONEY
+#define QTDSMONEY_N SYBMONEYN
+#define QTDSNUMERIC SYBNUMERIC
+#define QTDSTEXT SYBTEXT
+#define QTDSVARCHAR SYBVARCHAR
+#define QTDSBIT SYBBIT
+#define QTDSBINARY SYBBINARY
+#define QTDSVARBINARY SYBVARBINARY
+#define QTDSIMAGE SYBIMAGE
+// magic numbers not defined anywhere in Sybase headers
+#define QTDSDECIMAL_2 55
+#define QTDSNUMERIC_2 63
+#endif //DBNTWIN32
+
+#define TDS_CURSOR_SIZE 50
+
+// workaround for FreeTDS
+#ifndef CS_PUBLIC
+#define CS_PUBLIC
+#endif
+
+QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, int errNo = -1)
+{
+ return QSqlError(QLatin1String("QTDS: ") + err, QString(), type, errNo);
+}
+
+class QTDSDriverPrivate : public QSqlDriverPrivate
+{
+ Q_DECLARE_PUBLIC(QTDSDriver)
+
+public:
+ QTDSDriverPrivate() : QSqlDriverPrivate(), login(0), initialized(false) { dbmsType = QSqlDriver::Sybase; }
+ LOGINREC* login; // login information
+ QString hostName;
+ QString db;
+ bool initialized;
+};
+
+struct QTDSColumnData
+{
+ void *data;
+ DBINT nullbind;
+};
+Q_DECLARE_TYPEINFO(QTDSColumnData, Q_MOVABLE_TYPE);
+
+class QTDSResultPrivate;
+
+class QTDSResult : public QSqlCachedResult
+{
+ Q_DECLARE_PRIVATE(QTDSResult)
+
+public:
+ explicit QTDSResult(const QTDSDriver* db);
+ ~QTDSResult();
+ QVariant handle() const Q_DECL_OVERRIDE;
+
+protected:
+ void cleanup();
+ bool reset(const QString &query) Q_DECL_OVERRIDE;
+ int size() Q_DECL_OVERRIDE;
+ int numRowsAffected() Q_DECL_OVERRIDE;
+ bool gotoNext(QSqlCachedResult::ValueCache &values, int index) Q_DECL_OVERRIDE;
+ QSqlRecord record() const Q_DECL_OVERRIDE;
+};
+
+class QTDSResultPrivate: public QSqlCachedResultPrivate
+{
+ Q_DECLARE_PUBLIC(QTDSResult)
+
+public:
+ Q_DECLARE_SQLDRIVER_PRIVATE(QTDSDriver)
+ QTDSResultPrivate(QTDSResult *q, const QTDSDriver *drv)
+ : QSqlCachedResultPrivate(q, drv),
+ login(0),
+ dbproc(0) {}
+ LOGINREC* login; // login information
+ DBPROCESS* dbproc; // connection from app to server
+ QSqlError lastError;
+ void addErrorMsg(QString& errMsg) { errorMsgs.append(errMsg); }
+ QString getErrorMsgs() { return errorMsgs.join(QLatin1String("\n")); }
+ void clearErrorMsgs() { errorMsgs.clear(); }
+ QVector<QTDSColumnData> buffer;
+ QSqlRecord rec;
+
+private:
+ QStringList errorMsgs;
+};
+
+typedef QHash<DBPROCESS *, QTDSResultPrivate *> QTDSErrorHash;
+Q_GLOBAL_STATIC(QTDSErrorHash, errs)
+
+extern "C" {
+static int CS_PUBLIC qTdsMsgHandler (DBPROCESS* dbproc,
+ DBINT msgno,
+ int msgstate,
+ int severity,
+ char* msgtext,
+ char* srvname,
+ char* /*procname*/,
+ int line)
+{
+ QTDSResultPrivate* p = errs()->value(dbproc);
+
+ if (!p) {
+// ### umm... temporary disabled since this throws a lot of warnings...
+// qWarning("QTDSDriver warning (%d): [%s] from server [%s]", msgstate, msgtext, srvname);
+ return INT_CANCEL;
+ }
+
+ if (severity > 0) {
+ QString errMsg = QString::fromLatin1("%1 (Msg %2, Level %3, State %4, Server %5, Line %6)")
+ .arg(QString::fromLatin1(msgtext))
+ .arg(msgno)
+ .arg(severity)
+ .arg(msgstate)
+ .arg(QString::fromLatin1(srvname))
+ .arg(line);
+ p->addErrorMsg(errMsg);
+ if (severity > 10) {
+ // Severe messages are really errors in the sense of lastError
+ errMsg = p->getErrorMsgs();
+ p->lastError = qMakeError(errMsg, QSqlError::UnknownError, msgno);
+ p->clearErrorMsgs();
+ }
+ }
+
+ return INT_CANCEL;
+}
+
+static int CS_PUBLIC qTdsErrHandler(DBPROCESS* dbproc,
+ int /*severity*/,
+ int dberr,
+ int /*oserr*/,
+ char* dberrstr,
+ char* oserrstr)
+{
+ QTDSResultPrivate* p = errs()->value(dbproc);
+ if (!p) {
+ qWarning("QTDSDriver error (%d): [%s] [%s]", dberr, dberrstr, oserrstr);
+ return INT_CANCEL;
+ }
+ /*
+ * If the process is dead or NULL and
+ * we are not in the middle of logging in...
+ */
+ if((dbproc == NULL || DBDEAD(dbproc))) {
+ qWarning("QTDSDriver error (%d): [%s] [%s]", dberr, dberrstr, oserrstr);
+ return INT_CANCEL;
+ }
+
+
+ QString errMsg = QString::fromLatin1("%1 %2\n").arg(QLatin1String(dberrstr)).arg(
+ QLatin1String(oserrstr));
+ errMsg += p->getErrorMsgs();
+ p->lastError = qMakeError(errMsg, QSqlError::UnknownError, dberr);
+ p->clearErrorMsgs();
+
+ return INT_CANCEL ;
+}
+
+} //extern "C"
+
+
+QVariant::Type qDecodeTDSType(int type)
+{
+ QVariant::Type t = QVariant::Invalid;
+ switch (type) {
+ case QTDSCHAR:
+ case QTDSTEXT:
+ case QTDSVARCHAR:
+ t = QVariant::String;
+ break;
+ case QTDSINT1:
+ case QTDSINT2:
+ case QTDSINT4:
+ case QTDSINT4_N:
+ case QTDSBIT:
+ t = QVariant::Int;
+ break;
+ case QTDSFLT4:
+ case QTDSFLT8:
+ case QTDSFLT8_N:
+ case QTDSMONEY4:
+ case QTDSMONEY:
+ case QTDSDECIMAL:
+ case QTDSNUMERIC:
+#ifdef QTDSNUMERIC_2
+ case QTDSNUMERIC_2:
+#endif
+#ifdef QTDSDECIMAL_2
+ case QTDSDECIMAL_2:
+#endif
+ case QTDSMONEY_N:
+ t = QVariant::Double;
+ break;
+ case QTDSDATETIME4:
+ case QTDSDATETIME:
+ case QTDSDATETIME_N:
+ t = QVariant::DateTime;
+ break;
+ case QTDSBINARY:
+ case QTDSVARBINARY:
+ case QTDSIMAGE:
+ t = QVariant::ByteArray;
+ break;
+ default:
+ t = QVariant::Invalid;
+ break;
+ }
+ return t;
+}
+
+QVariant::Type qFieldType(QTDSResultPrivate* d, int i)
+{
+ QVariant::Type type = qDecodeTDSType(dbcoltype(d->dbproc, i+1));
+ return type;
+}
+
+
+QTDSResult::QTDSResult(const QTDSDriver* db)
+ : QSqlCachedResult(*new QTDSResultPrivate(this, db))
+{
+ Q_D(QTDSResult);
+ d->login = d->drv_d_func()->login;
+
+ d->dbproc = dbopen(d->login, const_cast<char*>(d->drv_d_func()->hostName.toLatin1().constData()));
+ if (!d->dbproc)
+ return;
+ if (dbuse(d->dbproc, const_cast<char*>(d->drv_d_func()->db.toLatin1().constData())) == FAIL)
+ return;
+
+ // insert d in error handler dict
+ errs()->insert(d->dbproc, d);
+ dbcmd(d->dbproc, "set quoted_identifier on");
+ dbsqlexec(d->dbproc);
+}
+
+QTDSResult::~QTDSResult()
+{
+ Q_D(QTDSResult);
+ cleanup();
+ if (d->dbproc)
+ dbclose(d->dbproc);
+ errs()->remove(d->dbproc);
+}
+
+void QTDSResult::cleanup()
+{
+ Q_D(QTDSResult);
+ d->clearErrorMsgs();
+ d->rec.clear();
+ for (int i = 0; i < d->buffer.size(); ++i)
+ free(d->buffer.at(i).data);
+ d->buffer.clear();
+ // "can" stands for "cancel"... very clever.
+ dbcanquery(d->dbproc);
+ dbfreebuf(d->dbproc);
+
+ QSqlCachedResult::cleanup();
+}
+
+QVariant QTDSResult::handle() const
+{
+ Q_D(const QTDSResult);
+ return QVariant(qRegisterMetaType<DBPROCESS *>("DBPROCESS*"), &d->dbproc);
+}
+
+static inline bool qIsNull(const QTDSColumnData &p)
+{
+ return p.nullbind == -1;
+}
+
+bool QTDSResult::gotoNext(QSqlCachedResult::ValueCache &values, int index)
+{
+ Q_D(QTDSResult);
+ STATUS stat = dbnextrow(d->dbproc);
+ if (stat == NO_MORE_ROWS) {
+ setAt(QSql::AfterLastRow);
+ return false;
+ }
+ if ((stat == FAIL) || (stat == BUF_FULL)) {
+ setLastError(d->lastError);
+ return false;
+ }
+
+ if (index < 0)
+ return true;
+
+ for (int i = 0; i < d->rec.count(); ++i) {
+ int idx = index + i;
+ switch (d->rec.field(i).type()) {
+ case QVariant::DateTime:
+ if (qIsNull(d->buffer.at(i))) {
+ values[idx] = QVariant(QVariant::DateTime);
+ } else {
+ DBDATETIME *bdt = (DBDATETIME*) d->buffer.at(i).data;
+ QDate date = QDate::fromString(QLatin1String("1900-01-01"), Qt::ISODate);
+ QTime time = QTime::fromString(QLatin1String("00:00:00"), Qt::ISODate);
+ values[idx] = QDateTime(date.addDays(bdt->dtdays), time.addMSecs(int(bdt->dttime / 0.3)));
+ }
+ break;
+ case QVariant::Int:
+ if (qIsNull(d->buffer.at(i)))
+ values[idx] = QVariant(QVariant::Int);
+ else
+ values[idx] = *((int*)d->buffer.at(i).data);
+ break;
+ case QVariant::Double:
+ case QVariant::String:
+ if (qIsNull(d->buffer.at(i)))
+ values[idx] = QVariant(QVariant::String);
+ else
+ values[idx] = QString::fromLocal8Bit((const char*)d->buffer.at(i).data).trimmed();
+ break;
+ case QVariant::ByteArray: {
+ if (qIsNull(d->buffer.at(i)))
+ values[idx] = QVariant(QVariant::ByteArray);
+ else
+ values[idx] = QByteArray((const char*)d->buffer.at(i).data);
+ break;
+ }
+ default:
+ // should never happen, and we already fired
+ // a warning while binding.
+ values[idx] = QVariant();
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool QTDSResult::reset (const QString& query)
+{
+ Q_D(QTDSResult);
+ cleanup();
+ if (!driver() || !driver()-> isOpen() || driver()->isOpenError())
+ return false;
+ setActive(false);
+ setAt(QSql::BeforeFirstRow);
+ if (dbcmd(d->dbproc, const_cast<char*>(query.toLocal8Bit().constData())) == FAIL) {
+ setLastError(d->lastError);
+ return false;
+ }
+
+ if (dbsqlexec(d->dbproc) == FAIL) {
+ setLastError(d->lastError);
+ dbfreebuf(d->dbproc);
+ return false;
+ }
+ if (dbresults(d->dbproc) != SUCCEED) {
+ setLastError(d->lastError);
+ dbfreebuf(d->dbproc);
+ return false;
+ }
+
+ setSelect((DBCMDROW(d->dbproc) == SUCCEED)); // decide whether or not we are dealing with a SELECT query
+ int numCols = dbnumcols(d->dbproc);
+ if (numCols > 0) {
+ d->buffer.resize(numCols);
+ init(numCols);
+ }
+ for (int i = 0; i < numCols; ++i) {
+ int dbType = dbcoltype(d->dbproc, i+1);
+ QVariant::Type vType = qDecodeTDSType(dbType);
+ QSqlField f(QString::fromLatin1(dbcolname(d->dbproc, i+1)), vType);
+ f.setSqlType(dbType);
+ f.setLength(dbcollen(d->dbproc, i+1));
+ d->rec.append(f);
+
+ RETCODE ret = -1;
+ void* p = 0;
+ switch (vType) {
+ case QVariant::Int:
+ p = malloc(4);
+ ret = dbbind(d->dbproc, i+1, INTBIND, (DBINT) 4, (unsigned char *)p);
+ break;
+ case QVariant::Double:
+ // use string binding to prevent loss of precision
+ p = malloc(50);
+ ret = dbbind(d->dbproc, i+1, STRINGBIND, 50, (unsigned char *)p);
+ break;
+ case QVariant::String:
+ p = malloc(dbcollen(d->dbproc, i+1) + 1);
+ ret = dbbind(d->dbproc, i+1, STRINGBIND, DBINT(dbcollen(d->dbproc, i+1) + 1), (unsigned char *)p);
+ break;
+ case QVariant::DateTime:
+ p = malloc(8);
+ ret = dbbind(d->dbproc, i+1, DATETIMEBIND, (DBINT) 8, (unsigned char *)p);
+ break;
+ case QVariant::ByteArray:
+ p = malloc(dbcollen(d->dbproc, i+1) + 1);
+ ret = dbbind(d->dbproc, i+1, BINARYBIND, DBINT(dbcollen(d->dbproc, i+1) + 1), (unsigned char *)p);
+ break;
+ default: //don't bind the field since we do not support it
+ qWarning("QTDSResult::reset: Unsupported type for field \"%s\"", dbcolname(d->dbproc, i+1));
+ break;
+ }
+ if (ret == SUCCEED) {
+ d->buffer[i].data = p;
+ ret = dbnullbind(d->dbproc, i+1, &d->buffer[i].nullbind);
+ } else {
+ d->buffer[i].data = 0;
+ d->buffer[i].nullbind = 0;
+ free(p);
+ }
+ if ((ret != SUCCEED) && (ret != -1)) {
+ setLastError(d->lastError);
+ return false;
+ }
+ }
+
+ setActive(true);
+ return true;
+}
+
+int QTDSResult::size()
+{
+ return -1;
+}
+
+int QTDSResult::numRowsAffected()
+{
+ Q_D(const QTDSResult);
+#ifdef DBNTWIN32
+ if (dbiscount(d->dbproc)) {
+ return DBCOUNT(d->dbproc);
+ }
+ return -1;
+#else
+ return DBCOUNT(d->dbproc);
+#endif
+}
+
+QSqlRecord QTDSResult::record() const
+{
+ Q_D(const QTDSResult);
+ return d->rec;
+}
+
+///////////////////////////////////////////////////////////////////
+
+QTDSDriver::QTDSDriver(QObject* parent)
+ : QSqlDriver(*new QTDSDriverPrivate, parent)
+{
+ init();
+}
+
+QTDSDriver::QTDSDriver(LOGINREC* rec, const QString& host, const QString &db, QObject* parent)
+ : QSqlDriver(*new QTDSDriverPrivate, parent)
+{
+ Q_D(QTDSDriver);
+ init();
+ d->login = rec;
+ d->hostName = host;
+ d->db = db;
+ if (rec) {
+ setOpen(true);
+ setOpenError(false);
+ }
+}
+
+QVariant QTDSDriver::handle() const
+{
+ Q_D(const QTDSDriver);
+ return QVariant(qRegisterMetaType<LOGINREC *>("LOGINREC*"), &d->login);
+}
+
+void QTDSDriver::init()
+{
+ Q_D(QTDSDriver);
+ d->initialized = (dbinit() == SUCCEED);
+ // the following two code-lines will fail compilation on some FreeTDS versions
+ // just comment them out if you have FreeTDS (you won't get any errors and warnings then)
+ dberrhandle((QERRHANDLE)qTdsErrHandler);
+ dbmsghandle((QMSGHANDLE)qTdsMsgHandler);
+}
+
+QTDSDriver::~QTDSDriver()
+{
+ dberrhandle(0);
+ dbmsghandle(0);
+ // dbexit also calls dbclose if necessary
+ dbexit();
+}
+
+bool QTDSDriver::hasFeature(DriverFeature f) const
+{
+ switch (f) {
+ case Transactions:
+ case QuerySize:
+ case Unicode:
+ case SimpleLocking:
+ case EventNotifications:
+ case MultipleResultSets:
+ return false;
+ case BLOB:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool QTDSDriver::open(const QString & db,
+ const QString & user,
+ const QString & password,
+ const QString & host,
+ int /*port*/,
+ const QString& /*connOpts*/)
+{
+ Q_D(QTDSDriver);
+ if (isOpen())
+ close();
+ if (!d->initialized) {
+ setOpenError(true);
+ return false;
+ }
+ d->login = dblogin();
+ if (!d->login) {
+ setOpenError(true);
+ return false;
+ }
+ DBSETLPWD(d->login, const_cast<char*>(password.toLocal8Bit().constData()));
+ DBSETLUSER(d->login, const_cast<char*>(user.toLocal8Bit().constData()));
+
+ // Now, try to open and use the database. If this fails, return false.
+ DBPROCESS* dbproc;
+
+ dbproc = dbopen(d->login, const_cast<char*>(host.toLatin1().constData()));
+ if (!dbproc) {
+ setLastError(qMakeError(tr("Unable to open connection"), QSqlError::ConnectionError, -1));
+ setOpenError(true);
+ return false;
+ }
+ if (dbuse(dbproc, const_cast<char*>(db.toLatin1().constData())) == FAIL) {
+ setLastError(qMakeError(tr("Unable to use database"), QSqlError::ConnectionError, -1));
+ setOpenError(true);
+ return false;
+ }
+ dbclose( dbproc );
+
+ setOpen(true);
+ setOpenError(false);
+ d->hostName = host;
+ d->db = db;
+ return true;
+}
+
+void QTDSDriver::close()
+{
+ Q_D(QTDSDriver);
+ if (isOpen()) {
+#ifdef Q_USE_SYBASE
+ dbloginfree(d->login);
+#else
+ dbfreelogin(d->login);
+#endif
+ d->login = 0;
+ setOpen(false);
+ setOpenError(false);
+ }
+}
+
+QSqlResult *QTDSDriver::createResult() const
+{
+ return new QTDSResult(this);
+}
+
+bool QTDSDriver::beginTransaction()
+{
+ return false;
+/*
+ if (!isOpen()) {
+ qWarning("QTDSDriver::beginTransaction: Database not open");
+ return false;
+ }
+ if (dbcmd(d->dbproc, "BEGIN TRANSACTION") == FAIL) {
+ setLastError(d->lastError);
+ dbfreebuf(d->dbproc);
+ return false;
+ }
+ if (dbsqlexec(d->dbproc) == FAIL) {
+ setLastError(d->lastError);
+ dbfreebuf(d->dbproc);
+ return false;
+ }
+ while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
+ dbfreebuf(d->dbproc);
+ inTransaction = true;
+ return true;
+*/
+}
+
+bool QTDSDriver::commitTransaction()
+{
+ return false;
+/*
+ if (!isOpen()) {
+ qWarning("QTDSDriver::commitTransaction: Database not open");
+ return false;
+ }
+ if (dbcmd(d->dbproc, "COMMIT TRANSACTION") == FAIL) {
+ setLastError(d->lastError);
+ dbfreebuf(d->dbproc);
+ return false;
+ }
+ if (dbsqlexec(d->dbproc) == FAIL) {
+ setLastError(d->lastError);
+ dbfreebuf(d->dbproc);
+ return false;
+ }
+ while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
+ dbfreebuf(d->dbproc);
+ inTransaction = false;
+ return true;
+*/
+}
+
+bool QTDSDriver::rollbackTransaction()
+{
+ return false;
+/*
+ if (!isOpen()) {
+ qWarning("QTDSDriver::rollbackTransaction: Database not open");
+ return false;
+ }
+ if (dbcmd(d->dbproc, "ROLLBACK TRANSACTION") == FAIL) {
+ setLastError(d->lastError);
+ dbfreebuf(d->dbproc);
+ return false;
+ }
+ if (dbsqlexec(d->dbproc) == FAIL) {
+ setLastError(d->lastError);
+ dbfreebuf(d->dbproc);
+ return false;
+ }
+ while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
+ dbfreebuf(d->dbproc);
+ inTransaction = false;
+ return true;
+*/
+}
+
+QSqlRecord QTDSDriver::record(const QString& tablename) const
+{
+ QSqlRecord info;
+ if (!isOpen())
+ return info;
+ QSqlQuery t(createResult());
+ t.setForwardOnly(true);
+
+ QString table = tablename;
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+
+ QString stmt (QLatin1String("select name, type, length, prec from syscolumns "
+ "where id = (select id from sysobjects where name = '%1')"));
+ t.exec(stmt.arg(table));
+ while (t.next()) {
+ QSqlField f(t.value(0).toString().simplified(), qDecodeTDSType(t.value(1).toInt()));
+ f.setLength(t.value(2).toInt());
+ f.setPrecision(t.value(3).toInt());
+ f.setSqlType(t.value(1).toInt());
+ info.append(f);
+ }
+ return info;
+}
+
+QStringList QTDSDriver::tables(QSql::TableType type) const
+{
+ QStringList list;
+
+ if (!isOpen())
+ return list;
+
+ QStringList typeFilter;
+
+ if (type & QSql::Tables)
+ typeFilter += QLatin1String("type='U'");
+ if (type & QSql::SystemTables)
+ typeFilter += QLatin1String("type='S'");
+ if (type & QSql::Views)
+ typeFilter += QLatin1String("type='V'");
+
+ if (typeFilter.isEmpty())
+ return list;
+
+ QSqlQuery t(createResult());
+ t.setForwardOnly(true);
+ t.exec(QLatin1String("select name from sysobjects where ") + typeFilter.join(QLatin1String(" or ")));
+ while (t.next())
+ list.append(t.value(0).toString().simplified());
+
+ return list;
+}
+
+QString QTDSDriver::formatValue(const QSqlField &field,
+ bool trim) const
+{
+ QString r;
+ if (field.isNull())
+ r = QLatin1String("NULL");
+ else if (field.type() == QVariant::DateTime) {
+ if (field.value().toDateTime().isValid()){
+ r = field.value().toDateTime().toString(QLatin1String("yyyyMMdd hh:mm:ss"));
+ r.prepend(QLatin1String("'"));
+ r.append(QLatin1String("'"));
+ } else
+ r = QLatin1String("NULL");
+ } else if (field.type() == QVariant::ByteArray) {
+ QByteArray ba = field.value().toByteArray();
+ QString res;
+ static const char hexchars[] = "0123456789abcdef";
+ for (int i = 0; i < ba.size(); ++i) {
+ uchar s = (uchar) ba[i];
+ res += QLatin1Char(hexchars[s >> 4]);
+ res += QLatin1Char(hexchars[s & 0x0f]);
+ }
+ r = QLatin1String("0x") + res;
+ } else {
+ r = QSqlDriver::formatValue(field, trim);
+ }
+ return r;
+}
+
+QSqlIndex QTDSDriver::primaryIndex(const QString& tablename) const
+{
+ QSqlRecord rec = record(tablename);
+
+ QString table = tablename;
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+
+ QSqlIndex idx(table);
+ if ((!isOpen()) || (table.isEmpty()))
+ return QSqlIndex();
+
+ QSqlQuery t(createResult());
+ t.setForwardOnly(true);
+ t.exec(QString::fromLatin1("sp_helpindex '%1'").arg(table));
+ if (t.next()) {
+ QStringList fNames = t.value(2).toString().simplified().split(QLatin1Char(','));
+ QRegExp regx(QLatin1String("\\s*(\\S+)(?:\\s+(DESC|desc))?\\s*"));
+ for(QStringList::Iterator it = fNames.begin(); it != fNames.end(); ++it) {
+ regx.indexIn(*it);
+ QSqlField f(regx.cap(1), rec.field(regx.cap(1)).type());
+ if (regx.cap(2).toLower() == QLatin1String("desc")) {
+ idx.append(f, true);
+ } else {
+ idx.append(f, false);
+ }
+ }
+ idx.setName(t.value(0).toString().simplified());
+ }
+ return idx;
+}
+
+QString QTDSDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
+{
+ Q_UNUSED(type)
+ QString res = identifier;
+ if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
+ res.replace(QLatin1Char('"'), QLatin1String("\"\""));
+ res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
+ res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ }
+ return res;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/tds/qsql_tds_p.h b/src/plugins/sqldrivers/tds/qsql_tds_p.h
new file mode 100644
index 0000000000..d0914455a2
--- /dev/null
+++ b/src/plugins/sqldrivers/tds/qsql_tds_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSQL_TDS_H
+#define QSQL_TDS_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 <QtSql/qsqldriver.h>
+
+#ifdef Q_OS_WIN32
+#define WIN32_LEAN_AND_MEAN
+#ifndef Q_USE_SYBASE
+#define DBNTWIN32 // indicates 32bit windows dblib
+#endif
+#include <winsock2.h>
+#include <QtCore/qt_windows.h>
+#include <sqlfront.h>
+#include <sqldb.h>
+#define CS_PUBLIC
+#else
+#include <sybfront.h>
+#include <sybdb.h>
+#endif //Q_OS_WIN32
+
+#ifdef QT_PLUGIN
+#define Q_EXPORT_SQLDRIVER_TDS
+#else
+#define Q_EXPORT_SQLDRIVER_TDS Q_SQL_EXPORT
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QSqlResult;
+class QTDSDriverPrivate;
+
+class Q_EXPORT_SQLDRIVER_TDS QTDSDriver : public QSqlDriver
+{
+ Q_DECLARE_PRIVATE(QTDSDriver)
+ Q_OBJECT
+ friend class QTDSResultPrivate;
+public:
+ explicit QTDSDriver(QObject* parent = 0);
+ QTDSDriver(LOGINREC* rec, const QString& host, const QString &db, QObject* parent = 0);
+ ~QTDSDriver();
+ bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
+ bool open(const QString &db,
+ const QString &user,
+ const QString &password,
+ const QString &host,
+ int port,
+ const QString &connOpts) Q_DECL_OVERRIDE;
+ void close() Q_DECL_OVERRIDE;
+ QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
+ QSqlResult *createResult() const Q_DECL_OVERRIDE;
+ QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE;
+ QSqlIndex primaryIndex(const QString &tablename) const Q_DECL_OVERRIDE;
+
+ QString formatValue(const QSqlField &field,
+ bool trimStrings) const Q_DECL_OVERRIDE;
+ QVariant handle() const Q_DECL_OVERRIDE;
+
+ QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
+
+protected:
+ bool beginTransaction() Q_DECL_OVERRIDE;
+ bool commitTransaction() Q_DECL_OVERRIDE;
+ bool rollbackTransaction() Q_DECL_OVERRIDE;
+private:
+ void init();
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQL_TDS_H
diff --git a/src/plugins/sqldrivers/tds/tds.pro b/src/plugins/sqldrivers/tds/tds.pro
index 88f4b7c451..b5d32ae5a8 100644
--- a/src/plugins/sqldrivers/tds/tds.pro
+++ b/src/plugins/sqldrivers/tds/tds.pro
@@ -1,8 +1,17 @@
TARGET = qsqltds
-SOURCES = main.cpp
+HEADERS += $$PWD/qsql_tds_p.h
+SOURCES += $$PWD/qsql_tds.cpp $$PWD/main.cpp
+
+unix|mingw: {
+ LIBS += $$QMAKE_LIBS_TDS
+ !contains(LIBS, .*sybdb.*):LIBS += -lsybdb
+ QMAKE_CXXFLAGS *= $$QMAKE_CFLAGS_TDS
+} else {
+ LIBS *= -lNTWDBLIB
+}
+
OTHER_FILES += tds.json
-include(../../../sql/drivers/tds/qsql_tds.pri)
PLUGIN_CLASS_NAME = QTDSDriverPlugin
include(../qsqldriverbase.pri)